1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 18:32:34 +01:00

implement go to timecode #625

inputted value
`g` key or right click timeline context menu
This commit is contained in:
Mikael Finstad 2022-01-14 22:54:33 +07:00
parent 9e05ec3498
commit 87df1c5e5f
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
4 changed files with 34 additions and 12 deletions

View File

@ -1648,6 +1648,18 @@ const App = memo(() => {
}
}, [customOutDir, filePath, html5ifyAndLoad, hasVideo, hasAudio, rememberConvertToSupportedFormat, setWorking]);
const goToTimecode = useCallback(async () => {
if (!filePath) return;
const timeCode = await promptTimeOffset({
initialValue: formatDuration({ seconds: commandedTimeRef.current }),
title: i18n.t('Seek to timecode'),
});
if (timeCode === undefined) return;
seekAbs(timeCode);
}, [filePath, seekAbs]);
// TODO split up?
useEffect(() => {
@ -1704,6 +1716,7 @@ const App = memo(() => {
mousetrap.bind('d', () => cleanupFiles());
mousetrap.bind('b', () => splitCurrentSegment());
mousetrap.bind('r', () => increaseRotation());
mousetrap.bind('g', () => goToTimecode());
mousetrap.bind('left', () => seekBackwards());
mousetrap.bind('left', () => seekReset(), 'keyup');
@ -1746,7 +1759,7 @@ const App = memo(() => {
setCutEnd, setCutStart, seekRel, seekRelPercent, shortStep, cleanupFiles, jumpSeg,
seekClosestKeyframe, zoomRel, toggleComfortZoom, splitCurrentSegment, exportConfirmVisible,
increaseRotation, jumpCutStart, jumpCutEnd, cutSegmentsHistory, keyboardSeekAccFactor,
keyboardNormalSeekSpeed, onLabelSegmentPress, currentSegIndexSafe, batchFileJump,
keyboardNormalSeekSpeed, onLabelSegmentPress, currentSegIndexSafe, batchFileJump, goToTimecode,
]);
const onVideoError = useCallback(async () => {
@ -1797,9 +1810,11 @@ const App = memo(() => {
}
async function setStartOffset() {
const newStartTimeOffset = await promptTimeOffset(
startTimeOffset !== undefined ? formatDuration({ seconds: startTimeOffset }) : undefined,
);
const newStartTimeOffset = await promptTimeOffset({
initialValue: startTimeOffset !== undefined ? formatDuration({ 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)'),
});
if (newStartTimeOffset === undefined) return;
@ -2415,6 +2430,7 @@ const App = memo(() => {
playing={playing}
isFileOpened={isFileOpened}
onWheel={onTimelineWheel}
goToTimecode={goToTimecode}
/>
<TimelineControls

View File

@ -60,6 +60,7 @@ const HelpSheet = memo(({ visible, onTogglePress, ffmpegCommandLog, currentCutSe
<div><kbd>CTRL</kbd> / <kbd>CMD</kbd> + <kbd></kbd> {t('Seek forward 1% of timeline at current zoom')}</div>
<div style={{ lineHeight: 1.7 }}><SegmentCutpointButton currentCutSeg={currentCutSeg} side="start" Icon={FaStepBackward} style={{ verticalAlign: 'middle' }} />, <kbd>SHIFT</kbd> + <kbd></kbd> {t('Jump to cut start')}</div>
<div style={{ lineHeight: 1.7 }}><SegmentCutpointButton currentCutSeg={currentCutSeg} side="end" Icon={FaStepForward} style={{ verticalAlign: 'middle' }} />, <kbd>SHIFT</kbd> + <kbd></kbd> {t('Jump to cut end')}</div>
<div><kbd>G</kbd> {t('Seek to timecode')}</div>
<h2>{t('Segments and cut points')}</h2>

View File

@ -7,6 +7,7 @@ import { FaCaretDown, FaCaretUp } from 'react-icons/fa';
import TimelineSeg from './TimelineSeg';
import BetweenSegments from './BetweenSegments';
import useContextMenu from './hooks/useContextMenu';
import { timelineBackground } from './colors';
@ -41,14 +42,14 @@ const Waveform = memo(({ calculateTimelinePercent, durationSafe, waveform, zoom,
const CommandedTime = memo(({ commandedTimePercent }) => {
const color = 'white';
const commonStyle = { left: commandedTimePercent, position: 'absolute', zIndex: 4, pointerEvents: 'none' }
const commonStyle = { left: commandedTimePercent, position: 'absolute', zIndex: 4, pointerEvents: 'none' };
return (
<>
<FaCaretDown style={{ ...commonStyle, top: 0, color, fontSize: 14, marginLeft: -7, marginTop: -6 }} />
<div style={{ ...commonStyle, bottom: 0, top: 0, backgroundColor: color, width: currentTimeWidth }} />
<FaCaretUp style={{ ...commonStyle, bottom: 0, color, fontSize: 14, marginLeft: -7, marginBottom: -5 }} />
</>
)
);
});
const Timeline = memo(({
@ -57,7 +58,7 @@ const Timeline = memo(({
setCurrentSegIndex, currentSegIndexSafe, invertCutSegments, inverseCutSegments, formatTimecode,
waveform, shouldShowWaveform, shouldShowKeyframes, timelineHeight, thumbnails,
onZoomWindowStartTimeChange, waveformEnabled, thumbnailsEnabled,
playing, isFileOpened, onWheel, commandedTimeRef,
playing, isFileOpened, onWheel, commandedTimeRef, goToTimecode,
}) => {
const { t } = useTranslation();
@ -191,6 +192,10 @@ const Timeline = memo(({
const onMouseMove = useCallback((e) => setHoveringTime(getMouseTimelinePos(e.nativeEvent)), [getMouseTimelinePos]);
const onMouseOut = useCallback(() => setHoveringTime(), []);
useContextMenu(timelineScrollerRef, [
{ label: t('Seek to timecode'), click: goToTimecode },
]);
return (
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
<Hammer

View File

@ -21,12 +21,12 @@ const { dialog, app } = electron.remote;
const ReactSwal = withReactContent(Swal);
export async function promptTimeOffset(inputValue) {
export async function promptTimeOffset({ initialValue, title, text }) {
const { value } = await Swal.fire({
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)'),
title,
text,
input: 'text',
inputValue: inputValue || '',
inputValue: initialValue || '',
showCancelButton: true,
inputPlaceholder: '00:00:00.000',
});
@ -37,7 +37,7 @@ export async function promptTimeOffset(inputValue) {
const duration = parseDuration(value);
// Invalid, try again
if (duration === undefined) return promptTimeOffset(value);
if (duration === undefined) return promptTimeOffset({ initialValue: value, title, text });
return duration;
}