improvements:

include segment name in output file name #251
pull/276/head
Mikael Finstad 7 years ago
parent 6b2d3e5013
commit 74abd81dcc

@ -28,6 +28,10 @@ const SegmentList = memo(({
title: 'Label current segment',
inputValue: currentCutSeg.name,
input: 'text',
inputValidator: (v) => {
const maxLength = 100;
return v.length > maxLength ? `Max length ${maxLength}` : undefined;
},
});
if (value != null) setCurrentSegmentName(value);

@ -70,7 +70,8 @@ function renderFileRow(path, formatData, onTrashClick) {
const StreamsSelector = memo(({
mainFilePath, mainFileFormatData, streams: existingStreams, isCopyingStreamId, toggleCopyStreamId,
setCopyStreamIdsForPath, onExtractAllStreamsPress, externalFiles, setExternalFiles,
showAddStreamSourceDialog, shortestFlag, setShortestFlag, exportExtraStreams,
showAddStreamSourceDialog, shortestFlag, setShortestFlag, nonCopiedExtraStreams, areWeCutting,
AutoExportToggler,
}) => {
if (!existingStreams) return null;
@ -144,8 +145,8 @@ const StreamsSelector = memo(({
</tbody>
</table>
{externalFilesEntries.length > 0 && (
<div>
{externalFilesEntries.length > 0 && !areWeCutting && (
<div style={{ margin: '10px 0' }}>
<div>
If the streams have different length, do you want to make the combined output file as long as the longest stream or the shortest stream?
</div>
@ -158,7 +159,12 @@ const StreamsSelector = memo(({
</div>
)}
{exportExtraStreams && <p>Unprocessable tracks will be extracted to separate files. This can be configured in settings.</p>}
{nonCopiedExtraStreams.length > 0 && (
<div style={{ margin: '10px 0' }}>
Discard or extract unprocessable tracks to separate files?
<AutoExportToggler />
</div>
)}
<div style={{ cursor: 'pointer', padding: '10px 0' }} role="button" onClick={showAddStreamSourceDialog}>
<FaFileImport size={30} style={{ verticalAlign: 'middle', marginRight: 5 }} /> Include more tracks from other file

@ -14,7 +14,7 @@ const trash = require('trash');
const isDev = require('electron-is-dev');
const os = require('os');
const { formatDuration, getOutPath, transferTimestamps } = require('./util');
const { formatDuration, getOutPath, transferTimestamps, filenamify } = require('./util');
function getFfCommandLine(cmd, args) {
@ -147,15 +147,17 @@ async function cut({
filePath, outFormat, cutFrom, cutTo, videoDuration, rotation,
onProgress, copyStreamIds, keyframeCut, outPath, appendFfmpegCommandLog, shortestFlag,
}) {
console.log('Cutting from', cutFrom, 'to', cutTo);
const cuttingStart = isCuttingStart(cutFrom);
const cuttingEnd = isCuttingEnd(cutTo, videoDuration);
console.log('Exporting from', cuttingStart ? cutFrom : 'start', 'to', cuttingEnd ? cutTo : 'end');
const ssBeforeInput = keyframeCut;
const cutDuration = cutTo - cutFrom;
// Don't cut if no need: https://github.com/mifi/lossless-cut/issues/50
const cutFromArgs = isCuttingStart(cutFrom) ? ['-ss', cutFrom.toFixed(5)] : [];
const cutToArgs = isCuttingEnd(cutTo, videoDuration) ? ['-t', cutDuration.toFixed(5)] : [];
const cutFromArgs = cuttingStart ? ['-ss', cutFrom.toFixed(5)] : [];
const cutToArgs = cuttingEnd ? ['-t', cutDuration.toFixed(5)] : [];
const copyStreamIdsFiltered = copyStreamIds.filter(({ streamIds }) => streamIds.length > 0);
@ -225,11 +227,14 @@ async function cutMultiple({
let i = 0;
// eslint-disable-next-line no-restricted-syntax,no-unused-vars
for (const { cutFrom, cutTo } of segments) {
for (const { start, end, name } of segments) {
const cutFromStr = formatDuration({ seconds: start, fileNameFriendly: true });
const cutToStr = formatDuration({ seconds: end, fileNameFriendly: true });
const segNamePart = name ? `-${filenamify(name)}` : '';
const cutSpecification = `${cutFromStr}-${cutToStr}${segNamePart}`.substr(0, 200);
const ext = isOutFormatUserSelected ? `.${getExtensionForFormat(outFormat)}` : extname(filePath);
const cutSpecification = `${formatDuration({ seconds: cutFrom, fileNameFriendly: true })}-${formatDuration({ seconds: cutTo, fileNameFriendly: true })}`;
const outPath = getOutPath(customOutDir, filePath, `${cutSpecification}${ext}`);
const fileName = `${cutSpecification}${ext}`;
const outPath = getOutPath(customOutDir, filePath, fileName);
// eslint-disable-next-line no-await-in-loop
await cut({
@ -241,8 +246,8 @@ async function cutMultiple({
rotation,
copyStreamIds,
keyframeCut,
cutFrom,
cutTo,
cutFrom: start,
cutTo: end,
shortestFlag,
// eslint-disable-next-line no-loop-func
onProgress: progress => onSingleProgress(i, progress),

@ -749,11 +749,6 @@ const App = memo(() => {
return;
}
const ffmpegSegments = outSegments.map((seg) => ({
cutFrom: seg.start,
cutTo: seg.end,
}));
if (outSegments.length < 1) {
errorToast('No segments to export');
return;
@ -771,7 +766,7 @@ const App = memo(() => {
rotation: effectiveRotation,
copyStreamIds,
keyframeCut,
segments: ffmpegSegments,
segments: outSegments,
onProgress: setCutProgress,
appendFfmpegCommandLog,
shortestFlag,
@ -1315,6 +1310,14 @@ const App = memo(() => {
);
}
const AutoExportToggler = () => (
<SegmentedControl
options={[{ label: 'Extract', value: 'extract' }, { label: 'Discard', value: 'discard' }]}
value={autoExportExtraStreams ? 'extract' : 'discard'}
onChange={value => setAutoExportExtraStreams(value === 'extract')}
/>
);
const renderSettings = () => {
// eslint-disable-next-line react/jsx-props-no-spreading
const Row = (props) => <Table.Row height="auto" paddingY={12} {...props} />;
@ -1388,11 +1391,7 @@ const App = memo(() => {
(data tracks such as GoPro GPS, telemetry etc. are not copied over by default because ffmpeg cannot cut them, thus they will cause the media duration to stay the same after cutting video/audio)
</KeyCell>
<Table.TextCell>
<SegmentedControl
options={[{ label: 'Extract', value: 'extract' }, { label: 'Discard', value: 'discard' }]}
value={autoExportExtraStreams ? 'extract' : 'discard'}
onChange={value => setAutoExportExtraStreams(value === 'extract')}
/>
<AutoExportToggler />
</Table.TextCell>
</Row>
@ -1576,9 +1575,11 @@ const App = memo(() => {
toggleCopyStreamId={toggleCopyStreamId}
setCopyStreamIdsForPath={setCopyStreamIdsForPath}
onExtractAllStreamsPress={onExtractAllStreamsPress}
areWeCutting={areWeCutting}
shortestFlag={shortestFlag}
setShortestFlag={setShortestFlag}
exportExtraStreams={exportExtraStreams}
nonCopiedExtraStreams={nonCopiedExtraStreams}
AutoExportToggler={AutoExportToggler}
/>
</SideSheet>
<Button height={20} iconBefore="list" onClick={withBlur(() => setStreamsSelectorShown(true))}>

@ -91,6 +91,10 @@ function setFileNameTitle(filePath) {
document.title = filePath ? `${appName} - ${path.basename(filePath)}` : appName;
}
function filenamify(name) {
return name.replace(/[^0-9a-zA-Z_.]/g, '_');
}
async function promptTimeOffset(inputValue) {
const { value } = await Swal.fire({
title: 'Set custom start time offset',

Loading…
Cancel
Save