mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-21 18:02:35 +01:00
allow relative timeline seek #2056
This commit is contained in:
parent
8a6dd62d6d
commit
6a98e3315b
@ -79,7 +79,7 @@ import { formatDuration, parseDuration } from './util/duration';
|
||||
import { adjustRate } from './util/rate-calculator';
|
||||
import { askExtractFramesAsImages } from './dialogs/extractFrames';
|
||||
import { askForHtml5ifySpeed } from './dialogs/html5ify';
|
||||
import { askForOutDir, askForImportChapters, promptTimeOffset, askForFileOpenAction, confirmExtractAllStreamsDialog, showCleanupFilesDialog, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, openDirToast, openExportFinishedToast, openConcatFinishedToast, showOpenDialog, showMuxNotSupported } from './dialogs';
|
||||
import { askForOutDir, askForImportChapters, promptTimecode, askForFileOpenAction, confirmExtractAllStreamsDialog, showCleanupFilesDialog, showDiskFull, showExportFailedDialog, showConcatFailedDialog, openYouTubeChaptersDialog, showRefuseToOverwrite, openDirToast, openExportFinishedToast, openConcatFinishedToast, showOpenDialog, showMuxNotSupported } from './dialogs';
|
||||
import { openSendReportDialog } from './reporting';
|
||||
import { fallbackLng } from './i18n';
|
||||
import { createSegment, getCleanCutSegments, findSegmentsAtCursor, sortSegments, convertSegmentsToChapters, hasAnySegmentOverlap, isDurationValid, playOnlyCurrentSegment, getSegmentTags } from './segments';
|
||||
@ -1736,17 +1736,20 @@ function App() {
|
||||
|
||||
const goToTimecode = useCallback(async () => {
|
||||
if (!filePath) return;
|
||||
const timecode = await promptTimeOffset({
|
||||
const timecode = await promptTimecode({
|
||||
initialValue: formatTimecode({ seconds: commandedTimeRef.current }),
|
||||
title: i18n.t('Seek to timecode'),
|
||||
text: i18n.t('Use + and - for relative seek'),
|
||||
allowRelative: true,
|
||||
inputPlaceholder: timecodePlaceholder,
|
||||
parseTimecode,
|
||||
});
|
||||
|
||||
if (timecode === undefined) return;
|
||||
|
||||
userSeekAbs(timecode);
|
||||
}, [filePath, formatTimecode, parseTimecode, timecodePlaceholder, userSeekAbs]);
|
||||
if (timecode.relDirection != null) seekRel(timecode.duration * timecode.relDirection);
|
||||
else userSeekAbs(timecode.duration);
|
||||
}, [filePath, formatTimecode, parseTimecode, seekRel, timecodePlaceholder, userSeekAbs]);
|
||||
|
||||
const goToTimecodeDirect = useCallback(async ({ time: timeStr }: { time: string }) => {
|
||||
if (!filePath) return;
|
||||
@ -1819,7 +1822,7 @@ function App() {
|
||||
}, [customOutDir, filePath, html5ifyAndLoad, hasVideo, hasAudio, rememberConvertToSupportedFormat, setWorking]);
|
||||
|
||||
const askStartTimeOffset = useCallback(async () => {
|
||||
const newStartTimeOffset = await promptTimeOffset({
|
||||
const newStartTimeOffset = await promptTimecode({
|
||||
initialValue: startTimeOffset !== undefined ? formatTimecode({ seconds: startTimeOffset }) : undefined,
|
||||
title: i18n.t('Set custom start time offset'),
|
||||
text: i18n.t('Instead of video apparently starting at 0, you can offset by a specified value. This only applies to the preview inside LosslessCut and does not modify the file in any way. (Useful for viewing/cutting videos according to timecodes)'),
|
||||
@ -1827,9 +1830,9 @@ function App() {
|
||||
parseTimecode,
|
||||
});
|
||||
|
||||
if (newStartTimeOffset === undefined) return;
|
||||
if (newStartTimeOffset === undefined || newStartTimeOffset.duration < 0) return;
|
||||
|
||||
setStartTimeOffset(newStartTimeOffset);
|
||||
setStartTimeOffset(newStartTimeOffset.duration);
|
||||
}, [formatTimecode, parseTimecode, startTimeOffset, timecodePlaceholder]);
|
||||
|
||||
const toggleKeyboardShortcuts = useCallback(() => setKeyboardShortcutsVisible((v) => !v), []);
|
||||
|
@ -18,8 +18,10 @@ import { ParseTimecode, SegmentBase } from '../types';
|
||||
const { dialog, shell } = window.require('@electron/remote');
|
||||
|
||||
|
||||
export async function promptTimeOffset({ initialValue, title, text, inputPlaceholder, parseTimecode }: { initialValue?: string | undefined, title: string, text?: string | undefined, inputPlaceholder: string, parseTimecode: ParseTimecode }) {
|
||||
const { value } = await Swal.fire({
|
||||
export async function promptTimecode({ initialValue, title, text, inputPlaceholder, parseTimecode, allowRelative = false }: {
|
||||
initialValue?: string | undefined, title: string, text?: string | undefined, inputPlaceholder: string, parseTimecode: ParseTimecode, allowRelative?: boolean,
|
||||
}) {
|
||||
const { value } = await Swal.fire<string>({
|
||||
title,
|
||||
text,
|
||||
input: 'text',
|
||||
@ -35,11 +37,22 @@ export async function promptTimeOffset({ initialValue, title, text, inputPlaceho
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const duration = parseTimecode(value);
|
||||
// Invalid, try again
|
||||
if (duration === undefined) return promptTimeOffset({ initialValue: value, title, text, inputPlaceholder, parseTimecode });
|
||||
let relDirection: number | undefined;
|
||||
if (allowRelative) {
|
||||
if (value.startsWith('-')) relDirection = -1;
|
||||
else if (value.startsWith('+')) relDirection = 1;
|
||||
}
|
||||
|
||||
return duration;
|
||||
const value2 = allowRelative ? value.replace(/^[+-]/, '') : value;
|
||||
|
||||
const duration = parseTimecode(value2);
|
||||
// Invalid, try again
|
||||
if (duration === undefined) return promptTimecode({ initialValue: value, title, text, inputPlaceholder, parseTimecode, allowRelative });
|
||||
|
||||
return {
|
||||
duration,
|
||||
relDirection,
|
||||
};
|
||||
}
|
||||
|
||||
// https://github.com/mifi/lossless-cut/issues/1495
|
||||
|
Loading…
Reference in New Issue
Block a user