mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 02:12:30 +01:00
improve "Resulting file names"
make it show the actual resulting file names (if error) #1732
This commit is contained in:
parent
a3cbce6190
commit
7f1fbe4953
17
src/App.jsx
17
src/App.jsx
@ -78,7 +78,7 @@ import { askForOutDir, askForImportChapters, promptTimeOffset, askForFileOpenAct
|
|||||||
import { openSendReportDialog } from './reporting';
|
import { openSendReportDialog } from './reporting';
|
||||||
import { fallbackLng } from './i18n';
|
import { fallbackLng } from './i18n';
|
||||||
import { createSegment, getCleanCutSegments, findSegmentsAtCursor, sortSegments, convertSegmentsToChapters, hasAnySegmentOverlap, isDurationValid, playOnlyCurrentSegment } from './segments';
|
import { createSegment, getCleanCutSegments, findSegmentsAtCursor, sortSegments, convertSegmentsToChapters, hasAnySegmentOverlap, isDurationValid, playOnlyCurrentSegment } from './segments';
|
||||||
import { getOutSegError as getOutSegErrorRaw, generateOutSegFileNames as generateOutSegFileNamesRaw, defaultOutSegTemplate } from './util/outputNameTemplate';
|
import { generateOutSegFileNames as generateOutSegFileNamesRaw, defaultOutSegTemplate } from './util/outputNameTemplate';
|
||||||
import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants';
|
import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './util/constants';
|
||||||
import BigWaveform from './components/BigWaveform';
|
import BigWaveform from './components/BigWaveform';
|
||||||
|
|
||||||
@ -1114,10 +1114,8 @@ const App = memo(() => {
|
|||||||
}, [cleanupFilesWithDialog, isFileOpened, setWorking]);
|
}, [cleanupFilesWithDialog, isFileOpened, setWorking]);
|
||||||
|
|
||||||
const generateOutSegFileNames = useCallback(({ segments = segmentsToExport, template, forceSafeOutputFileName }) => (
|
const generateOutSegFileNames = useCallback(({ segments = segmentsToExport, template, forceSafeOutputFileName }) => (
|
||||||
generateOutSegFileNamesRaw({ segments, template, forceSafeOutputFileName, formatTimecode, isCustomFormatSelected, fileFormat, filePath, safeOutputFileName, maxLabelLength, outputFileNameMinZeroPadding })
|
generateOutSegFileNamesRaw({ segments, template, forceSafeOutputFileName, formatTimecode, isCustomFormatSelected, fileFormat, filePath, outputDir, safeOutputFileName, maxLabelLength, outputFileNameMinZeroPadding })
|
||||||
), [fileFormat, filePath, formatTimecode, isCustomFormatSelected, maxLabelLength, outputFileNameMinZeroPadding, safeOutputFileName, segmentsToExport]);
|
), [fileFormat, filePath, formatTimecode, isCustomFormatSelected, maxLabelLength, outputDir, outputFileNameMinZeroPadding, safeOutputFileName, segmentsToExport]);
|
||||||
|
|
||||||
const getOutSegError = useCallback((fileNames) => getOutSegErrorRaw({ fileNames, filePath, outputDir, safeOutputFileName }), [filePath, outputDir, safeOutputFileName]);
|
|
||||||
|
|
||||||
const closeExportConfirm = useCallback(() => setExportConfirmVisible(false), []);
|
const closeExportConfirm = useCallback(() => setExportConfirmVisible(false), []);
|
||||||
|
|
||||||
@ -1168,10 +1166,9 @@ const App = memo(() => {
|
|||||||
|
|
||||||
console.log('outSegTemplateOrDefault', outSegTemplateOrDefault);
|
console.log('outSegTemplateOrDefault', outSegTemplateOrDefault);
|
||||||
|
|
||||||
let outSegFileNames = generateOutSegFileNames({ segments: segmentsToExport, template: outSegTemplateOrDefault });
|
const { outSegFileNames, outSegError } = generateOutSegFileNames({ segments: segmentsToExport, template: outSegTemplateOrDefault });
|
||||||
if (getOutSegError(outSegFileNames) != null) {
|
if (outSegError != null) {
|
||||||
console.warn('Output segments file name invalid, using default instead', outSegFileNames);
|
console.warn('Output segments file name invalid, using default instead', outSegFileNames);
|
||||||
outSegFileNames = generateOutSegFileNames({ segments: segmentsToExport, template: defaultOutSegTemplate, forceSafeOutputFileName: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw (() => { const err = new Error('test'); err.code = 'ENOENT'; return err; })();
|
// throw (() => { const err = new Error('test'); err.code = 'ENOENT'; return err; })();
|
||||||
@ -1276,7 +1273,7 @@ const App = memo(() => {
|
|||||||
setWorking();
|
setWorking();
|
||||||
setCutProgress();
|
setCutProgress();
|
||||||
}
|
}
|
||||||
}, [numStreamsToCopy, segmentsToExport, haveInvalidSegs, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, getOutSegError, 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, mergedOutFilePath, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, segmentsToChapters, invertCutSegments, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, filePath, handleExportFailed]);
|
}, [numStreamsToCopy, segmentsToExport, haveInvalidSegs, 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, mergedOutFilePath, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, segmentsToChapters, invertCutSegments, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, filePath, handleExportFailed]);
|
||||||
|
|
||||||
const onExportPress = useCallback(async () => {
|
const onExportPress = useCallback(async () => {
|
||||||
if (!filePath) return;
|
if (!filePath) return;
|
||||||
@ -2538,7 +2535,7 @@ const App = memo(() => {
|
|||||||
)}
|
)}
|
||||||
</Sheet>
|
</Sheet>
|
||||||
|
|
||||||
<ExportConfirm filePath={filePath} areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} onShowStreamsSelectorClick={handleShowStreamsSelectorClick} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} getOutSegError={getOutSegError} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} needSmartCut={needSmartCut} mergedOutFileName={mergedOutFileName} setMergedOutFileName={setMergedOutFileName} />
|
<ExportConfirm filePath={filePath} areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} onShowStreamsSelectorClick={handleShowStreamsSelectorClick} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} needSmartCut={needSmartCut} mergedOutFileName={mergedOutFileName} setMergedOutFileName={setMergedOutFileName} />
|
||||||
|
|
||||||
<LastCommandsSheet
|
<LastCommandsSheet
|
||||||
visible={lastCommandsVisible}
|
visible={lastCommandsVisible}
|
||||||
|
@ -36,7 +36,7 @@ const HelpIcon = ({ onClick, style }) => <IoIosHelpCircle size={20} role="button
|
|||||||
const ExportConfirm = memo(({
|
const ExportConfirm = memo(({
|
||||||
areWeCutting, selectedSegments, segmentsToExport, willMerge, visible, onClosePress, onExportConfirm,
|
areWeCutting, selectedSegments, segmentsToExport, willMerge, visible, onClosePress, onExportConfirm,
|
||||||
outFormat, renderOutFmt, outputDir, numStreamsTotal, numStreamsToCopy, onShowStreamsSelectorClick, outSegTemplate,
|
outFormat, renderOutFmt, outputDir, numStreamsTotal, numStreamsToCopy, onShowStreamsSelectorClick, outSegTemplate,
|
||||||
setOutSegTemplate, generateOutSegFileNames, filePath, currentSegIndexSafe, getOutSegError, nonFilteredSegmentsOrInverse,
|
setOutSegTemplate, generateOutSegFileNames, filePath, currentSegIndexSafe, nonFilteredSegmentsOrInverse,
|
||||||
mainCopiedThumbnailStreams, needSmartCut, mergedOutFileName, setMergedOutFileName,
|
mainCopiedThumbnailStreams, needSmartCut, mergedOutFileName, setMergedOutFileName,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -191,7 +191,7 @@ const ExportConfirm = memo(({
|
|||||||
{canEditTemplate && (
|
{canEditTemplate && (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={2}>
|
<td colSpan={2}>
|
||||||
<OutSegTemplateEditor filePath={filePath} outSegTemplate={outSegTemplate} setOutSegTemplate={setOutSegTemplate} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} getOutSegError={getOutSegError} />
|
<OutSegTemplateEditor filePath={filePath} outSegTemplate={outSegTemplate} setOutSegTemplate={setOutSegTemplate} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<HelpIcon onClick={onOutSegTemplateHelpPress} />
|
<HelpIcon onClick={onOutSegTemplateHelpPress} />
|
||||||
|
@ -42,9 +42,8 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate
|
|||||||
if (debouncedText == null) return;
|
if (debouncedText == null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newOutSegFileNames = generateOutSegFileNames({ template: debouncedText });
|
const { outSegFileNames: newOutSegFileNames, outSegError } = generateOutSegFileNames({ template: debouncedText });
|
||||||
setOutSegFileNames(newOutSegFileNames);
|
setOutSegFileNames(newOutSegFileNames);
|
||||||
const outSegError = getOutSegError(newOutSegFileNames);
|
|
||||||
if (outSegError) {
|
if (outSegError) {
|
||||||
setError(outSegError);
|
setError(outSegError);
|
||||||
setValidText();
|
setValidText();
|
||||||
|
@ -11,8 +11,7 @@ export const segSuffixVariable = 'SEG_SUFFIX';
|
|||||||
|
|
||||||
const { parse: parsePath, sep: pathSep, join: pathJoin, normalize: pathNormalize } = window.require('path');
|
const { parse: parsePath, sep: pathSep, join: pathJoin, normalize: pathNormalize } = window.require('path');
|
||||||
|
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileName }) {
|
||||||
export function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileName }) {
|
|
||||||
let error;
|
let error;
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
@ -90,49 +89,60 @@ function interpolateSegmentFileName({ template, epochMs, inputFileNameWithoutExt
|
|||||||
return compiled(data);
|
return compiled(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateOutSegFileNames({ segments, template, forceSafeOutputFileName, formatTimecode, isCustomFormatSelected, fileFormat, filePath, safeOutputFileName, maxLabelLength, outputFileNameMinZeroPadding }) {
|
export function generateOutSegFileNames({ segments, template: desiredTemplate, formatTimecode, isCustomFormatSelected, fileFormat, filePath, outputDir, safeOutputFileName, maxLabelLength, outputFileNameMinZeroPadding }) {
|
||||||
const epochMs = Date.now();
|
function generate({ template, forceSafeOutputFileName }) {
|
||||||
|
const epochMs = Date.now();
|
||||||
|
|
||||||
return segments.map((segment, i) => {
|
return segments.map((segment, i) => {
|
||||||
const { start, end, name = '' } = segment;
|
const { start, end, name = '' } = segment;
|
||||||
const segNum = formatSegNum(i, segments.length, outputFileNameMinZeroPadding);
|
const segNum = formatSegNum(i, segments.length, outputFileNameMinZeroPadding);
|
||||||
|
|
||||||
// Fields that did not come from the source file's name must be sanitized, because they may contain characters that are not supported by the target operating/file system
|
// Fields that did not come from the source file's name must be sanitized, because they may contain characters that are not supported by the target operating/file system
|
||||||
// however we disable this when the user has chosen to (safeOutputFileName === false)
|
// however we disable this when the user has chosen to (safeOutputFileName === false)
|
||||||
const filenamifyOrNot = (fileName) => (safeOutputFileName || forceSafeOutputFileName ? filenamify(fileName) : fileName).substr(0, maxLabelLength);
|
const filenamifyOrNot = (fileName) => (safeOutputFileName || forceSafeOutputFileName ? filenamify(fileName) : fileName).substr(0, maxLabelLength);
|
||||||
|
|
||||||
function getSegSuffix() {
|
function getSegSuffix() {
|
||||||
if (name) return `-${filenamifyOrNot(name)}`;
|
if (name) return `-${filenamifyOrNot(name)}`;
|
||||||
// https://github.com/mifi/lossless-cut/issues/583
|
// https://github.com/mifi/lossless-cut/issues/583
|
||||||
if (segments.length > 1) return `-seg${segNum}`;
|
if (segments.length > 1) return `-seg${segNum}`;
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name: inputFileNameWithoutExt } = parsePath(filePath);
|
const { name: inputFileNameWithoutExt } = parsePath(filePath);
|
||||||
|
|
||||||
const segFileName = interpolateSegmentFileName({
|
const segFileName = interpolateSegmentFileName({
|
||||||
template,
|
template,
|
||||||
epochMs,
|
epochMs,
|
||||||
segNum,
|
segNum,
|
||||||
inputFileNameWithoutExt,
|
inputFileNameWithoutExt,
|
||||||
segSuffix: getSegSuffix(),
|
segSuffix: getSegSuffix(),
|
||||||
ext: getOutFileExtension({ isCustomFormatSelected, outFormat: fileFormat, filePath }),
|
ext: getOutFileExtension({ isCustomFormatSelected, outFormat: fileFormat, filePath }),
|
||||||
segLabel: filenamifyOrNot(name),
|
segLabel: filenamifyOrNot(name),
|
||||||
cutFrom: formatTimecode({ seconds: start, fileNameFriendly: true }),
|
cutFrom: formatTimecode({ seconds: start, fileNameFriendly: true }),
|
||||||
cutTo: formatTimecode({ seconds: end, fileNameFriendly: true }),
|
cutTo: formatTimecode({ seconds: end, fileNameFriendly: true }),
|
||||||
tags: Object.fromEntries(Object.entries(getSegmentTags(segment)).map(([tag, value]) => [tag, filenamifyOrNot(value)])),
|
tags: Object.fromEntries(Object.entries(getSegmentTags(segment)).map(([tag, value]) => [tag, filenamifyOrNot(value)])),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now split the path by its separator, so we can check the actual file name (last path seg)
|
||||||
|
const pathSegs = segFileName.split(pathSep);
|
||||||
|
if (pathSegs.length === 0) return '';
|
||||||
|
const [lastSeg] = pathSegs.slice(-1);
|
||||||
|
const rest = pathSegs.slice(0, -1);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...rest,
|
||||||
|
// If sanitation is enabled, make sure filename (last seg of the path) is not too long
|
||||||
|
safeOutputFileName ? lastSeg.substring(0, 200) : lastSeg,
|
||||||
|
].join(pathSep);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Now split the path by its separator, so we can check the actual file name (last path seg)
|
let outSegFileNames = generate({ template: desiredTemplate, forceSafeOutputFileName: false });
|
||||||
const pathSegs = segFileName.split(pathSep);
|
|
||||||
if (pathSegs.length === 0) return '';
|
|
||||||
const [lastSeg] = pathSegs.slice(-1);
|
|
||||||
const rest = pathSegs.slice(0, -1);
|
|
||||||
|
|
||||||
return [
|
const outSegError = getOutSegError({ fileNames: outSegFileNames, filePath, outputDir, safeOutputFileName });
|
||||||
...rest,
|
if (outSegError != null) {
|
||||||
// If sanitation is enabled, make sure filename (last seg of the path) is not too long
|
outSegFileNames = generate({ template: defaultOutSegTemplate, forceSafeOutputFileName: true });
|
||||||
safeOutputFileName ? lastSeg.substring(0, 200) : lastSeg,
|
}
|
||||||
].join(pathSep);
|
|
||||||
});
|
return { outSegFileNames, outSegError };
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user