mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-25 19:52:44 +01:00
allow showing timecode as frame counts #878
This commit is contained in:
parent
7928257003
commit
6b5857b902
@ -13,7 +13,7 @@ const defaults = {
|
||||
keyframeCut: true,
|
||||
autoMerge: false,
|
||||
autoDeleteMergedSegments: true,
|
||||
timecodeShowFrames: false,
|
||||
timecodeFormat: 'timecodeWithDecimalFraction',
|
||||
invertCutSegments: false,
|
||||
autoExportExtraStreams: true,
|
||||
exportConfirmEnabled: true,
|
||||
|
23
src/App.jsx
23
src/App.jsx
@ -170,7 +170,7 @@ const App = memo(() => {
|
||||
const isCustomFormatSelected = fileFormat !== detectedFileFormat;
|
||||
|
||||
const {
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoMerge, setAutoMerge, timecodeShowFrames, setTimecodeShowFrames, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, setAutoExportExtraStreams, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, setAutoSaveProjectFile, wheelSensitivity, setWheelSensitivity, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, autoDeleteMergedSegments, setAutoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, setKeyboardSeekAccFactor, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, enableTransferTimestamps, setEnableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName,
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoMerge, setAutoMerge, timecodeFormat, setTimecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, setAutoExportExtraStreams, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, setAutoSaveProjectFile, wheelSensitivity, setWheelSensitivity, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, ffmpegExperimental, setFfmpegExperimental, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, autoDeleteMergedSegments, setAutoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, keyboardSeekAccFactor, setKeyboardSeekAccFactor, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, enableTransferTimestamps, setEnableTransferTimestamps, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName,
|
||||
} = useUserPreferences();
|
||||
|
||||
const {
|
||||
@ -421,15 +421,22 @@ const App = memo(() => {
|
||||
setCutSegments(sortBy(cutSegments, getSegApparentStart));
|
||||
}, [cutSegments, setCutSegments]);
|
||||
|
||||
const formatTimecode = useCallback((sec) => formatDuration({
|
||||
seconds: sec, fps: timecodeShowFrames ? detectedFps : undefined,
|
||||
}), [detectedFps, timecodeShowFrames]);
|
||||
|
||||
const getFrameCount = useCallback((sec) => {
|
||||
if (detectedFps == null) return undefined;
|
||||
return Math.floor(sec * detectedFps);
|
||||
}, [detectedFps]);
|
||||
|
||||
const formatTimecode = useCallback((sec) => {
|
||||
if (timecodeFormat === 'framesTotal') {
|
||||
const frameCount = getFrameCount(sec);
|
||||
return frameCount != null ? frameCount : '';
|
||||
}
|
||||
if (timecodeFormat === 'timecodeWithFramesFraction') {
|
||||
return formatDuration({ seconds: sec, fps: detectedFps });
|
||||
}
|
||||
return formatDuration({ seconds: sec });
|
||||
}, [detectedFps, timecodeFormat, getFrameCount]);
|
||||
|
||||
useEffect(() => {
|
||||
currentTimeRef.current = playing ? playerTime : commandedTime;
|
||||
}, [commandedTime, playerTime, playing]);
|
||||
@ -2047,8 +2054,8 @@ const App = memo(() => {
|
||||
setInvertCutSegments={setInvertCutSegments}
|
||||
autoSaveProjectFile={autoSaveProjectFile}
|
||||
setAutoSaveProjectFile={setAutoSaveProjectFile}
|
||||
timecodeShowFrames={timecodeShowFrames}
|
||||
setTimecodeShowFrames={setTimecodeShowFrames}
|
||||
timecodeFormat={timecodeFormat}
|
||||
setTimecodeFormat={setTimecodeFormat}
|
||||
askBeforeClose={askBeforeClose}
|
||||
setAskBeforeClose={setAskBeforeClose}
|
||||
enableAskForImportChapters={enableAskForImportChapters}
|
||||
@ -2071,7 +2078,7 @@ const App = memo(() => {
|
||||
renderCaptureFormatButton={renderCaptureFormatButton}
|
||||
onTunerRequested={onTunerRequested}
|
||||
/>
|
||||
), [changeOutDir, customOutDir, keyframeCut, setKeyframeCut, invertCutSegments, setInvertCutSegments, autoSaveProjectFile, setAutoSaveProjectFile, timecodeShowFrames, setTimecodeShowFrames, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, ffmpegExperimental, setFfmpegExperimental, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, AutoExportToggler, renderCaptureFormatButton, onTunerRequested, enableTransferTimestamps, setEnableTransferTimestamps]);
|
||||
), [changeOutDir, customOutDir, keyframeCut, setKeyframeCut, invertCutSegments, setInvertCutSegments, autoSaveProjectFile, setAutoSaveProjectFile, timecodeFormat, setTimecodeFormat, askBeforeClose, setAskBeforeClose, enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction, ffmpegExperimental, setFfmpegExperimental, invertTimelineScroll, setInvertTimelineScroll, language, setLanguage, hideNotifications, setHideNotifications, autoLoadTimecode, setAutoLoadTimecode, AutoExportToggler, renderCaptureFormatButton, onTunerRequested, enableTransferTimestamps, setEnableTransferTimestamps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isStoreBuild) loadMifiLink().then(setMifiLink);
|
||||
|
@ -1,12 +1,39 @@
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import React, { memo, useCallback, useMemo } from 'react';
|
||||
import { FaYinYang } from 'react-icons/fa';
|
||||
import { Button, Table, NumericalIcon, KeyIcon, FolderCloseIcon, DocumentIcon, TimeIcon, Checkbox, Select } from 'evergreen-ui';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
||||
// https://www.electronjs.org/docs/api/locales
|
||||
// See i18n.js
|
||||
const langNames = {
|
||||
en: 'English',
|
||||
cs: 'Čeština',
|
||||
de: 'Deutsch',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
it: 'Italiano',
|
||||
nl: 'Nederlands',
|
||||
nb: 'Norsk',
|
||||
pl: 'Polski',
|
||||
pt: 'Português',
|
||||
pt_BR: 'português do Brasil',
|
||||
fi: 'Suomi',
|
||||
ru: 'русский',
|
||||
// sr: 'Cрпски',
|
||||
tr: 'Türkçe',
|
||||
vi: 'Tiếng Việt',
|
||||
ja: '日本語',
|
||||
zh: '中文',
|
||||
zh_Hant: '繁體中文',
|
||||
zh_Hans: '简体中文',
|
||||
ko: '한국어',
|
||||
};
|
||||
|
||||
|
||||
const Settings = memo(({
|
||||
changeOutDir, customOutDir, keyframeCut, setKeyframeCut, invertCutSegments, setInvertCutSegments,
|
||||
autoSaveProjectFile, setAutoSaveProjectFile, timecodeShowFrames, setTimecodeShowFrames, askBeforeClose, setAskBeforeClose,
|
||||
autoSaveProjectFile, setAutoSaveProjectFile, timecodeFormat, setTimecodeFormat, askBeforeClose, setAskBeforeClose,
|
||||
AutoExportToggler, renderCaptureFormatButton, onTunerRequested, language, setLanguage,
|
||||
invertTimelineScroll, setInvertTimelineScroll, ffmpegExperimental, setFfmpegExperimental,
|
||||
enableAskForImportChapters, setEnableAskForImportChapters, enableAskForFileOpenAction, setEnableAskForFileOpenAction,
|
||||
@ -26,31 +53,19 @@ const Settings = memo(({
|
||||
setLanguage(l);
|
||||
}, [setLanguage]);
|
||||
|
||||
// https://www.electronjs.org/docs/api/locales
|
||||
// See i18n.js
|
||||
const langNames = {
|
||||
en: 'English',
|
||||
cs: 'Čeština',
|
||||
de: 'Deutsch',
|
||||
es: 'Español',
|
||||
fr: 'Français',
|
||||
it: 'Italiano',
|
||||
nl: 'Nederlands',
|
||||
nb: 'Norsk',
|
||||
pl: 'Polski',
|
||||
pt: 'Português',
|
||||
pt_BR: 'português do Brasil',
|
||||
fi: 'Suomi',
|
||||
ru: 'русский',
|
||||
// sr: 'Cрпски',
|
||||
tr: 'Türkçe',
|
||||
vi: 'Tiếng Việt',
|
||||
ja: '日本語',
|
||||
zh: '中文',
|
||||
zh_Hant: '繁體中文',
|
||||
zh_Hans: '简体中文',
|
||||
ko: '한국어',
|
||||
};
|
||||
const timecodeFormatOptions = useMemo(() => ({
|
||||
framesTotal: t('Frame numbers'),
|
||||
timecodeWithDecimalFraction: t('Millisecond fractions'),
|
||||
timecodeWithFramesFraction: t('Frame fractions'),
|
||||
}), [t]);
|
||||
|
||||
const onTimecodeFormatClick = useCallback(() => {
|
||||
const keys = Object.keys(timecodeFormatOptions);
|
||||
let index = keys.indexOf(timecodeFormat);
|
||||
if (index === -1 || index >= keys.length - 1) index = 0;
|
||||
else index += 1;
|
||||
setTimecodeFormat(keys[index]);
|
||||
}, [setTimecodeFormat, timecodeFormat, timecodeFormatOptions]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -159,8 +174,8 @@ const Settings = memo(({
|
||||
<Row>
|
||||
<KeyCell>{t('In timecode show')}</KeyCell>
|
||||
<Table.TextCell>
|
||||
<Button iconBefore={timecodeShowFrames ? NumericalIcon : TimeIcon} onClick={() => setTimecodeShowFrames((v) => !v)}>
|
||||
{timecodeShowFrames ? t('Frame numbers') : t('Millisecond fractions')}
|
||||
<Button iconBefore={timecodeFormat === 'framesTotal' ? NumericalIcon : TimeIcon} onClick={onTimecodeFormatClick}>
|
||||
{timecodeFormatOptions[timecodeFormat]}
|
||||
</Button>
|
||||
</Table.TextCell>
|
||||
</Row>
|
||||
|
@ -38,8 +38,8 @@ export default () => {
|
||||
useEffect(() => safeSetConfig('avoidNegativeTs', avoidNegativeTs), [avoidNegativeTs]);
|
||||
const [autoMerge, setAutoMerge] = useState(configStore.get('autoMerge'));
|
||||
useEffect(() => safeSetConfig('autoMerge', autoMerge), [autoMerge]);
|
||||
const [timecodeShowFrames, setTimecodeShowFrames] = useState(configStore.get('timecodeShowFrames'));
|
||||
useEffect(() => safeSetConfig('timecodeShowFrames', timecodeShowFrames), [timecodeShowFrames]);
|
||||
const [timecodeFormat, setTimecodeFormat] = useState(configStore.get('timecodeFormat'));
|
||||
useEffect(() => safeSetConfig('timecodeFormat', timecodeFormat), [timecodeFormat]);
|
||||
const [invertCutSegments, setInvertCutSegments] = useState(configStore.get('invertCutSegments'));
|
||||
useEffect(() => safeSetConfig('invertCutSegments', invertCutSegments), [invertCutSegments]);
|
||||
const [autoExportExtraStreams, setAutoExportExtraStreams] = useState(configStore.get('autoExportExtraStreams'));
|
||||
@ -113,8 +113,8 @@ export default () => {
|
||||
setAvoidNegativeTs,
|
||||
autoMerge,
|
||||
setAutoMerge,
|
||||
timecodeShowFrames,
|
||||
setTimecodeShowFrames,
|
||||
timecodeFormat,
|
||||
setTimecodeFormat,
|
||||
invertCutSegments,
|
||||
setInvertCutSegments,
|
||||
autoExportExtraStreams,
|
||||
|
Loading…
Reference in New Issue
Block a user