1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-21 18:02:35 +01:00

allow customising preservation

of map_metadata and chapters

fixes #2176
see #1027
This commit is contained in:
Mikael Finstad 2024-10-06 23:39:19 +02:00
parent 789f857e26
commit 8024884363
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
9 changed files with 103 additions and 69 deletions

View File

@ -106,6 +106,9 @@ const defaults: Config = {
wheelSensitivity: 0.2,
language: undefined,
ffmpegExperimental: false,
preserveChapters: true,
preserveMetadata: 'default',
preserveMetadataOnMerge: false,
preserveMovData: false,
movFastStart: true,
avoidNegativeTs: 'make_zero',
@ -113,7 +116,6 @@ const defaults: Config = {
hideOsNotifications: undefined,
autoLoadTimecode: false,
segmentsToChapters: false,
preserveMetadataOnMerge: false,
simpleMode: true,
outSegTemplate: undefined,
mergedFileTemplate: undefined,

View File

@ -171,7 +171,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, hideOsNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, mergedFileTemplate, setMergedFileTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, mouseWheelFrameSeekModifierKey, mouseWheelKeyframeSeekModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMetadata, preserveChapters, preserveMovData, movFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, hideOsNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, preserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, mergedFileTemplate, setMergedFileTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, mouseWheelFrameSeekModifierKey, mouseWheelKeyframeSeekModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
} = allUserSettings;
const { working, setWorking, workingRef, abortWorking } = useLoading();
@ -238,10 +238,6 @@ function App() {
return newVal;
}), [setExportConfirmEnabled, showNotification]);
const toggleSegmentsToChapters = useCallback(() => setSegmentsToChapters((v) => !v), [setSegmentsToChapters]);
const togglePreserveMetadataOnMerge = useCallback(() => setPreserveMetadataOnMerge((v) => !v), [setPreserveMetadataOnMerge]);
const toggleShowKeyframes = useCallback(() => {
setKeyframesEnabled((old) => {
const enabled = !old;
@ -429,10 +425,6 @@ function App() {
return newVal;
}), [showNotification, setKeyframeCut]);
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), [setPreserveMovData]);
const toggleMovFastStart = useCallback(() => setMovFastStart((val) => !val), [setMovFastStart]);
const toggleSimpleMode = useCallback(() => setSimpleMode((v) => {
showNotification({ text: v ? i18n.t('Advanced view has been enabled. You will now also see non-essential buttons and functions') : i18n.t('Advanced view disabled. You will now see only the most essential buttons and functions') });
const newValue = !v;
@ -477,8 +469,8 @@ function App() {
}, [ensureAccessToSourceDir, getProjectFileSavePath, setStoreProjectInWorkingDir, storeProjectInWorkingDir]);
const userSettingsContext = useMemo<UserSettingsContextType>(() => ({
...allUserSettings, toggleCaptureFormat, changeOutDir, toggleKeyframeCut, togglePreserveMovData, toggleMovFastStart, toggleExportConfirmEnabled, toggleSegmentsToChapters, togglePreserveMetadataOnMerge, toggleSimpleMode, toggleSafeOutputFileName, effectiveExportMode,
}), [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleMovFastStart, togglePreserveMetadataOnMerge, togglePreserveMovData, toggleSafeOutputFileName, toggleSegmentsToChapters, toggleSimpleMode]);
...allUserSettings, toggleCaptureFormat, changeOutDir, toggleKeyframeCut, toggleExportConfirmEnabled, toggleSimpleMode, toggleSafeOutputFileName, effectiveExportMode,
}), [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleSafeOutputFileName, toggleSimpleMode]);
const segColorsContext = useMemo(() => ({
getSegColor: (seg: SegmentColorIndex) => {
@ -804,10 +796,12 @@ function App() {
effectiveExportMode,
outSegTemplate,
mergedFileTemplate,
preserveMetadata,
preserveChapters,
};
openSendReportDialog(err, state);
}, [commonSettings, copyStreamIdsByFile, cutSegments, effectiveExportMode, externalFilesMeta, fileFormat, filePath, mainFileFormatData, mainStreams, mergedFileTemplate, outSegTemplate, rotation, shortestFlag]);
}, [commonSettings, copyStreamIdsByFile, cutSegments, effectiveExportMode, externalFilesMeta, fileFormat, filePath, mainFileFormatData, mainStreams, mergedFileTemplate, outSegTemplate, preserveChapters, preserveMetadata, rotation, shortestFlag]);
const openSendConcatReportDialogWithState = useCallback(async (err: unknown, reportState?: object) => {
const state = { ...commonSettings, ...reportState };
@ -1025,8 +1019,10 @@ function App() {
onProgress: setProgress,
shortestFlag,
ffmpegExperimental,
preserveMovData,
preserveMetadata,
preserveMetadataOnMerge,
preserveMovData,
preserveChapters,
movFastStart,
avoidNegativeTs,
customTagsByFile,
@ -1134,7 +1130,7 @@ function App() {
setWorking(undefined);
setProgress(undefined);
}
}, [filePath, numStreamsToCopy, segmentsToExport, haveInvalidSegs, workingRef, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMovData, preserveMetadataOnMerge, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, detectedFps, willMerge, enableOverwriteOutput, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, mergedFileTemplateOrDefault, segmentsToChapters, invertCutSegments, generateMergedFileNames, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, showOsNotification, handleExportFailed]);
}, [filePath, numStreamsToCopy, segmentsToExport, haveInvalidSegs, workingRef, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMetadataOnMerge, preserveMovData, preserveChapters, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, detectedFps, willMerge, enableOverwriteOutput, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, mergedFileTemplateOrDefault, segmentsToChapters, invertCutSegments, generateMergedFileNames, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, showOsNotification, handleExportFailed]);
const onExportPress = useCallback(async () => {
if (!filePath) return;

View File

@ -9,8 +9,6 @@ import type { SweetAlertIcon } from 'sweetalert2';
import ExportButton from './ExportButton';
import ExportModeButton from './ExportModeButton';
import PreserveMovDataButton from './PreserveMovDataButton';
import MovFastStartButton from './MovFastStartButton';
import ToggleExportConfirm from './ToggleExportConfirm';
import FileNameTemplateEditor from './FileNameTemplateEditor';
import HighlightedText, { highlightedTextStyle } from './HighlightedText';
@ -26,7 +24,7 @@ import styles from './ExportConfirm.module.css';
import { InverseCutSegment, SegmentToExport } from '../types';
import { defaultMergedFileTemplate, defaultOutSegTemplate, GenerateOutFileNames } from '../util/outputNameTemplate';
import { FFprobeStream } from '../../../../ffprobe';
import { AvoidNegativeTs } from '../../../../types';
import { AvoidNegativeTs, PreserveMetadata } from '../../../../types';
import TextInput from './TextInput';
@ -95,7 +93,13 @@ function ExportConfirm({
}) {
const { t } = useTranslation();
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, movFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, toggleSegmentsToChapters, preserveMetadataOnMerge, togglePreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental, cutFromAdjustmentFrames, setCutFromAdjustmentFrames } = useUserSettings();
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, setPreserveMovData, preserveMetadata, setPreserveMetadata, preserveChapters, setPreserveChapters, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental, cutFromAdjustmentFrames, setCutFromAdjustmentFrames } = useUserSettings();
const togglePreserveChapters = useCallback(() => setPreserveChapters((val) => !val), [setPreserveChapters]);
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), [setPreserveMovData]);
const toggleMovFastStart = useCallback(() => setMovFastStart((val) => !val), [setMovFastStart]);
const toggleSegmentsToChapters = useCallback(() => setSegmentsToChapters((v) => !v), [setSegmentsToChapters]);
const togglePreserveMetadataOnMerge = useCallback(() => setPreserveMetadataOnMerge((v) => !v), [setPreserveMetadataOnMerge]);
const isMov = ffmpegIsMov(outFormat);
const isIpod = outFormat === 'ipod';
@ -120,10 +124,18 @@ function ExportConfirm({
const showHelpText = useCallback(({ icon = 'info', timer = 10000, text }: { icon?: SweetAlertIcon, timer?: number, text: string }) => toast.fire({ icon, timer, text }), []);
const onPreserveChaptersPress = useCallback(() => {
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Whether to preserve chapters from source file.') });
}, []);
const onPreserveMovDataHelpPress = useCallback(() => {
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Preserve all MOV/MP4 metadata tags (e.g. EXIF, GPS position etc.) from source file? Note that some players have trouble playing back files where all metadata is preserved, like iTunes and other Apple software') });
}, []);
const onPreserveMetadataHelpPress = useCallback(() => {
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Whether to preserve metadata from source file. Default: Global (file metadata), per-track and per-chapter metadata will be copied. Non-global: Only per-track and per-chapter metadata will be copied. None: No metadata will be copied') });
}, []);
const onMovFastStartHelpPress = useCallback(() => {
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Enabling this will allow faster playback of the exported file. This makes processing use 3 times as much export I/O, which is negligible for small files but might slow down exporting of large files.') });
}, []);
@ -354,7 +366,7 @@ function ExportConfirm({
{t('Enable MOV Faststart?')}
</td>
<td>
<MovFastStartButton />
<Switch checked={movFastStart} onCheckedChange={toggleMovFastStart} />
{isIpod && !movFastStart && <div style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</div>}
</td>
<td>
@ -366,13 +378,41 @@ function ExportConfirm({
</td>
</tr>
<tr>
<td>
{t('Preserve chapters')}
</td>
<td>
<Switch checked={preserveChapters} onCheckedChange={togglePreserveChapters} />
</td>
<td>
<HelpIcon onClick={onPreserveChaptersPress} />
</td>
</tr>
<tr>
<td>
{t('Preserve metadata')}
</td>
<td>
<Select value={preserveMetadata} onChange={(e) => setPreserveMetadata(e.target.value as PreserveMetadata)} style={{ height: 20, marginLeft: 5 }}>
<option value={'default' as PreserveMetadata}>{t('Default')}</option>
<option value={'none' satisfies PreserveMetadata}>{t('None')}</option>
<option value={'nonglobal' satisfies PreserveMetadata}>{t('Non-global')}</option>
</Select>
</td>
<td>
<HelpIcon onClick={onPreserveMetadataHelpPress} />
</td>
</tr>
<tr>
<td>
{t('Preserve all MP4/MOV metadata?')}
{isIpod && preserveMovData && <div style={warningStyle}>{t('For the ipod format, it is recommended to deactivate this option')}</div>}
</td>
<td>
<PreserveMovDataButton />
<Switch checked={preserveMovData} onCheckedChange={togglePreserveMovData} />
</td>
<td>
{isIpod && preserveMovData ? (

View File

@ -1,15 +0,0 @@
import { memo } from 'react';
import useUserSettings from '../hooks/useUserSettings';
import Switch from './Switch';
function MovFastStartButton() {
const { movFastStart, toggleMovFastStart } = useUserSettings();
return (
<Switch checked={movFastStart} onCheckedChange={toggleMovFastStart} />
);
}
export default memo(MovFastStartButton);

View File

@ -1,15 +0,0 @@
import { memo } from 'react';
import useUserSettings from '../hooks/useUserSettings';
import Switch from './Switch';
function PreserveMovDataButton() {
const { preserveMovData, togglePreserveMovData } = useUserSettings();
return (
<Switch checked={preserveMovData} onCheckedChange={togglePreserveMovData} />
);
}
export default memo(PreserveMovDataButton);

View File

@ -4,15 +4,12 @@ import Color from 'color';
import useUserSettingsRoot from './hooks/useUserSettingsRoot';
import { ExportMode, SegmentColorIndex } from './types';
export type UserSettingsContextType = ReturnType<typeof useUserSettingsRoot> & {
toggleCaptureFormat: () => void,
changeOutDir: () => Promise<void>,
toggleKeyframeCut: (showMessage?: boolean) => void,
togglePreserveMovData: () => void,
toggleMovFastStart: () => void,
toggleExportConfirmEnabled: () => void,
toggleSegmentsToChapters: () => void,
togglePreserveMetadataOnMerge: () => void,
toggleSimpleMode: () => void,
toggleSafeOutputFileName: () => void,
effectiveExportMode: ExportMode,

View File

@ -10,7 +10,7 @@ import { getMapStreamsArgs, getStreamIdsToCopy } from '../util/streams';
import { getSmartCutParams } from '../smartcut';
import { isDurationValid } from '../segments';
import { FFprobeStream } from '../../../../ffprobe';
import { AvoidNegativeTs, Html5ifyMode } from '../../../../types';
import { AvoidNegativeTs, Html5ifyMode, PreserveMetadata } from '../../../../types';
import { AllFilesMeta, Chapter, CopyfileStreams, CustomTagsByFile, ParamsByStreamId, SegmentToExport } from '../types';
const { join, resolve, dirname } = window.require('path');
@ -233,14 +233,14 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
const losslessCutSingle = useCallback(async ({
keyframeCut: ssBeforeInput, avoidNegativeTs, copyFileStreams, cutFrom, cutTo, chaptersPath, onProgress, outPath,
videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, detectedFps,
videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, detectedFps,
}: {
keyframeCut: boolean,
avoidNegativeTs: AvoidNegativeTs | undefined,
copyFileStreams: CopyfileStreams,
cutFrom: number,
cutTo: number,
chaptersPath?: string | undefined,
chaptersPath: string | undefined,
onProgress: (p: number) => void,
outPath: string,
videoDuration: number | undefined,
@ -249,7 +249,9 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
outFormat: string,
shortestFlag: boolean,
ffmpegExperimental: boolean,
preserveMetadata: PreserveMetadata,
preserveMovData: boolean,
preserveChapters: boolean,
movFastStart: boolean,
customTagsByFile: CustomTagsByFile,
paramsByStreamId: ParamsByStreamId,
@ -360,6 +362,19 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
return ret;
})();
function getPreserveMetadata() {
if (preserveMetadata === 'default') return ['-map_metadata', '0']; // todo isn't this ffmpeg default and can be omitted? https://stackoverflow.com/a/67508734/6519037
if (preserveMetadata === 'none') return ['-map_metadata', '-1'];
if (preserveMetadata === 'nonglobal') return ['-map_metadata:g', '-1']; // https://superuser.com/a/1546267/658247
return [];
}
function getPreserveChapters() {
if (chaptersPath) return ['-map_chapters', String(chaptersInputIndex)];
if (!preserveChapters) return ['-map_chapters', '-1']; // https://github.com/mifi/lossless-cut/issues/2176
return []; // default: includes chapters from input
}
const ffmpegArgs = [
'-hide_banner',
// No progress if we set loglevel warning :(
@ -371,9 +386,9 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
...mapStreamsArgs,
'-map_metadata', '0',
...getPreserveMetadata(),
...(chaptersPath ? ['-map_chapters', String(chaptersInputIndex)] : []),
...getPreserveChapters(),
...(shortestFlag ? ['-shortest'] : []),
@ -404,7 +419,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
}, [appendFfmpegCommandLog, cutFromAdjustmentFrames, filePath, getOutputPlaybackRateArgs, shouldSkipExistingFile, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart]);
const cutMultiple = useCallback(async ({
outputDir, customOutDir, segments, outSegFileNames, videoDuration, rotation, detectedFps, onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, chapters, preserveMetadataOnMerge,
outputDir, customOutDir, segments, outSegFileNames, videoDuration, rotation, detectedFps, onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMetadataOnMerge, preserveMovData, preserveChapters, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, chapters,
}: {
outputDir: string,
customOutDir: string | undefined,
@ -420,13 +435,15 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
outFormat: string | undefined,
shortestFlag: boolean,
ffmpegExperimental: boolean,
preserveMetadata: PreserveMetadata,
preserveMovData: boolean,
preserveMetadataOnMerge: boolean,
preserveChapters: boolean,
movFastStart: boolean,
avoidNegativeTs: AvoidNegativeTs | undefined,
customTagsByFile: CustomTagsByFile,
paramsByStreamId: ParamsByStreamId,
chapters: Chapter[] | undefined,
preserveMetadataOnMerge,
}) => {
console.log('customTagsByFile', customTagsByFile);
console.log('paramsByStreamId', paramsByStreamId);
@ -456,7 +473,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
const outPath = await makeSegmentOutPath();
invariant(outFormat != null);
await losslessCutSingle({
cutFrom: desiredCutFrom, cutTo, chaptersPath, outPath, copyFileStreams, keyframeCut, avoidNegativeTs, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, onProgress: (progress) => onSingleProgress(i, progress),
cutFrom: desiredCutFrom, cutTo, chaptersPath, outPath, copyFileStreams, keyframeCut, avoidNegativeTs, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, onProgress: (progress) => onSingleProgress(i, progress),
});
return outPath;
}
@ -519,7 +536,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
// for smart cut we need to use keyframe cut here, and no avoid_negative_ts
await losslessCutSingle({
cutFrom: losslessCutFrom, cutTo, chaptersPath, outPath: losslessPartOutPath, copyFileStreams: copyFileStreamsFiltered, keyframeCut: true, avoidNegativeTs: undefined, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, onProgress,
cutFrom: losslessCutFrom, cutTo, chaptersPath, outPath: losslessPartOutPath, copyFileStreams: copyFileStreamsFiltered, keyframeCut: true, avoidNegativeTs: undefined, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, onProgress,
});
// OK, just return the single cut file (we may need smart cut in other segments though)

View File

@ -47,8 +47,14 @@ export default () => {
useEffect(() => safeSetConfig({ customOutDir }), [customOutDir]);
const [keyframeCut, setKeyframeCut] = useState(safeGetConfigInitial('keyframeCut'));
useEffect(() => safeSetConfig({ keyframeCut }), [keyframeCut]);
const [preserveMetadata, setPreserveMetadata] = useState(safeGetConfigInitial('preserveMetadata'));
useEffect(() => safeSetConfig({ preserveMetadata }), [preserveMetadata]);
const [preserveMetadataOnMerge, setPreserveMetadataOnMerge] = useState(safeGetConfigInitial('preserveMetadataOnMerge'));
useEffect(() => safeSetConfig({ preserveMetadataOnMerge }), [preserveMetadataOnMerge]);
const [preserveMovData, setPreserveMovData] = useState(safeGetConfigInitial('preserveMovData'));
useEffect(() => safeSetConfig({ preserveMovData }), [preserveMovData]);
const [preserveChapters, setPreserveChapters] = useState(safeGetConfigInitial('preserveChapters'));
useEffect(() => safeSetConfig({ preserveChapters }), [preserveChapters]);
const [movFastStart, setMovFastStart] = useState(safeGetConfigInitial('movFastStart'));
useEffect(() => safeSetConfig({ movFastStart }), [movFastStart]);
const [avoidNegativeTs, setAvoidNegativeTs] = useState(safeGetConfigInitial('avoidNegativeTs'));
@ -91,8 +97,6 @@ export default () => {
useEffect(() => safeSetConfig({ exportConfirmEnabled }), [exportConfirmEnabled]);
const [segmentsToChapters, setSegmentsToChapters] = useState(safeGetConfigInitial('segmentsToChapters'));
useEffect(() => safeSetConfig({ segmentsToChapters }), [segmentsToChapters]);
const [preserveMetadataOnMerge, setPreserveMetadataOnMerge] = useState(safeGetConfigInitial('preserveMetadataOnMerge'));
useEffect(() => safeSetConfig({ preserveMetadataOnMerge }), [preserveMetadataOnMerge]);
const [simpleMode, setSimpleMode] = useState(safeGetConfigInitial('simpleMode'));
useEffect(() => safeSetConfig({ simpleMode }), [simpleMode]);
const [outSegTemplate, setOutSegTemplate] = useState(safeGetConfigInitial('outSegTemplate'));
@ -180,8 +184,14 @@ export default () => {
setCustomOutDir,
keyframeCut,
setKeyframeCut,
preserveMetadata,
setPreserveMetadata,
preserveMetadataOnMerge,
setPreserveMetadataOnMerge,
preserveMovData,
setPreserveMovData,
preserveChapters,
setPreserveChapters,
movFastStart,
setMovFastStart,
avoidNegativeTs,
@ -224,8 +234,6 @@ export default () => {
setExportConfirmEnabled,
segmentsToChapters,
setSegmentsToChapters,
preserveMetadataOnMerge,
setPreserveMetadataOnMerge,
simpleMode,
setSimpleMode,
outSegTemplate,

View File

@ -44,6 +44,8 @@ export type AvoidNegativeTs = 'make_zero' | 'auto' | 'make_non_negative' | 'disa
export type ModifierKey = 'ctrl' | 'shift' | 'alt' | 'meta';
export type PreserveMetadata = 'default' | 'nonglobal' | 'none'
export interface Config {
captureFormat: CaptureFormat,
@ -65,6 +67,9 @@ export interface Config {
wheelSensitivity: number,
language: LanguageKey | undefined,
ffmpegExperimental: boolean,
preserveChapters: boolean,
preserveMetadata: PreserveMetadata,
preserveMetadataOnMerge: boolean,
preserveMovData: boolean,
movFastStart: boolean,
avoidNegativeTs: AvoidNegativeTs,
@ -72,7 +77,6 @@ export interface Config {
hideOsNotifications: 'all' | undefined,
autoLoadTimecode: boolean,
segmentsToChapters: boolean,
preserveMetadataOnMerge: boolean,
simpleMode: boolean,
outSegTemplate: string | undefined,
mergedFileTemplate: string | undefined,