implement shift all segments times

pull/901/head
Mikael Finstad 4 years ago
parent d9fd560993
commit 26783a1338
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -213,6 +213,12 @@ module.exports = (app, mainWindow, newVersion) => {
mainWindow.webContents.send('shuffleSegments');
},
},
{
label: i18n.t('Shift all segments on timeline'),
click() {
mainWindow.webContents.send('shiftAllSegmentTimes');
},
},
],
},
{

@ -69,7 +69,7 @@ import {
} from './util';
import { formatDuration } from './util/duration';
import { adjustRate } from './util/rate-calculator';
import { askForOutDir, askForInputDir, askForImportChapters, createNumSegments as createNumSegmentsDialog, createFixedDurationSegments as createFixedDurationSegmentsDialog, promptTimeOffset, askForHtml5ifySpeed, askForFileOpenAction, confirmExtractAllStreamsDialog, showCleanupFilesDialog, showDiskFull, showCutFailedDialog, labelSegmentDialog, openYouTubeChaptersDialog, openAbout, showEditableJsonDialog } from './dialogs';
import { askForOutDir, askForInputDir, askForImportChapters, createNumSegments as createNumSegmentsDialog, createFixedDurationSegments as createFixedDurationSegmentsDialog, promptTimeOffset, askForHtml5ifySpeed, askForFileOpenAction, confirmExtractAllStreamsDialog, showCleanupFilesDialog, showDiskFull, showCutFailedDialog, labelSegmentDialog, openYouTubeChaptersDialog, openAbout, showEditableJsonDialog, askForShiftSegments } from './dialogs';
import { openSendReportDialog } from './reporting';
import { fallbackLng } from './i18n';
import { createSegment, getCleanCutSegments, getSegApparentStart, findSegmentsAtCursor, sortSegments, invertSegments, getSegmentTags } from './segments';
@ -405,6 +405,15 @@ const App = memo(() => {
updateSegAtIndex(currentSegIndexSafe, { [type]: Math.min(Math.max(time, 0), duration) });
}, [currentSegIndexSafe, getSegApparentEnd, currentCutSeg, duration, updateSegAtIndex]);
const shiftAllSegmentTimes = useCallback(async () => {
const shiftValue = await askForShiftSegments();
if (shiftValue == null) return;
const clampValue = (val) => Math.min(Math.max(val + shiftValue, 0), duration);
const newSegments = apparentCutSegments.map((segment) => ({ ...segment, start: clampValue(segment.start + shiftValue), end: clampValue(segment.end + shiftValue) })).filter((segment) => segment.end > segment.start);
if (newSegments.length < 1) setCutSegments(createInitialCutSegments());
else setCutSegments(newSegments);
}, [apparentCutSegments, createInitialCutSegments, duration, setCutSegments]);
const maxLabelLength = safeOutputFileName ? 100 : 500;
const onLabelSegmentPress = useCallback(async (index) => {
@ -2084,12 +2093,13 @@ const App = memo(() => {
fixInvalidDuration: tryFixInvalidDuration,
reorderSegsByStartTime,
concatCurrentBatch,
shiftAllSegmentTimes,
};
const entries = Object.entries(action);
entries.forEach(([key, value]) => electron.ipcRenderer.on(key, value));
return () => entries.forEach(([key, value]) => electron.ipcRenderer.removeListener(key, value));
}, [apparentCutSegments, askSetStartTimeOffset, checkFileOpened, clearSegments, closeBatch, closeFileWithConfirm, concatCurrentBatch, createFixedDurationSegments, createNumSegments, customOutDir, cutSegments, extractAllStreams, fileFormat, filePath, getFrameCount, getTimeFromFrameNum, invertAllCutSegments, loadCutSegments, loadMedia, openSendReportDialogWithState, reorderSegsByStartTime, setWorking, shuffleSegments, toggleHelp, toggleSettings, tryFixInvalidDuration, userHtml5ifyCurrentFile, userOpenFiles]);
}, [apparentCutSegments, askSetStartTimeOffset, checkFileOpened, clearSegments, closeBatch, closeFileWithConfirm, concatCurrentBatch, createFixedDurationSegments, createNumSegments, customOutDir, cutSegments, extractAllStreams, fileFormat, filePath, getFrameCount, getTimeFromFrameNum, invertAllCutSegments, loadCutSegments, loadMedia, openSendReportDialogWithState, reorderSegsByStartTime, setWorking, shiftAllSegmentTimes, shuffleSegments, toggleHelp, toggleSettings, tryFixInvalidDuration, userHtml5ifyCurrentFile, userOpenFiles]);
const showAddStreamSourceDialog = useCallback(async () => {
try {

@ -216,8 +216,9 @@ export async function createNumSegments(fileDuration) {
return edl;
}
const exampleDuration = '00:00:05.123';
async function askForSegmentDuration(fileDuration) {
const example = '00:00:05.123';
const { value } = await Swal.fire({
input: 'text',
showCancelButton: true,
@ -229,7 +230,7 @@ async function askForSegmentDuration(fileDuration) {
const numSegments = Math.ceil(fileDuration / duration);
if (duration > 0 && duration < fileDuration && numSegments <= maxSegments) return undefined;
}
return i18n.t('Please input a valid duration. Example: {{example}}', { example });
return i18n.t('Please input a valid duration. Example: {{example}}', { example: exampleDuration });
},
});
@ -238,6 +239,37 @@ async function askForSegmentDuration(fileDuration) {
return parseDuration(value);
}
export async function askForShiftSegments() {
function parseValue(value) {
let parseableValue = value;
let sign = 1;
if (parseableValue[0] === '-') {
parseableValue = parseableValue.substring(1);
sign = -1;
}
const duration = parseDuration(parseableValue);
if (duration != null && duration > 0) {
return duration * sign;
}
return undefined;
}
const { value } = await Swal.fire({
input: 'text',
showCancelButton: true,
inputValue: '00:00:00.000',
text: i18n.t('Shift all segments on the timeline by this amount. Negative values will be shifted back, while positive value will be shifted forward in time.'),
inputValidator: (v) => {
const parsed = parseValue(v);
if (parsed == null) return i18n.t('Please input a valid duration. Example: {{example}}', { example: exampleDuration });
return undefined;
},
});
if (value == null) return undefined;
return parseValue(value);
}
export async function askForMetadataKey() {
const { value } = await Swal.fire({
title: i18n.t('Add metadata'),

Loading…
Cancel
Save