kopia lustrzana https://github.com/mifi/lossless-cut
fix broken loop selected segments
rodzic
25021774bb
commit
250217fee6
|
|
@ -335,7 +335,7 @@ function App() {
|
|||
}, [isFileOpened]);
|
||||
|
||||
const {
|
||||
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, focusSegmentAtCursor, createNumSegments, createFixedDurationSegments, createRandomSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, onSelectSegmentsByExpr, onMutateSegmentsByExpr, toggleSegmentSelected, selectOnlySegment, getCutSegmentById, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, segmentsToExport, duplicateCurrentSegment, duplicateSegment, updateSegAtIndex, getSegApparentEnd, getApparentCutSegments,
|
||||
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, focusSegmentAtCursor, createNumSegments, createFixedDurationSegments, createRandomSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, onSelectSegmentsByExpr, onMutateSegmentsByExpr, toggleSegmentSelected, selectOnlySegment, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, segmentsToExport, duplicateCurrentSegment, duplicateSegment, updateSegAtIndex, getSegApparentEnd, getApparentCutSegments,
|
||||
} = useSegments({ filePath, workingRef, setWorking, setProgress, videoStream: activeVideoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly, timecodePlaceholder, parseTimecode, appendFfmpegCommandLog });
|
||||
|
||||
const { getEdlFilePath, getEdlFilePathOld, projectFileSavePath, getProjectFileSavePath } = useSegmentsAutoSave({ autoSaveProjectFile, storeProjectInWorkingDir, filePath, customOutDir, cutSegments });
|
||||
|
|
@ -698,17 +698,20 @@ function App() {
|
|||
return;
|
||||
}
|
||||
|
||||
// If we are using a special playback mode, we might need to do more:
|
||||
if (playbackModeRef.current != null) {
|
||||
const selectedSegmentAtCursor = selectedSegments.find((selectedSegment) => selectedSegment.segId === segmentAtCursorRef.current?.segId);
|
||||
const isSomeSegmentAtCursor = selectedSegmentAtCursor != null && commandedTimeRef.current != null && getSegApparentEnd(selectedSegmentAtCursor) - commandedTimeRef.current > 0.1;
|
||||
if (!isSomeSegmentAtCursor) { // if a segment is already at cursor, don't do anything
|
||||
// if no segment at cursor, and looping playback mode, continue looping
|
||||
if (playbackModeRef.current === 'loop-selected-segments') {
|
||||
const firstSelectedSegment = selectedSegments[0];
|
||||
if (firstSelectedSegment == null) throw new Error();
|
||||
invariant(firstSelectedSegment != null);
|
||||
const index = cutSegments.indexOf(firstSelectedSegment);
|
||||
if (index >= 0) setCurrentSegIndex(index);
|
||||
seekAbs(firstSelectedSegment.start);
|
||||
} else {
|
||||
// for all other playback modes, seek to start of current segment
|
||||
seekAbs(getSegApparentStart(currentCutSeg));
|
||||
}
|
||||
}
|
||||
|
|
@ -722,31 +725,33 @@ function App() {
|
|||
setPlayerTime(currentTime);
|
||||
|
||||
const playbackMode = playbackModeRef.current;
|
||||
if (playbackMode != null && segmentAtCursorRef.current != null) { // todo and is currently playing?
|
||||
const playingSegment = getCutSegmentById(segmentAtCursorRef.current.segId);
|
||||
|
||||
if (playingSegment != null) {
|
||||
const nextAction = getPlaybackMode({ playbackMode, currentTime, playingSegment: { start: getSegApparentStart(playingSegment), end: getSegApparentEnd(playingSegment) } });
|
||||
if (nextAction != null) {
|
||||
console.log(nextAction);
|
||||
if (nextAction.nextSegment) {
|
||||
const index = selectedSegments.indexOf(playingSegment);
|
||||
let newIndex = getNewJumpIndex(index >= 0 ? index : 0, 1);
|
||||
if (newIndex > selectedSegments.length - 1) newIndex = 0; // have reached end of last segment, start over
|
||||
const nextSelectedSegment = selectedSegments[newIndex];
|
||||
if (nextSelectedSegment != null) seekAbs(nextSelectedSegment.start);
|
||||
}
|
||||
if (nextAction.seekTo != null) {
|
||||
seekAbs(nextAction.seekTo);
|
||||
}
|
||||
if (nextAction.exit) {
|
||||
playbackModeRef.current = undefined;
|
||||
pause();
|
||||
}
|
||||
const segmentsAtCursorIndexes = findSegmentsAtCursor(cutSegments, commandedTimeRef.current);
|
||||
const firstSegmentAtCursorIndex = segmentsAtCursorIndexes[0];
|
||||
const playingSegment = firstSegmentAtCursorIndex != null ? cutSegments[firstSegmentAtCursorIndex] : undefined;
|
||||
|
||||
if (playbackMode != null && playingSegment) { // todo and is currently playing?
|
||||
const nextAction = getPlaybackMode({ playbackMode, currentTime, playingSegment: { start: getSegApparentStart(playingSegment), end: getSegApparentEnd(playingSegment) } });
|
||||
|
||||
if (nextAction != null) {
|
||||
console.log(nextAction);
|
||||
if (nextAction.nextSegment) {
|
||||
const index = selectedSegments.indexOf(playingSegment);
|
||||
let newIndex = getNewJumpIndex(index >= 0 ? index : 0, 1);
|
||||
if (newIndex > selectedSegments.length - 1) newIndex = 0; // have reached end of last segment, start over
|
||||
const nextSelectedSegment = selectedSegments[newIndex];
|
||||
if (nextSelectedSegment != null) seekAbs(nextSelectedSegment.start);
|
||||
}
|
||||
if (nextAction.seekTo != null) {
|
||||
seekAbs(nextAction.seekTo);
|
||||
}
|
||||
if (nextAction.exit) {
|
||||
playbackModeRef.current = undefined;
|
||||
pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [getCutSegmentById, getSegApparentEnd, pause, playbackModeRef, playerTime, seekAbs, selectedSegments, setPlayerTime]);
|
||||
}, [commandedTimeRef, cutSegments, getSegApparentEnd, pause, playbackModeRef, playerTime, seekAbs, selectedSegments, setPlayerTime]);
|
||||
|
||||
const closeFileWithConfirm = useCallback(() => {
|
||||
if (!isFileOpened || workingRef.current) return;
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ function SegmentList({
|
|||
if (cutSegments.length < 2) return;
|
||||
const { value } = await Swal.fire({
|
||||
title: `${t('Change order of segment')} ${index + 1}`,
|
||||
text: t('Please enter a number from 1 to {{n}} to be the new order for the current segment', { n: cutSegments.length}),
|
||||
text: t('Please enter a number from 1 to {{n}} to be the new order for the current segment', { n: cutSegments.length }),
|
||||
input: 'text',
|
||||
inputValue: index + 1,
|
||||
showCancelButton: true,
|
||||
|
|
|
|||
|
|
@ -148,8 +148,6 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
|
|||
end: getSegApparentEnd(cutSegment),
|
||||
})), [getSegApparentEnd]);
|
||||
|
||||
const getCutSegmentById = useCallback((id: string) => cutSegments.find((s) => s.segId === id), [cutSegments]);
|
||||
|
||||
const haveInvalidSegs = useMemo(() => cutSegments.some((cutSegment) => getSegApparentStart(cutSegment) >= getSegApparentEnd(cutSegment)), [cutSegments, getSegApparentEnd]);
|
||||
|
||||
const currentSegIndexSafe = Math.min(currentSegIndex, cutSegments.length - 1);
|
||||
|
|
@ -683,7 +681,6 @@ function useSegments({ filePath, workingRef, setWorking, setProgress, videoStrea
|
|||
createNumSegments,
|
||||
createFixedDurationSegments,
|
||||
createRandomSegments,
|
||||
getCutSegmentById,
|
||||
getApparentCutSegments,
|
||||
getSegApparentEnd,
|
||||
haveInvalidSegs,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { ReactEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ReactEventHandler, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { ChromiumHTMLVideoElement, PlaybackMode } from '../types';
|
||||
import { isDurationValid } from '../segments';
|
||||
import { showPlaybackFailedMessage } from '../swal';
|
||||
|
||||
export default ({ filePath }: { filePath: string | undefined }) => {
|
||||
const [commandedTime, setCommandedTime] = useState(0);
|
||||
const [commandedTime, setCommandedTimeRaw] = useState(0);
|
||||
const [compatPlayerEventId, setCompatPlayerEventId] = useState(0);
|
||||
const [playbackRate, setPlaybackRateState] = useState(1);
|
||||
const [outputPlaybackRate, setOutputPlaybackRateState] = useState(1);
|
||||
|
|
@ -54,6 +54,13 @@ export default ({ filePath }: { filePath: string | undefined }) => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
const commandedTimeRef = useRef(commandedTime);
|
||||
|
||||
const setCommandedTime = useCallback((t: number) => {
|
||||
commandedTimeRef.current = t;
|
||||
setCommandedTimeRaw(t);
|
||||
}, []);
|
||||
|
||||
const seekAbs = useCallback((val: number | undefined) => {
|
||||
const video = videoRef.current;
|
||||
if (video == null || val == null || Number.isNaN(val)) return;
|
||||
|
|
@ -64,12 +71,7 @@ export default ({ filePath }: { filePath: string | undefined }) => {
|
|||
smoothSeek(outVal);
|
||||
setCommandedTime(outVal);
|
||||
setCompatPlayerEventId((id) => id + 1); // To make sure that we can seek even to the same commanded time that we are already add (e.g. loop current segment)
|
||||
}, [smoothSeek]);
|
||||
|
||||
const commandedTimeRef = useRef(commandedTime);
|
||||
useEffect(() => {
|
||||
commandedTimeRef.current = commandedTime;
|
||||
}, [commandedTime]);
|
||||
}, [setCommandedTime, smoothSeek]);
|
||||
|
||||
// Relevant time is the player's playback position if we're currently playing - if not, it's the user's commanded time.
|
||||
const relevantTime = useMemo(() => (playing ? playerTime : commandedTime) || 0, [commandedTime, playerTime, playing]);
|
||||
|
|
@ -86,7 +88,7 @@ export default ({ filePath }: { filePath: string | undefined }) => {
|
|||
if (!val) {
|
||||
setCommandedTime(videoRef.current!.currentTime);
|
||||
}
|
||||
}, []);
|
||||
}, [setCommandedTime]);
|
||||
|
||||
const onStopPlaying = useCallback(() => {
|
||||
onPlayingChange(false);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function findSegmentsAtCursor(segments: SegmentBase[], currentTime: numbe
|
|||
segments.forEach((segment, index) => {
|
||||
if ((segment.start == null || segment.start <= currentTime) && (segment.end == null || segment.end >= currentTime)) indexes.push(index);
|
||||
});
|
||||
return indexes;
|
||||
return indexes.reverse(); // if we are on multiple, select the last. That way, auto play selected segments won't go on repeat on the same segment
|
||||
}
|
||||
|
||||
// in the past we had non-string tags
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue