kopia lustrzana https://github.com/mifi/lossless-cut
allow opening directories recursively
rodzic
fabab12bce
commit
bc04a4f2a4
35
src/App.jsx
35
src/App.jsx
|
@ -68,7 +68,7 @@ import {
|
||||||
getOutPath, getSuffixedOutPath, handleError, getOutDir,
|
getOutPath, getSuffixedOutPath, handleError, getOutDir,
|
||||||
isStoreBuild, dragPreventer,
|
isStoreBuild, dragPreventer,
|
||||||
havePermissionToReadFile, resolvePathIfNeeded, getPathReadAccessError, html5ifiedPrefix, html5dummySuffix, findExistingHtml5FriendlyFile,
|
havePermissionToReadFile, resolvePathIfNeeded, getPathReadAccessError, html5ifiedPrefix, html5dummySuffix, findExistingHtml5FriendlyFile,
|
||||||
deleteFiles, isOutOfSpaceError, isExecaFailure, readFileSize, readFileSizes, checkFileSizes, setDocumentTitle, getOutFileExtension, getSuffixedFileName, mustDisallowVob, readVideoTs, getImportProjectType,
|
deleteFiles, isOutOfSpaceError, isExecaFailure, readFileSize, readFileSizes, checkFileSizes, setDocumentTitle, getOutFileExtension, getSuffixedFileName, mustDisallowVob, readVideoTs, readDirRecursively, getImportProjectType,
|
||||||
calcShouldShowWaveform, calcShouldShowKeyframes,
|
calcShouldShowWaveform, calcShouldShowKeyframes,
|
||||||
} from './util';
|
} from './util';
|
||||||
import { toast, errorToast } from './swal';
|
import { toast, errorToast } from './swal';
|
||||||
|
@ -88,6 +88,7 @@ import isDev from './isDev';
|
||||||
|
|
||||||
const electron = window.require('electron');
|
const electron = window.require('electron');
|
||||||
const { exists } = window.require('fs-extra');
|
const { exists } = window.require('fs-extra');
|
||||||
|
const { lstat } = window.require('fs/promises');
|
||||||
const filePathToUrl = window.require('file-url');
|
const filePathToUrl = window.require('file-url');
|
||||||
const { parse: parsePath, join: pathJoin, basename, dirname } = window.require('path');
|
const { parse: parsePath, join: pathJoin, basename, dirname } = window.require('path');
|
||||||
|
|
||||||
|
@ -1798,12 +1799,28 @@ function App() {
|
||||||
|
|
||||||
[lastOpenedPathRef.current] = filePaths;
|
[lastOpenedPathRef.current] = filePaths;
|
||||||
|
|
||||||
// https://en.wikibooks.org/wiki/Inside_DVD-Video/Directory_Structure
|
// first check if it is a single directory, and if so, read it recursively
|
||||||
if (filePaths.length === 1 && /^VIDEO_TS$/i.test(basename(filePaths[0]))) {
|
if (filePaths.length === 1) {
|
||||||
if (mustDisallowVob()) return;
|
const firstFilePath = filePaths[0];
|
||||||
filePaths = await readVideoTs(filePaths[0]);
|
const firstFileStat = await lstat(firstFilePath);
|
||||||
|
if (firstFileStat.isDirectory()) {
|
||||||
|
console.log('Reading directory...');
|
||||||
|
filePaths = await readDirRecursively(firstFilePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only allow opening regular files
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
|
for (const path of filePaths) {
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const fileStat = await lstat(path);
|
||||||
|
|
||||||
|
if (!fileStat.isFile()) {
|
||||||
|
errorToast(i18n.t('Cannot open anything else than regular files'));
|
||||||
|
console.warn('Not a file:', path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (filePaths.length > 1) {
|
if (filePaths.length > 1) {
|
||||||
if (alwaysConcatMultipleFiles) {
|
if (alwaysConcatMultipleFiles) {
|
||||||
|
@ -1818,6 +1835,12 @@ function App() {
|
||||||
// filePaths.length is now 1
|
// filePaths.length is now 1
|
||||||
const firstFilePath = filePaths[0];
|
const firstFilePath = filePaths[0];
|
||||||
|
|
||||||
|
// https://en.wikibooks.org/wiki/Inside_DVD-Video/Directory_Structure
|
||||||
|
if (/^VIDEO_TS$/i.test(basename(firstFilePath))) {
|
||||||
|
if (mustDisallowVob()) return;
|
||||||
|
filePaths = await readVideoTs(firstFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
if (workingRef.current) return;
|
if (workingRef.current) return;
|
||||||
try {
|
try {
|
||||||
setWorking({ text: i18n.t('Loading file') });
|
setWorking({ text: i18n.t('Loading file') });
|
||||||
|
@ -1898,7 +1921,7 @@ function App() {
|
||||||
}, [alwaysConcatMultipleFiles, batchLoadPaths, setWorking, isFileOpened, batchFiles.length, userOpenSingleFile, checkFileOpened, loadEdlFile, enableAskForFileOpenAction, addStreamSourceFile, filePath]);
|
}, [alwaysConcatMultipleFiles, batchLoadPaths, setWorking, isFileOpened, batchFiles.length, userOpenSingleFile, checkFileOpened, loadEdlFile, enableAskForFileOpenAction, addStreamSourceFile, filePath]);
|
||||||
|
|
||||||
const openFilesDialog = useCallback(async () => {
|
const openFilesDialog = useCallback(async () => {
|
||||||
const { canceled, filePaths } = await showOpenDialog({ properties: ['openFile', 'multiSelections'], defaultPath: lastOpenedPathRef.current });
|
const { canceled, filePaths } = await showOpenDialog({ properties: ['openFile', 'openDirectory', 'multiSelections'], defaultPath: lastOpenedPathRef.current });
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
userOpenFiles(filePaths);
|
userOpenFiles(filePaths);
|
||||||
}, [userOpenFiles]);
|
}, [userOpenFiles]);
|
||||||
|
|
20
src/util.js
20
src/util.js
|
@ -11,7 +11,7 @@ import { ffmpegExtractWindow } from './util/constants';
|
||||||
|
|
||||||
const { dirname, parse: parsePath, join, extname, isAbsolute, resolve, basename } = window.require('path');
|
const { dirname, parse: parsePath, join, extname, isAbsolute, resolve, basename } = window.require('path');
|
||||||
const fsExtra = window.require('fs-extra');
|
const fsExtra = window.require('fs-extra');
|
||||||
const { stat, readdir, utimes, unlink } = window.require('fs/promises');
|
const { stat, lstat, readdir, utimes, unlink } = window.require('fs/promises');
|
||||||
const os = window.require('os');
|
const os = window.require('os');
|
||||||
const { ipcRenderer } = window.require('electron');
|
const { ipcRenderer } = window.require('electron');
|
||||||
const remote = window.require('@electron/remote');
|
const remote = window.require('@electron/remote');
|
||||||
|
@ -90,7 +90,7 @@ export async function getPathReadAccessError(pathIn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function dirExists(dirPath) {
|
export async function dirExists(dirPath) {
|
||||||
return (await pathExists(dirPath)) && (await fsExtra.lstat(dirPath)).isDirectory();
|
return (await pathExists(dirPath)) && (await lstat(dirPath)).isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
// const testFailFsOperation = isDev;
|
// const testFailFsOperation = isDev;
|
||||||
|
@ -402,6 +402,22 @@ export async function readVideoTs(videoTsPath) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function readDirRecursively(dirPath) {
|
||||||
|
const files = await readdir(dirPath, { recursive: true });
|
||||||
|
const ret = (await pMap(files, async (path) => {
|
||||||
|
if (['.DS_Store'].includes(basename(path))) return [];
|
||||||
|
|
||||||
|
const absPath = join(dirPath, path);
|
||||||
|
const fileStat = await lstat(absPath); // readdir also returns directories...
|
||||||
|
if (!fileStat.isFile()) return [];
|
||||||
|
|
||||||
|
return [absPath];
|
||||||
|
}, { concurrency: 5 })).flat();
|
||||||
|
|
||||||
|
if (ret.length === 0) throw new Error('No files found in folder');
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
export function getImportProjectType(filePath) {
|
export function getImportProjectType(filePath) {
|
||||||
if (filePath.endsWith('Summary.txt')) return 'dv-analyzer-summary-txt';
|
if (filePath.endsWith('Summary.txt')) return 'dv-analyzer-summary-txt';
|
||||||
const edlFormatForExtension = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' };
|
const edlFormatForExtension = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' };
|
||||||
|
|
Ładowanie…
Reference in New Issue