1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-25 11:43:17 +01:00

don't error if skipping overwrite existing file

closes #1655
This commit is contained in:
Mikael Finstad 2023-07-26 11:33:16 +02:00
parent 37afd7daf6
commit 3b53051e3d
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
2 changed files with 22 additions and 23 deletions

View File

@ -716,7 +716,7 @@ const App = memo(() => {
const {
concatFiles, html5ifyDummy, cutMultiple, autoConcatCutSegments, html5ify, fixInvalidDuration,
} = useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut });
} = useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut, enableOverwriteOutput });
const html5ifyAndLoad = useCallback(async (cod, fp, speed, hv, ha) => {
const usesDummyVideo = ['fastest-audio', 'fastest-audio-remux', 'fastest'].includes(speed);
@ -1130,7 +1130,6 @@ const App = memo(() => {
dispositionByStreamId,
chapters: chaptersToAdd,
detectedFps,
enableOverwriteOutput,
});
let concatOutPath;
@ -1159,6 +1158,8 @@ const App = memo(() => {
const notices = [];
const warnings = [];
if (!enableOverwriteOutput) warnings.push(i18n.t('Overwrite output setting is disabled and some files might have been skipped.'));
if (!exportConfirmEnabled) notices.push(i18n.t('Export options are not shown. You can enable export options by clicking the icon right next to the export button.'));
// https://github.com/mifi/lossless-cut/issues/329
@ -1190,10 +1191,6 @@ const App = memo(() => {
// assume execa killed (aborted by user)
return;
}
if (err instanceof RefuseOverwriteError) {
showRefuseToOverwrite();
return;
}
console.error('stdout:', err.stdout);
console.error('stderr:', err.stderr);

View File

@ -4,7 +4,7 @@ import sum from 'lodash/sum';
import pMap from 'p-map';
import { getSuffixedOutPath, transferTimestamps, getOutFileExtension, getOutDir, deleteDispositionValue, getHtml5ifiedPath } from '../util';
import { isCuttingStart, isCuttingEnd, runFfmpegWithProgress, getFfCommandLine, getDuration, createChaptersFromSegments, readFileMeta, cutEncodeSmartPart, getExperimentalArgs, html5ify as ffmpegHtml5ify, getVideoTimescaleArgs, RefuseOverwriteError, logStdoutStderr, runFfmpegConcat } from '../ffmpeg';
import { isCuttingStart, isCuttingEnd, runFfmpegWithProgress, getFfCommandLine, getDuration, createChaptersFromSegments, readFileMeta, cutEncodeSmartPart, getExperimentalArgs, html5ify as ffmpegHtml5ify, getVideoTimescaleArgs, logStdoutStderr, runFfmpegConcat } from '../ffmpeg';
import { getMapStreamsArgs, getStreamIdsToCopy } from '../util/streams';
import { getSmartCutParams } from '../smartcut';
@ -55,12 +55,20 @@ const tryDeleteFiles = async (paths) => pMap(paths, (path) => {
unlink(path).catch((err) => console.error('Failed to delete', path, err));
}, { concurrency: 5 });
function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut }) {
function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut, enableOverwriteOutput }) {
const optionalTransferTimestamps = useCallback(async (...args) => {
if (enableTransferTimestamps) await transferTimestamps(...args);
}, [enableTransferTimestamps]);
const shouldSkipExistingFile = useCallback(async (path) => {
const skip = !enableOverwriteOutput && await pathExists(path);
if (skip) console.log('Not overwriting existing file', path);
return skip;
}, [enableOverwriteOutput]);
const concatFiles = useCallback(async ({ paths, outDir, outPath, metadataFromPath, includeAllStreams, streams, outFormat, ffmpegExperimental, onProgress = () => {}, preserveMovData, movFastStart, chapters, preserveMetadataOnMerge, videoTimebase, appendFfmpegCommandLog }) => {
if (await shouldSkipExistingFile(outPath)) return { haveExcludedStreams: false };
console.log('Merging files', { paths }, 'to', outPath);
const durations = await pMap(paths, getDuration, { concurrency: 1 });
@ -163,12 +171,14 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
} finally {
if (chaptersPath) await tryDeleteFiles([chaptersPath]);
}
}, [optionalTransferTimestamps]);
}, [optionalTransferTimestamps, shouldSkipExistingFile]);
const cutSingle = useCallback(async ({
keyframeCut: ssBeforeInput, avoidNegativeTs, copyFileStreams, cutFrom, cutTo, chaptersPath, onProgress, outPath,
videoDuration, rotation, allFilesMeta, outFormat, appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, customTagsByStreamId, dispositionByStreamId, videoTimebase,
}) => {
if (await shouldSkipExistingFile(outPath)) return;
const cuttingStart = isCuttingStart(cutFrom);
const cuttingEnd = isCuttingEnd(cutTo, videoDuration);
console.log('Cutting from', cuttingStart ? cutFrom : 'start', 'to', cuttingEnd ? cutTo : 'end');
@ -310,14 +320,13 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
logStdoutStderr(result);
await optionalTransferTimestamps(filePath, outPath, cutFrom);
}, [filePath, optionalTransferTimestamps]);
}, [filePath, optionalTransferTimestamps, shouldSkipExistingFile]);
const cutMultiple = useCallback(async ({
outputDir, customOutDir, segments, outSegFileNames, videoDuration, rotation, detectedFps,
onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat,
appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, avoidNegativeTs,
customTagsByFile, customTagsByStreamId, dispositionByStreamId, chapters, preserveMetadataOnMerge,
enableOverwriteOutput,
}) => {
console.log('customTagsByFile', customTagsByFile);
console.log('customTagsByStreamId', customTagsByStreamId);
@ -330,11 +339,6 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
const chaptersPath = await writeChaptersFfmetadata(outputDir, chapters);
async function checkOverwrite(path) {
if (!enableOverwriteOutput && await pathExists(path)) throw new RefuseOverwriteError();
}
// This function will either call cutSingle (if no smart cut enabled)
// or if enabled, will first cut&encode the part before the next keyframe, trying to match the input file's codec params
// then it will cut the part *from* the keyframe to "end", and concat them together and return the concated file
@ -351,7 +355,6 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
if (!needSmartCut) {
// old fashioned way
const outPath = await makeSegmentOutPath();
await checkOverwrite(outPath);
await cutSingle({
cutFrom: desiredCutFrom, cutTo, chaptersPath, outPath, copyFileStreams, keyframeCut, avoidNegativeTs, videoDuration, rotation, allFilesMeta, outFormat, appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, customTagsByStreamId, dispositionByStreamId, onProgress: (progress) => onSingleProgress(i, progress),
});
@ -379,13 +382,15 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
}];
// eslint-disable-next-line no-shadow
const cutEncodeSmartPartWrapper = async ({ cutFrom, cutTo, outPath }) => cutEncodeSmartPart({ filePath, cutFrom, cutTo, outPath, outFormat, videoCodec, videoBitrate, videoStreamIndex, videoTimebase, allFilesMeta, copyFileStreams: copyFileStreamsFiltered, ffmpegExperimental });
async function cutEncodeSmartPartWrapper({ cutFrom, cutTo, outPath }) {
if (await shouldSkipExistingFile(outPath)) return;
await cutEncodeSmartPart({ filePath, cutFrom, cutTo, outPath, outFormat, videoCodec, videoBitrate, videoStreamIndex, videoTimebase, allFilesMeta, copyFileStreams: copyFileStreamsFiltered, ffmpegExperimental });
}
// If we are cutting within two keyframes, just encode the whole part and return that
// See https://github.com/mifi/lossless-cut/pull/1267#issuecomment-1236381740
if (segmentNeedsSmartCut && encodeCutTo > cutTo) {
const outPath = await makeSegmentOutPath();
await checkOverwrite(outPath);
await cutEncodeSmartPartWrapper({ cutFrom: desiredCutFrom, cutTo, outPath });
return outPath;
}
@ -400,8 +405,6 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
const smartCutSegmentsToConcat = [smartCutEncodedPartOutPath, smartCutMainPartOutPath];
if (!segmentNeedsSmartCut) await checkOverwrite(smartCutMainPartOutPath);
// for smart cut we need to use keyframe cut here, and no avoid_negative_ts
await cutSingle({
cutFrom: encodeCutTo, cutTo, chaptersPath, outPath: smartCutMainPartOutPath, copyFileStreams: copyFileStreamsFiltered, keyframeCut: true, avoidNegativeTs: false, videoDuration, rotation, allFilesMeta, outFormat, appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, customTagsByStreamId, dispositionByStreamId, videoTimebase, onProgress: onCutProgress,
@ -420,7 +423,6 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
const { streams: streamsAfterCut } = await readFileMeta(smartCutMainPartOutPath);
const outPath = await makeSegmentOutPath();
await checkOverwrite(outPath);
await concatFiles({ paths: smartCutSegmentsToConcat, outDir: outputDir, outPath, metadataFromPath: smartCutMainPartOutPath, outFormat, includeAllStreams: true, streams: streamsAfterCut, ffmpegExperimental, preserveMovData, movFastStart, chapters, preserveMetadataOnMerge, videoTimebase, appendFfmpegCommandLog, onProgress: onConcatProgress });
return outPath;
@ -436,7 +438,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut
} finally {
if (chaptersPath) await tryDeleteFiles([chaptersPath]);
}
}, [concatFiles, cutSingle, filePath, needSmartCut]);
}, [concatFiles, cutSingle, filePath, needSmartCut, shouldSkipExistingFile]);
const autoConcatCutSegments = useCallback(async ({ customOutDir, isCustomFormatSelected, outFormat, segmentPaths, ffmpegExperimental, onProgress, preserveMovData, movFastStart, autoDeleteMergedSegments, chapterNames, preserveMetadataOnMerge, appendFfmpegCommandLog }) => {
const ext = getOutFileExtension({ isCustomFormatSelected, outFormat, filePath });