diff --git a/src/App.jsx b/src/App.jsx index 3c13741f..43e915a3 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -712,15 +712,6 @@ const App = memo(() => { return { cancel: false, newCustomOutDir }; }, [customOutDir, setCustomOutDir]); - const concatCurrentBatch = useCallback(() => { - if (batchFiles.length < 2) { - errorToast(i18n.t('Please open at least 2 files to merge, then try again')); - return; - } - - setConcatDialogVisible(true); - }, [batchFiles]); - const toggleCaptureFormat = useCallback(() => setCaptureFormat(f => (f === 'png' ? 'jpeg' : 'png')), [setCaptureFormat]); const toggleKeyframeCut = useCallback((showMessage) => setKeyframeCut((val) => { @@ -1895,6 +1886,119 @@ const App = memo(() => { } }, [addFileAsCoverArt, captureFormat, customOutDir, enableTransferTimestamps, filePath, getCurrentTime, hideAllNotifications]); + const batchLoadPaths = useCallback((newPaths, append) => { + setBatchFiles((existingFiles) => { + const mapPathsToFiles = (paths) => paths.map((path) => ({ path, name: basename(path) })); + if (append) { + const newUniquePaths = newPaths.filter((newPath) => !existingFiles.some(({ path: existingPath }) => newPath === existingPath)); + setSelectedBatchFiles([newUniquePaths[0]]); + return [...existingFiles, ...mapPathsToFiles(newUniquePaths)]; + } + setSelectedBatchFiles([newPaths[0]]); + return mapPathsToFiles(newPaths); + }); + }, []); + + const userOpenFiles = useCallback(async (filePaths) => { + if (!filePaths || filePaths.length < 1) return; + + console.log('userOpenFiles'); + console.log(filePaths.join('\n')); + + [lastOpenedPath] = filePaths; + + if (filePaths.length > 1) { + if (alwaysConcatMultipleFiles) { + batchLoadPaths(filePaths); + setConcatDialogVisible(true); + } else { + batchLoadPaths(filePaths, true); + } + return; + } + + // filePaths.length is now 1 + const firstFilePath = filePaths[0]; + + const filePathLowerCase = firstFilePath.toLowerCase(); + + if (workingRef.current) return; + try { + setWorking(i18n.t('Loading file')); + + // Import segments for for already opened file + const edlFormats = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' }; + const matchingExt = Object.keys(edlFormats).find((ext) => filePathLowerCase.endsWith(`.${ext}`)); + if (matchingExt) { + if (!checkFileOpened()) return; + await loadEdlFile({ path: firstFilePath, type: edlFormats[matchingExt], append: true }); + return; + } + + const isLlcProject = filePathLowerCase.endsWith('.llc'); + + // Need to ask the user what to do if more than one option + const inputOptions = { + open: isFileOpened ? i18n.t('Open the file instead of the current one') : i18n.t('Open the file'), + }; + if (isFileOpened) { + if (isLlcProject) inputOptions.project = i18n.t('Load segments from the new file, but keep the current media'); + else inputOptions.tracks = i18n.t('Include all tracks from the new file'); + } + if (batchFiles.length > 0) inputOptions.addToBatch = i18n.t('Add the file to the batch list'); + + if (Object.keys(inputOptions).length > 1) { + const openFileResponse = enableAskForFileOpenAction ? await askForFileOpenAction(inputOptions) : 'open'; + + if (openFileResponse === 'open') { + await userOpenSingleFile({ path: firstFilePath, isLlcProject }); + return; + } + if (openFileResponse === 'project') { + await loadEdlFile({ path: firstFilePath, type: 'llc' }); + return; + } + if (openFileResponse === 'tracks') { + await addStreamSourceFile(firstFilePath); + setStreamsSelectorShown(true); + return; + } + if (openFileResponse === 'addToBatch') { + batchLoadPaths([firstFilePath], true); + return; + } + // Dialog canceled: + return; + } + + await userOpenSingleFile({ path: firstFilePath, isLlcProject }); + } catch (err) { + console.error('userOpenFiles', err); + if (err.code === 'LLC_FFPROBE_UNSUPPORTED_FILE') { + errorToast(i18n.t('Unsupported file')); + } else { + handleError(i18n.t('Failed to open file'), err); + } + } finally { + setWorking(); + } + }, [alwaysConcatMultipleFiles, batchLoadPaths, setWorking, batchFiles.length, isFileOpened, userOpenSingleFile, checkFileOpened, loadEdlFile, enableAskForFileOpenAction, addStreamSourceFile]); + + const openFilesDialog = useCallback(async () => { + const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'], defaultPath: lastOpenedPath }); + if (canceled) return; + userOpenFiles(filePaths); + }, [userOpenFiles]); + + const concatCurrentBatch = useCallback(() => { + if (batchFiles.length < 2) { + openFilesDialog(); + return; + } + + setConcatDialogVisible(true); + }, [batchFiles.length, openFilesDialog]); + const onKeyPress = useCallback(({ action, keyup }) => { function seekReset() { seekAccelerationRef.current = 1; @@ -2067,104 +2171,6 @@ const App = memo(() => { const batchFilePaths = useMemo(() => batchFiles.map((f) => f.path), [batchFiles]); - const batchLoadPaths = useCallback((newPaths, append) => { - setBatchFiles((existingFiles) => { - const mapPathsToFiles = (paths) => paths.map((path) => ({ path, name: basename(path) })); - if (append) { - const newUniquePaths = newPaths.filter((newPath) => !existingFiles.some(({ path: existingPath }) => newPath === existingPath)); - setSelectedBatchFiles([newUniquePaths[0]]); - return [...existingFiles, ...mapPathsToFiles(newUniquePaths)]; - } - setSelectedBatchFiles([newPaths[0]]); - return mapPathsToFiles(newPaths); - }); - }, []); - - const userOpenFiles = useCallback(async (filePaths) => { - if (!filePaths || filePaths.length < 1) return; - - console.log('userOpenFiles'); - console.log(filePaths.join('\n')); - - [lastOpenedPath] = filePaths; - - if (filePaths.length > 1) { - if (alwaysConcatMultipleFiles) { - batchLoadPaths(filePaths); - setConcatDialogVisible(true); - } else { - batchLoadPaths(filePaths, true); - } - return; - } - - // filePaths.length is now 1 - const firstFilePath = filePaths[0]; - - const filePathLowerCase = firstFilePath.toLowerCase(); - - if (workingRef.current) return; - try { - setWorking(i18n.t('Loading file')); - - // Import segments for for already opened file - const edlFormats = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' }; - const matchingExt = Object.keys(edlFormats).find((ext) => filePathLowerCase.endsWith(`.${ext}`)); - if (matchingExt) { - if (!checkFileOpened()) return; - await loadEdlFile({ path: firstFilePath, type: edlFormats[matchingExt], append: true }); - return; - } - - const isLlcProject = filePathLowerCase.endsWith('.llc'); - - // Need to ask the user what to do if more than one option - const inputOptions = { - open: isFileOpened ? i18n.t('Open the file instead of the current one') : i18n.t('Open the file'), - }; - if (isFileOpened) { - if (isLlcProject) inputOptions.project = i18n.t('Load segments from the new file, but keep the current media'); - else inputOptions.tracks = i18n.t('Include all tracks from the new file'); - } - if (batchFiles.length > 0) inputOptions.addToBatch = i18n.t('Add the file to the batch list'); - - if (Object.keys(inputOptions).length > 1) { - const openFileResponse = enableAskForFileOpenAction ? await askForFileOpenAction(inputOptions) : 'open'; - - if (openFileResponse === 'open') { - await userOpenSingleFile({ path: firstFilePath, isLlcProject }); - return; - } - if (openFileResponse === 'project') { - await loadEdlFile({ path: firstFilePath, type: 'llc' }); - return; - } - if (openFileResponse === 'tracks') { - await addStreamSourceFile(firstFilePath); - setStreamsSelectorShown(true); - return; - } - if (openFileResponse === 'addToBatch') { - batchLoadPaths([firstFilePath], true); - return; - } - // Dialog canceled: - return; - } - - await userOpenSingleFile({ path: firstFilePath, isLlcProject }); - } catch (err) { - console.error('userOpenFiles', err); - if (err.code === 'LLC_FFPROBE_UNSUPPORTED_FILE') { - errorToast(i18n.t('Unsupported file')); - } else { - handleError(i18n.t('Failed to open file'), err); - } - } finally { - setWorking(); - } - }, [alwaysConcatMultipleFiles, batchLoadPaths, setWorking, batchFiles.length, isFileOpened, userOpenSingleFile, checkFileOpened, loadEdlFile, enableAskForFileOpenAction, addStreamSourceFile]); - const onVideoError = useCallback(async () => { const { error } = videoRef.current; if (!error) return; @@ -2203,12 +2209,6 @@ const App = memo(() => { } }, [fileUri, usingPreviewFile, hasVideo, hasAudio, html5ifyAndLoadWithPreferences, customOutDir, filePath, setWorking]); - const openFilesDialog = useCallback(async () => { - const { canceled, filePaths } = await dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'], defaultPath: lastOpenedPath }); - if (canceled) return; - userOpenFiles(filePaths); - }, [userOpenFiles]); - useEffect(() => { async function exportEdlFile2(e, type) { if (!checkFileOpened()) return;