Skip to content

Commit

Permalink
implement 2 more configurable seek speeds
Browse files Browse the repository at this point in the history
  • Loading branch information
mifi committed May 14, 2024
1 parent 236bdd8 commit 8436bfd
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 28 deletions.
4 changes: 4 additions & 0 deletions src/main/configStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ const defaultKeyBindings: KeyBinding[] = [
{ keys: 'g', action: 'goToTimecode' },

{ keys: 'left', action: 'seekBackwards' },
{ keys: 'ctrl+shift+left', action: 'seekBackwards2' },
{ keys: 'ctrl+left', action: 'seekBackwardsPercent' },
{ keys: 'command+left', action: 'seekBackwardsPercent' },
{ keys: 'alt+left', action: 'seekBackwardsKeyframe' },
{ keys: 'shift+left', action: 'jumpCutStart' },

{ keys: 'right', action: 'seekForwards' },
{ keys: 'ctrl+shift+right', action: 'seekForwards2' },
{ keys: 'ctrl+right', action: 'seekForwardsPercent' },
{ keys: 'command+right', action: 'seekForwardsPercent' },
{ keys: 'alt+right', action: 'seekForwardsKeyframe' },
Expand Down Expand Up @@ -114,6 +116,8 @@ const defaults: Config = {
outSegTemplate: undefined,
keyboardSeekAccFactor: 1.03,
keyboardNormalSeekSpeed: 1,
keyboardSeekSpeed2: 10,
keyboardSeekSpeed3: 60,
treatInputFileModifiedTimeAsStart: true,
treatOutputFileModifiedTimeAsStart: true,
outFormatLocked: undefined,
Expand Down
35 changes: 17 additions & 18 deletions src/renderer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function App() {
const allUserSettings = useUserSettingsRoot();

const {
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
} = allUserSettings;

useEffect(() => {
Expand Down Expand Up @@ -2087,6 +2087,15 @@ function App() {
seekAccelerationRef.current = 1;
}

function seekRel2({ keyup, amount }: { keyup: boolean | undefined, amount: number }) {
if (keyup) {
seekReset();
return;
}
seekRel(seekAccelerationRef.current * amount);
seekAccelerationRef.current *= keyboardSeekAccFactor;
}

const ret: Record<MainKeyboardAction, ((a: { keyup?: boolean | undefined }) => boolean) | ((a: { keyup?: boolean | undefined }) => void)> = {
// NOTE: Do not change these keys because users have bound keys by these names in their config files
// For actions, see also KeyboardShortcuts.jsx
Expand All @@ -2111,22 +2120,12 @@ function App() {
splitCurrentSegment,
increaseRotation,
goToTimecode,
seekBackwards({ keyup }) {
if (keyup) {
seekReset();
return;
}
seekRel(keyboardNormalSeekSpeed * seekAccelerationRef.current * -1);
seekAccelerationRef.current *= keyboardSeekAccFactor;
},
seekForwards({ keyup }) {
if (keyup) {
seekReset();
return;
}
seekRel(keyboardNormalSeekSpeed * seekAccelerationRef.current);
seekAccelerationRef.current *= keyboardSeekAccFactor;
},
seekBackwards: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardNormalSeekSpeed }),
seekBackwards2: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardSeekSpeed2 }),
seekBackwards3: ({ keyup }) => seekRel2({ keyup, amount: -1 * keyboardSeekSpeed3 }),
seekForwards: ({ keyup }) => seekRel2({ keyup, amount: keyboardNormalSeekSpeed }),
seekForwards2: ({ keyup }) => seekRel2({ keyup, amount: keyboardSeekSpeed2 }),
seekForwards3: ({ keyup }) => seekRel2({ keyup, amount: keyboardSeekSpeed3 }),
seekBackwardsPercent: () => { seekRelPercent(-0.01); return false; },
seekForwardsPercent: () => { seekRelPercent(0.01); return false; },
seekBackwardsKeyframe: () => seekClosestKeyframe(-1),
Expand Down Expand Up @@ -2220,7 +2219,7 @@ function App() {
};

return ret;
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegments.length, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, editCurrentSegmentTags, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCurrentSegIndex, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleStripThumbnail, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegments.length, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, editCurrentSegmentTags, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, keyboardSeekSpeed2, keyboardSeekSpeed3, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCurrentSegIndex, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleStripThumbnail, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);

const getKeyboardAction = useCallback((action: MainKeyboardAction) => mainActions[action], [mainActions]);

Expand Down
20 changes: 18 additions & 2 deletions src/renderer/src/components/KeyboardShortcuts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,27 @@ const KeyboardShortcuts = memo(({
category: seekingCategory,
},
seekBackwards: {
name: t('Seek backward 1 sec'),
name: t('Backward seek'),
category: seekingCategory,
},
seekForwards: {
name: t('Seek forward 1 sec'),
name: t('Forward seek'),
category: seekingCategory,
},
seekBackwards2: {
name: t('Backward seek (longer)'),
category: seekingCategory,
},
seekForwards2: {
name: t('Forward seek (longer)'),
category: seekingCategory,
},
seekBackwards3: {
name: t('Backward seek (longest)'),
category: seekingCategory,
},
seekForwards3: {
name: t('Forward seek (longest)'),
category: seekingCategory,
},
seekBackwardsKeyframe: {
Expand Down
16 changes: 15 additions & 1 deletion src/renderer/src/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -357,12 +357,26 @@ const Settings = memo(({
</Row>

<Row>
<KeyCell>{t('Timeline keyboard seek speed')}</KeyCell>
<KeyCell>{t('Timeline keyboard seek interval')}</KeyCell>
<td>
<Button iconBefore={CogIcon} onClick={() => onTunerRequested('keyboardNormalSeekSpeed')}>{t('Change value')}</Button>
</td>
</Row>

<Row>
<KeyCell>{t('Timeline keyboard seek interval (longer)')}</KeyCell>
<td>
<Button iconBefore={CogIcon} onClick={() => onTunerRequested('keyboardSeekSpeed2')}>{t('Change value')}</Button>
</td>
</Row>

<Row>
<KeyCell>{t('Timeline keyboard seek interval (longest)')}</KeyCell>
<td>
<Button iconBefore={CogIcon} onClick={() => onTunerRequested('keyboardSeekSpeed3')}>{t('Change value')}</Button>
</td>
</Row>

<Row>
<KeyCell>{t('Timeline keyboard seek acceleration')}</KeyCell>
<td>
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/components/ValueTuner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution
<div style={{ background: 'var(--gray1)', color: 'var(--gray12)', position: 'absolute', bottom: 0, padding: 10, margin: 10, borderRadius: 10, ...style }}>
<div style={{ display: 'flex', alignItems: 'center', flexBasis: 400, marginBottom: '.2em' }}>
<div>{title}</div>
<div style={{ marginLeft: '.5em', fontWeight: 'bold', marginRight: '.5em', textDecoration: 'underline' }}>{value.toFixed(4)}</div>
<div style={{ marginLeft: '.5em', fontWeight: 'bold', marginRight: '.5em', textDecoration: 'underline', fontFamily: 'monospace', width: '5em' }}>{value.toFixed(4)}</div>
<Switch checked={isZoomed} onCheckedChange={toggleZoom} style={{ flexShrink: 0 }} /><span style={{ marginLeft: '.3em' }}>{t('Precise')}</span>
</div>

Expand Down
22 changes: 19 additions & 3 deletions src/renderer/src/components/ValueTuners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TunerType } from '../types';

const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: () => void }) => {
const { t } = useTranslation();
const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings();
const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, keyboardSeekSpeed2, setKeyboardSeekSpeed2, keyboardSeekSpeed3, setKeyboardSeekSpeed3, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings();

// NOTE default values are duplicated in src/main/configStore.js
const types = {
Expand All @@ -20,13 +20,29 @@ const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: (
default: 0.2,
},
keyboardNormalSeekSpeed: {
title: t('Timeline keyboard seek speed'),
title: t('Timeline keyboard seek interval'),
value: keyboardNormalSeekSpeed,
setValue: setKeyboardNormalSeekSpeed,
min: 0,
max: 100,
max: 120,
default: 1,
},
keyboardSeekSpeed2: {
title: t('Timeline keyboard seek interval (longer)'),
value: keyboardSeekSpeed2,
setValue: setKeyboardSeekSpeed2,
min: 0,
max: 600,
default: 10,
},
keyboardSeekSpeed3: {
title: t('Timeline keyboard seek interval (longest)'),
value: keyboardSeekSpeed3,
setValue: setKeyboardSeekSpeed3,
min: 0,
max: 3600,
default: 60,
},
keyboardSeekAccFactor: {
title: t('Timeline keyboard seek acceleration'),
value: keyboardSeekAccFactor,
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/hooks/useKeyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { KeyBinding, KeyboardAction } from '../../../../types';

// for all dialog actions (e.g. detectSceneChanges) we must use keyup, or we risk having the button press inserted into the dialog's input element right after the dialog opens
// todo use keyup for most events?
const keyupActions = new Set<KeyboardAction>(['seekBackwards', 'seekForwards', 'detectBlackScenes', 'detectSilentScenes', 'detectSceneChanges']);
const keyupActions = new Set<KeyboardAction>(['seekBackwards', 'seekForwards', 'seekBackwards2', 'seekForwards2', 'seekBackwards3', 'seekForwards3', 'detectBlackScenes', 'detectSilentScenes', 'detectSceneChanges']);

interface StoredAction { action: KeyboardAction, keyup?: boolean }

Expand Down
8 changes: 8 additions & 0 deletions src/renderer/src/hooks/useUserSettingsRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export default () => {
useEffect(() => safeSetConfig({ keyboardSeekAccFactor }), [keyboardSeekAccFactor]);
const [keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed] = useState(safeGetConfigInitial('keyboardNormalSeekSpeed'));
useEffect(() => safeSetConfig({ keyboardNormalSeekSpeed }), [keyboardNormalSeekSpeed]);
const [keyboardSeekSpeed2, setKeyboardSeekSpeed2] = useState(safeGetConfigInitial('keyboardSeekSpeed2'));
useEffect(() => safeSetConfig({ keyboardSeekSpeed2 }), [keyboardSeekSpeed2]);
const [keyboardSeekSpeed3, setKeyboardSeekSpeed3] = useState(safeGetConfigInitial('keyboardSeekSpeed3'));
useEffect(() => safeSetConfig({ keyboardSeekSpeed3 }), [keyboardSeekSpeed3]);

const [treatInputFileModifiedTimeAsStart, setTreatInputFileModifiedTimeAsStart] = useState(safeGetConfigInitial('treatInputFileModifiedTimeAsStart'));
useEffect(() => safeSetConfig({ treatInputFileModifiedTimeAsStart }), [treatInputFileModifiedTimeAsStart]);
Expand Down Expand Up @@ -220,6 +224,10 @@ export default () => {
setKeyboardSeekAccFactor,
keyboardNormalSeekSpeed,
setKeyboardNormalSeekSpeed,
keyboardSeekSpeed2,
setKeyboardSeekSpeed2,
keyboardSeekSpeed3,
setKeyboardSeekSpeed3,
treatInputFileModifiedTimeAsStart,
setTreatInputFileModifiedTimeAsStart,
treatOutputFileModifiedTimeAsStart,
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export type EdlImportType = 'youtube' | EdlFileType;

export type EdlExportType = 'csv' | 'tsv-human' | 'csv-human' | 'csv-frames' | 'srt' | 'llc';

export type TunerType = 'wheelSensitivity' | 'keyboardNormalSeekSpeed' | 'keyboardSeekAccFactor';
export type TunerType = 'wheelSensitivity' | 'keyboardNormalSeekSpeed' | 'keyboardSeekSpeed2' | 'keyboardSeekSpeed3' | 'keyboardSeekAccFactor';

export interface RenderableWaveform {
createdAt: Date,
Expand Down
Loading

0 comments on commit 8436bfd

Please sign in to comment.