From 1cd3139ff445dcb5cd7700040d8182a778e07662 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Sat, 21 Nov 2020 00:30:53 +0100 Subject: [PATCH] Implement split into fixed duration segments #469 --- public/menu.js | 6 ++++++ src/App.jsx | 11 +++++++++-- src/util.js | 41 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/public/menu.js b/public/menu.js index 28a34772..891ecf26 100644 --- a/public/menu.js +++ b/public/menu.js @@ -127,6 +127,12 @@ module.exports = (app, mainWindow, newVersion) => { mainWindow.webContents.send('createNumSegments'); }, }, + { + label: 'Create fixed duration segments', + click() { + mainWindow.webContents.send('createFixedDurationSegments'); + }, + }, ], }, ], diff --git a/src/App.jsx b/src/App.jsx index d7d47f04..5961a828 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -48,7 +48,7 @@ import { getOutPath, formatDuration, toast, errorToast, showFfmpegFail, setFileNameTitle, promptTimeOffset, generateColor, getOutDir, withBlur, checkDirWriteAccess, dirExists, askForOutDir, openDirToast, askForHtml5ifySpeed, askForYouTubeInput, isMasBuild, isStoreBuild, askForFileOpenAction, - askForImportChapters, createNumSegments, + askForImportChapters, createNumSegments, createFixedDurationSegments, } from './util'; import { openSendReportDialog } from './reporting'; import { fallbackLng } from './i18n'; @@ -1631,6 +1631,12 @@ const App = memo(() => { if (segments) loadCutSegments(segments); } + async function createFixedDurationSegments2() { + if (!checkFileOpened()) return; + const segments = await createFixedDurationSegments(duration); + if (segments) loadCutSegments(segments); + } + electron.ipcRenderer.on('file-opened', fileOpened); electron.ipcRenderer.on('close-file', closeFile); electron.ipcRenderer.on('html5ify', html5ifyCurrentFile); @@ -1647,6 +1653,7 @@ const App = memo(() => { electron.ipcRenderer.on('batchConvertFriendlyFormat', batchConvertFriendlyFormat); electron.ipcRenderer.on('openSendReportDialog', openSendReportDialog2); electron.ipcRenderer.on('createNumSegments', createNumSegments2); + electron.ipcRenderer.on('createFixedDurationSegments', createFixedDurationSegments2); return () => { electron.ipcRenderer.removeListener('file-opened', fileOpened); @@ -1664,7 +1671,7 @@ const App = memo(() => { electron.ipcRenderer.removeListener('openAbout', openAbout); electron.ipcRenderer.removeListener('batchConvertFriendlyFormat', batchConvertFriendlyFormat); electron.ipcRenderer.removeListener('openSendReportDialog', openSendReportDialog2); - electron.ipcRenderer.removeListener('createNumSegments', createNumSegments2); + electron.ipcRenderer.removeListener('createFixedDurationSegments', createFixedDurationSegments2); }; }, [ mergeFiles, outputDir, filePath, isFileOpened, customOutDir, startTimeOffset, html5ifyCurrentFile, diff --git a/src/util.js b/src/util.js index d69f7b7d..58eb23d5 100644 --- a/src/util.js +++ b/src/util.js @@ -263,9 +263,9 @@ export async function askForImportChapters() { return value; } -async function askForNumSegments() { - const maxSegments = 1000; +const maxSegments = 300; +async function askForNumSegments() { const { value } = await Swal.fire({ input: 'number', inputAttributes: { @@ -277,9 +277,7 @@ async function askForNumSegments() { text: i18n.t('Divide timeline into a number of equal length segments'), inputValidator: (v) => { const parsed = parseInt(v, 10); - if (!Number.isNaN(parsed) && parsed >= 2 && parsed <= maxSegments) { - return undefined; - } + if (!Number.isNaN(parsed) && parsed >= 2 && parsed <= maxSegments) return undefined; return i18n.t('Please input a valid number of segments'); }, }); @@ -299,3 +297,36 @@ export async function createNumSegments(fileDuration) { } return edl; } + +async function askForSegmentDuration(fileDuration) { + const example = '00:00:05.123'; + const { value } = await Swal.fire({ + input: 'text', + showCancelButton: true, + inputValue: '00:00:00.000', + text: i18n.t('Divide timeline into a number of segments with the specified length'), + inputValidator: (v) => { + const duration = parseDuration(v); + if (duration != null) { + 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 }); + }, + }); + + if (value == null) return undefined; + + return parseDuration(value); +} + +export async function createFixedDurationSegments(fileDuration) { + const segmentDuration = await askForSegmentDuration(fileDuration); + if (segmentDuration == null) return undefined; + const edl = []; + for (let start = 0; start < fileDuration; start += segmentDuration) { + const end = start + segmentDuration; + edl.push({ start, end: end >= fileDuration ? undefined : end }); + } + return edl; +}