1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 02:12:30 +01:00

implement duplicate segment

This commit is contained in:
Mikael Finstad 2023-07-17 00:26:48 +02:00
parent b1405632f6
commit 743d190369
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
4 changed files with 36 additions and 5 deletions

View File

@ -345,7 +345,7 @@ const App = memo(() => {
}, [isFileOpened]);
const {
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, onViewSegmentTags, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, createNumSegments, createFixedDurationSegments, createRandomSegments, apparentCutSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, currentApparentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, toggleSegmentSelected, selectOnlySegment, getApparentCutSegmentById, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, segmentsToExport,
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, onViewSegmentTags, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, createNumSegments, createFixedDurationSegments, createRandomSegments, apparentCutSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, currentApparentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, toggleSegmentSelected, selectOnlySegment, getApparentCutSegmentById, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, segmentsToExport, duplicateCurrentSegment, duplicateSegment,
} = useSegments({ filePath, workingRef, setWorking, setCutProgress, mainVideoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly });
const jumpSegStart = useCallback((index) => userSeekAbs(apparentCutSegments[index].start), [apparentCutSegments, userSeekAbs]);
@ -1869,6 +1869,7 @@ const App = memo(() => {
redo: () => cutSegmentsHistory.forward(),
labelCurrentSegment: () => { onLabelSegment(currentSegIndexSafe); return false; },
addSegment,
duplicateCurrentSegment,
toggleLastCommands: () => { toggleLastCommands(); return false; },
export: onExportPress,
extractCurrentSegmentFramesAsImages,
@ -1946,7 +1947,7 @@ const App = memo(() => {
if (match) return bubble;
return true; // bubble the event
}, [addSegment, alignSegmentTimesToKeyframes, askSetStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, combineOverlappingSegments, combineSelectedSegments, concatCurrentBatch, concatDialogVisible, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, exportConfirmVisible, extractAllStreams, extractCurrentSegmentFramesAsImages, fillSegmentsGaps, goToTimecode, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegment, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
}, [addSegment, alignSegmentTimesToKeyframes, askSetStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, cleanupFilesDialog, clearSegments, closeBatch, closeExportConfirm, combineOverlappingSegments, combineSelectedSegments, concatCurrentBatch, concatDialogVisible, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, duplicateCurrentSegment, exportConfirmVisible, extractAllStreams, extractCurrentSegmentFramesAsImages, fillSegmentsGaps, goToTimecode, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardShortcutsVisible, onExportConfirm, onExportPress, onLabelSegment, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleStreamsSelector, toggleStripAudio, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
useKeyboard({ keyBindings, onKeyPress });
@ -2286,6 +2287,7 @@ const App = memo(() => {
currentCutSeg={currentCutSeg}
segmentAtCursor={segmentAtCursor}
addSegment={addSegment}
onDuplicateSegmentClick={duplicateSegment}
removeCutSegment={removeCutSegment}
onRemoveSelected={removeSelectedSegments}
toggleSegmentsList={toggleSegmentsList}

View File

@ -22,7 +22,7 @@ const buttonBaseStyle = {
const neutralButtonColor = 'var(--gray8)';
const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, getFrameCount, updateOrder, invertCutSegments, onClick, onRemovePress, onRemoveSelected, onLabelSelectedSegments, onReorderPress, onLabelPress, selected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectSegmentsByLabel, onSelectAllSegments, jumpSegStart, jumpSegEnd, addSegment, onViewSegmentTags, onExtractSegmentFramesAsImages, onInvertSelectedSegments }) => {
const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, getFrameCount, updateOrder, invertCutSegments, onClick, onRemovePress, onRemoveSelected, onLabelSelectedSegments, onReorderPress, onLabelPress, selected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectSegmentsByLabel, onSelectAllSegments, jumpSegStart, jumpSegEnd, addSegment, onViewSegmentTags, onExtractSegmentFramesAsImages, onInvertSelectedSegments, onDuplicateSegmentClick }) => {
const { t } = useTranslation();
const { getSegColor } = useSegColors();
@ -39,6 +39,7 @@ const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, g
{ label: t('Add segment'), click: addSegment },
{ label: t('Label segment'), click: onLabelPress },
{ label: t('Remove segment'), click: onRemovePress },
{ label: t('Duplicate segment'), click: () => onDuplicateSegmentClick(seg) },
{ type: 'separator' },
@ -64,7 +65,7 @@ const Segment = memo(({ darkMode, seg, index, currentSegIndex, formatTimecode, g
{ label: t('Segment tags'), click: () => onViewSegmentTags(index) },
{ label: t('Extract frames as image files'), click: () => onExtractSegmentFramesAsImages(index) },
];
}, [invertCutSegments, t, jumpSegStart, jumpSegEnd, addSegment, onLabelPress, onRemovePress, onLabelSelectedSegments, onRemoveSelected, onReorderPress, onSelectSingleSegment, seg, onSelectAllSegments, onDeselectAllSegments, onSelectSegmentsByLabel, onInvertSelectedSegments, updateOrder, onViewSegmentTags, index, onExtractSegmentFramesAsImages]);
}, [invertCutSegments, t, jumpSegStart, jumpSegEnd, addSegment, onLabelPress, onRemovePress, onLabelSelectedSegments, onRemoveSelected, onReorderPress, onDuplicateSegmentClick, seg, onSelectSingleSegment, onSelectAllSegments, onDeselectAllSegments, onSelectSegmentsByLabel, onInvertSelectedSegments, updateOrder, onViewSegmentTags, index, onExtractSegmentFramesAsImages]);
useContextMenu(ref, contextMenuTemplate);
@ -147,7 +148,7 @@ const SegmentList = memo(({
currentSegIndex,
updateSegOrder, updateSegOrders, addSegment, removeCutSegment, onRemoveSelected,
onLabelSegment, currentCutSeg, segmentAtCursor, toggleSegmentsList, splitCurrentSegment,
selectedSegments, isSegmentSelected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectAllSegments, onSelectSegmentsByLabel, onExtractSegmentFramesAsImages, onLabelSelectedSegments, onInvertSelectedSegments,
selectedSegments, isSegmentSelected, onSelectSingleSegment, onToggleSegmentSelected, onDeselectAllSegments, onSelectAllSegments, onSelectSegmentsByLabel, onExtractSegmentFramesAsImages, onLabelSelectedSegments, onInvertSelectedSegments, onDuplicateSegmentClick,
jumpSegStart, jumpSegEnd, onViewSegmentTags,
}) => {
const { t } = useTranslation();
@ -311,6 +312,7 @@ const SegmentList = memo(({
onExtractSegmentFramesAsImages={onExtractSegmentFramesAsImages}
onLabelSelectedSegments={onLabelSelectedSegments}
onInvertSelectedSegments={onInvertSelectedSegments}
onDuplicateSegmentClick={onDuplicateSegmentClick}
/>
);
})}

View File

@ -291,6 +291,10 @@ const KeyboardShortcuts = memo(({
name: t('Split segment at cursor'),
category: segmentsAndCutpointsCategory,
},
duplicateCurrentSegment: {
name: t('Duplicate current segment'),
category: segmentsAndCutpointsCategory,
},
jumpPrevSegment: {
name: t('Jump to previous segment'),
category: segmentsAndCutpointsCategory,

View File

@ -330,6 +330,27 @@ export default ({
}
}, [currentCutSeg.start, currentCutSeg.end, getRelevantTime, duration, cutSegments, createIndexedSegment, setCutSegments, setCurrentSegIndex]);
const duplicateSegment = useCallback((segment) => {
try {
// Cannot duplicate if seg is not finished
if (segment.start === undefined && segment.end === undefined) return;
const cutSegmentsNew = [
...cutSegments,
createIndexedSegment({ segment: { start: segment.start, end: segment.end, name: segment.name }, incrementCount: true }),
];
setCutSegments(cutSegmentsNew);
setCurrentSegIndex(cutSegmentsNew.length - 1);
} catch (err) {
console.error(err);
}
}, [createIndexedSegment, cutSegments, setCutSegments]);
const duplicateCurrentSegment = useCallback(() => {
duplicateSegment(currentCutSeg);
}, [currentCutSeg, duplicateSegment]);
const setCutStart = useCallback(() => {
if (!checkFileOpened()) return;
@ -484,6 +505,8 @@ export default ({
updateSegOrders,
reorderSegsByStartTime,
addSegment,
duplicateCurrentSegment,
duplicateSegment,
setCutStart,
setCutEnd,
onLabelSegment,