diff --git a/developer-notes.md b/developer-notes.md index 29c88ef6..34e96fec 100644 --- a/developer-notes.md +++ b/developer-notes.md @@ -35,12 +35,6 @@ For Windows, you may have to install [7z](https://www.7-zip.org/download.html), npm start ``` -### Building for production - -See: -- https://www.electron.build/ -- https://github.com/mifi/lossless-cut/blob/master/.github/workflows/build.yml - ## Building mas-dev (Mac App Store) build locally This will sign using the development provisioning profile: @@ -62,7 +56,7 @@ NOTE: when MAS (dev) build, Application Support will instead be here: rm -rf ~/Library/Containers/no.mifi.losslesscut-mac ``` -## Windows Store +## Windows Store notes Windows store version is built as a Desktop Bridge app (with `runFullTrust` capability). This means the app has access to essentially everything the user has access to, and even `internetClient` is redundant. @@ -76,13 +70,21 @@ For per-platform build/signing setup, see [this article](https://mifi.no/blog/au ### Release new version -- Commit changes +- If Mac App Store / Windows Store + - Checkout branch `stores` + - Merge `master` into `stores` - `npm version ...` - `git push --follow-tags` - Wait for build and draft in Github actions - Open draft in github and add Release notes - For files `LosslessCut-mac-universal.pkg` and `LosslessCut-win-x64.appx` add prefix `-DO-NOT-DOWNLOAD` -- Release the draft +- If intended as Github, release the draft +- If store-only release, release the draft as **pre-release** + +### After release + +- If Mac App Store / Windows Store + - Merge `stores` into `master` - Bump [snap version](https://snapcraft.io/losslesscut/listing) - `npm run scan-i18n` to get the newest English strings and push so weblate gets them diff --git a/no.mifi.losslesscut.appdata.xml b/no.mifi.losslesscut.appdata.xml index 3c5f4a27..ddd17da3 100644 --- a/no.mifi.losslesscut.appdata.xml +++ b/no.mifi.losslesscut.appdata.xml @@ -18,6 +18,7 @@ https://github.com/mifi/lossless-cut/issues https://paypal.me/mifino/usd + diff --git a/package.json b/package.json index 11f00a3c..8b8168cc 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "LosslessCut", "description": "The swiss army knife of lossless video/audio editing", "copyright": "Copyright © 2021 ${author}", - "version": "3.59.1", + "version": "3.60.0", "main": "public/electron.js", "homepage": "./", "scripts": { @@ -13,7 +13,7 @@ "icon-gen": "mkdirp icon-build build-resources/appx && node script/icon-gen.mjs", "download-ffmpeg-darwin-x64": "mkdirp ffmpeg/darwin-x64 && cd ffmpeg/darwin-x64 && wget https://github.com/mifi/ffmpeg-build-script/releases/download/6.0/ffmpeg -O ffmpeg && wget https://github.com/mifi/ffmpeg-build-script/releases/download/6.0/ffprobe -O ffprobe && chmod +x ffmpeg && chmod +x ffprobe", "download-ffmpeg-darwin-arm64": "mkdirp ffmpeg/darwin-arm64 && cd ffmpeg/darwin-arm64 && wget https://github.com/mifi/ffmpeg-builds/releases/download/6.0/ffmpeg-darwin-arm64-v6.0 -O ffmpeg && wget https://github.com/mifi/ffmpeg-builds/releases/download/6.0/ffprobe-darwin-arm64-v6.0 -O ffprobe && chmod +x ffmpeg && chmod +x ffprobe", - "download-ffmpeg-linux-x64": "mkdirp ffmpeg/linux-x64 && cd ffmpeg/linux-x64 && wget https://github.com/mifi/ffmpeg-builds/releases/download/6.0/ffmpeg-n6.0-12-ga6dc92968a-linux64-gpl-shared-6.0.tar.xz -O ffmpeg-ffprobe.xz && tar -xv -f ffmpeg-ffprobe.xz && mv ffmpeg-n6.0-12-ga6dc92968a-linux64-gpl-shared-6.0 extracted && mkdirp lib && mv extracted/bin/{ffmpeg,ffprobe} extracted/lib/lib*.so* lib", + "download-ffmpeg-linux-x64": "mkdirp ffmpeg/linux-x64 && cd ffmpeg/linux-x64 && wget https://github.com/mifi/ffmpeg-builds/releases/download/6.0/ffmpeg-n6.0-12-ga6dc92968a-linux64-gpl-shared-6.0.tar.xz -O ffmpeg-ffprobe.xz && tar -xv -f ffmpeg-ffprobe.xz && mv ffmpeg-n6.0-12-ga6dc92968a-linux64-gpl-shared-6.0 extracted && mkdirp lib && mv extracted/bin/ffmpeg extracted/bin/ffprobe extracted/lib/lib*.so* lib", "download-ffmpeg-win32-x64": "mkdirp ffmpeg/win32-x64 && cd ffmpeg/win32-x64 && npx download-cli https://github.com/mifi/ffmpeg-builds/releases/download/6.0/ffmpeg-n6.0-12-ga6dc92968a-win64-gpl-shared-6.0.zip --out . --filename ffmpeg-ffprobe.zip && 7z x ffmpeg-ffprobe.zip && mkdirp lib && cd ffmpeg-n6.0-12-ga6dc92968a-win64-gpl-shared-6.0/bin && npx shx mv ffmpeg.exe ffprobe.exe *.dll ../../lib", "build": "yarn icon-gen && vite build --outDir vite-dist", "tsc": "tsc --build", @@ -99,7 +99,7 @@ "use-debounce": "^5.1.0", "use-trace-update": "^1.3.0", "uuid": "^8.3.2", - "vite": "^4.1.5", + "vite": "^4.5.2", "vitest": "^0.28.5", "wait-on": "^7.0.1" }, diff --git a/public/electron.js b/public/electron.js index 878142f7..37d0d6ab 100644 --- a/public/electron.js +++ b/public/electron.js @@ -14,7 +14,7 @@ const { stat } = require('fs/promises'); const logger = require('./logger'); const menu = require('./menu'); const configStore = require('./configStore'); -const { frontendBuildDir } = require('./util'); +const { frontendBuildDir, isLinux, isWindows } = require('./util'); const attachContextMenu = require('./contextMenu'); const HttpServer = require('./httpServer'); @@ -33,6 +33,9 @@ unhandled({ }); const appName = 'LosslessCut'; +const copyrightYear = 2024; + +const appVersion = app.getVersion(); app.name = appName; @@ -40,11 +43,21 @@ const isStoreBuild = process.windowsStore || process.mas; const showVersion = !isStoreBuild; -const aboutPanelOptions = { applicationName: appName }; +/** @type import('electron').AboutPanelOptionsOptions */ +const aboutPanelOptions = { + applicationName: appName, + copyright: `Copyright © ${copyrightYear} Mikael Finstad ❤️ 🇳🇴`, + version: '', // not very useful (MacOS only, and same as applicationVersion) +}; + +// https://github.com/electron/electron/issues/18918 +// https://github.com/mifi/lossless-cut/issues/1537 +if (isLinux) { + aboutPanelOptions.version = appVersion; +} if (!showVersion) { - // version will be wrong in Store builds - aboutPanelOptions.applicationVersion = ''; - aboutPanelOptions.version = ''; + // https://github.com/mifi/lossless-cut/issues/1882 + aboutPanelOptions.applicationVersion = `${process.windowsStore ? 'Microsoft Store' : 'App Store'} edition, based on GitHub v${appVersion}`; } // https://www.electronjs.org/docs/latest/api/app#appsetaboutpaneloptionsoptions @@ -121,13 +134,13 @@ function createWindow() { webSecurity: !isDev, }, backgroundColor: darkMode ? '#333' : '#fff', + autoHideMenuBar: isWindows, // https://github.com/mifi/lossless-cut/issues/543#issuecomment-1872945955 }); remote.enable(mainWindow.webContents); attachContextMenu(mainWindow); - if (isDev) mainWindow.loadURL('http://localhost:3001'); // Need to useloadFile for special characters https://github.com/mifi/lossless-cut/issues/40 else mainWindow.loadFile(`${frontendBuildDir}/index.html`); diff --git a/src/App.jsx b/src/App.jsx index f7a72b85..eafba190 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -68,7 +68,7 @@ import { getOutPath, getSuffixedOutPath, handleError, getOutDir, isStoreBuild, dragPreventer, 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, mediaSourceQualities, } from './util'; import { toast, errorToast } from './swal'; @@ -88,6 +88,7 @@ import isDev from './isDev'; const electron = window.require('electron'); const { exists } = window.require('fs-extra'); +const { lstat } = window.require('fs/promises'); const filePathToUrl = window.require('file-url'); const { parse: parsePath, join: pathJoin, basename, dirname } = window.require('path'); @@ -1178,8 +1179,8 @@ function App() { console.log('outSegTemplateOrDefault', outSegTemplateOrDefault); - const { outSegFileNames, outSegError } = generateOutSegFileNames({ segments: segmentsToExport, template: outSegTemplateOrDefault }); - if (outSegError != null) { + const { outSegFileNames, outSegProblems } = generateOutSegFileNames({ segments: segmentsToExport, template: outSegTemplateOrDefault }); + if (outSegProblems.error != null) { console.warn('Output segments file name invalid, using default instead', outSegFileNames); } @@ -1296,6 +1297,7 @@ function App() { await onExportConfirm(); } else { setExportConfirmVisible(true); + setStreamsSelectorShown(false); } }, [filePath, exportConfirmEnabled, exportConfirmVisible, onExportConfirm]); @@ -1649,7 +1651,6 @@ function App() { const handleShowStreamsSelectorClick = useCallback(() => { setStreamsSelectorShown(true); - setExportConfirmVisible(false); }, []); const extractAllStreams = useCallback(async () => { @@ -1800,12 +1801,28 @@ function App() { [lastOpenedPathRef.current] = filePaths; - // https://en.wikibooks.org/wiki/Inside_DVD-Video/Directory_Structure - if (filePaths.length === 1 && /^VIDEO_TS$/i.test(basename(filePaths[0]))) { - if (mustDisallowVob()) return; - filePaths = await readVideoTs(filePaths[0]); + // first check if it is a single directory, and if so, read it recursively + if (filePaths.length === 1) { + const firstFilePath = 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 (alwaysConcatMultipleFiles) { @@ -1820,6 +1837,12 @@ function App() { // filePaths.length is now 1 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; try { setWorking({ text: i18n.t('Loading file') }); @@ -1900,7 +1923,7 @@ function App() { }, [alwaysConcatMultipleFiles, batchLoadPaths, setWorking, isFileOpened, batchFiles.length, userOpenSingleFile, checkFileOpened, loadEdlFile, enableAskForFileOpenAction, addStreamSourceFile, filePath]); 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; userOpenFiles(filePaths); }, [userOpenFiles]); @@ -2578,7 +2601,9 @@ function App() { /> - setStreamsSelectorShown(false)} style={{ padding: '1em 0' }}> + + + setStreamsSelectorShown(false)} maxWidth={1000}> {mainStreams && ( - - - + const { t } = useTranslation(); return ( - +

{t('Last ffmpeg commands')}

{ffmpegCommandLog.length > 0 ? ( diff --git a/src/Timeline.jsx b/src/Timeline.jsx index efaeac66..a943bd4f 100644 --- a/src/Timeline.jsx +++ b/src/Timeline.jsx @@ -42,7 +42,7 @@ const Waveforms = memo(({ calculateTimelinePercent, durationSafe, waveforms, zoo const CommandedTime = memo(({ commandedTimePercent }) => { const color = 'var(--gray12)'; - const commonStyle = { left: commandedTimePercent, position: 'absolute', zIndex: 4, pointerEvents: 'none' }; + const commonStyle = { left: commandedTimePercent, position: 'absolute', pointerEvents: 'none' }; return ( <> @@ -275,7 +275,7 @@ const Timeline = memo(({ const nextThumbTime = nextThumbnail ? nextThumbnail.time : durationSafe; const maxWidthPercent = ((nextThumbTime - thumbnail.time) / durationSafe) * 100 * 0.9; return ( - + ); })} @@ -285,13 +285,6 @@ const Timeline = memo(({ style={{ height: timelineHeight, width: `${zoom * 100}%`, position: 'relative', backgroundColor: timelineBackground, transition: darkModeTransition }} ref={timelineWrapperRef} > - {currentTimePercent !== undefined && ( - - )} - {commandedTimePercent !== undefined && ( - - )} - {apparentCutSegments.map((seg, i) => { if (seg.start === 0 && seg.end === 0) return null; // No video loaded @@ -325,10 +318,17 @@ const Timeline = memo(({ {shouldShowKeyframes && !areKeyframesTooClose && neighbouringKeyFrames.map((f) => (
))} + + {currentTimePercent !== undefined && ( + + )} + {commandedTimePercent !== undefined && ( + + )}
-
+
{formatTimeAndFrames(displayTime)}{isZoomed ? ` ${displayTimePercent}` : ''}
diff --git a/src/components/ExportConfirm.jsx b/src/components/ExportConfirm.jsx index 1fc77f2f..7e694289 100644 --- a/src/components/ExportConfirm.jsx +++ b/src/components/ExportConfirm.jsx @@ -356,29 +356,44 @@ const ExportConfirm = memo(({ )} - {!needSmartCut && ( - - - "avoid_negative_ts" - {!['make_zero', 'auto'].includes(avoidNegativeTs) &&
{t('It\'s generally recommended to set this to one of: {{values}}', { values: '"auto", "make_zero"' })}
} - - - - - - {!['make_zero', 'auto'].includes(avoidNegativeTs) ? ( - - ) : ( - - )} - - - )} + {!needSmartCut && (() => { + const avoidNegativeTsWarn = (() => { + if (willMerge) { + if (avoidNegativeTs !== 'make_non_negative') { + return t('When merging, it\'s generally recommended to set this to "make_non_negative"'); + } + return undefined; + } + if (!['make_zero', 'auto'].includes(avoidNegativeTs)) { + return t('It\'s generally recommended to set this to one of: {{values}}', { values: '"auto", "make_zero"' }); + } + return undefined; + })(); + + return ( + + + {`"${'avoid_negative_ts'}"`} + {avoidNegativeTsWarn != null &&
{avoidNegativeTsWarn}
} + + + + + + {avoidNegativeTsWarn != null ? ( + + ) : ( + + )} + + + ); + })()} @@ -397,7 +412,7 @@ const ExportConfirm = memo(({
-
+
keys.map((key, i) => ( @@ -105,13 +107,15 @@ const CreateBinding = memo(({ ); }); -const rowStyle = { display: 'flex', alignItems: 'center', margin: '6px 0' }; +const rowStyle = { display: 'flex', alignItems: 'center', margin: '.2em 0', borderBottom: '1px solid rgba(0,0,0,0.1)', paddingBottom: '.5em' }; const KeyboardShortcuts = memo(({ keyBindings, setKeyBindings, resetKeyBindings, currentCutSeg, mainActions, }) => { const { t } = useTranslation(); + const { mouseWheelZoomModifierKey } = useUserSettings(); + const { actionsMap, extraLinesPerCategory } = useMemo(() => { const playbackCategory = t('Playback'); const selectivePlaybackCategory = t('Playback/preview segments only'); @@ -136,8 +140,9 @@ const KeyboardShortcuts = memo(({
{t('Pan timeline')}
+ {getModifier(mouseWheelZoomModifierKey).map((v) => {v})} - {t('Mouse scroll/wheel left/right')} + {t('Mouse scroll/wheel up/down')}
, ], }, @@ -649,7 +654,7 @@ const KeyboardShortcuts = memo(({ return ( <> -
+
setSearchQuery(e.target.value)} placeholder="Search" width="100%" />
@@ -691,7 +696,7 @@ const KeyboardShortcuts = memo(({ ); })} - {extraLinesPerCategory[category]} + {extraLinesPerCategory[category] &&
{extraLinesPerCategory[category]}
}
))}
diff --git a/src/components/OutSegTemplateEditor.jsx b/src/components/OutSegTemplateEditor.jsx index 224e1add..e55f0c2e 100644 --- a/src/components/OutSegTemplateEditor.jsx +++ b/src/components/OutSegTemplateEditor.jsx @@ -23,13 +23,13 @@ const formatVariable = (variable) => `\${${variable}}`; const extVar = formatVariable('EXT'); -const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generateOutSegFileNames, currentSegIndexSafe, getOutSegError }) => { +const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generateOutSegFileNames, currentSegIndexSafe }) => { const { safeOutputFileName, toggleSafeOutputFileName, outputFileNameMinZeroPadding, setOutputFileNameMinZeroPadding } = useUserSettings(); const [text, setText] = useState(outSegTemplate); const [debouncedText] = useDebounce(text, 500); const [validText, setValidText] = useState(); - const [error, setError] = useState(); + const [outSegProblems, setOutSegProblems] = useState({ error: undefined, sameAsInputFileNameWarning: false }); const [outSegFileNames, setOutSegFileNames] = useState(); const [shown, setShown] = useState(); const inputRef = useRef(); @@ -42,22 +42,16 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate if (debouncedText == null) return; try { - const { outSegFileNames: newOutSegFileNames, outSegError } = generateOutSegFileNames({ template: debouncedText }); - setOutSegFileNames(newOutSegFileNames); - if (outSegError) { - setError(outSegError); - setValidText(); - return; - } - - setValidText(debouncedText); - setError(); + const outSegs = generateOutSegFileNames({ template: debouncedText }); + setOutSegFileNames(outSegs.outSegFileNames); + setOutSegProblems(outSegs.outSegProblems); + setValidText(outSegs.outSegProblems.error == null ? debouncedText : undefined); } catch (err) { console.error(err); setValidText(); - setError(err.message); + setOutSegProblems({ error: err.message }); } - }, [debouncedText, generateOutSegFileNames, getOutSegError, t]); + }, [debouncedText, generateOutSegFileNames, t]); // eslint-disable-next-line no-template-curly-in-string const isMissingExtension = validText != null && !validText.endsWith(extVar); @@ -80,8 +74,8 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate }, [setOutSegTemplate]); const onHideClick = useCallback(() => { - if (error == null) setShown(false); - }, [error]); + if (outSegProblems.error == null) setShown(false); + }, [outSegProblems.error]); const onShowClick = useCallback(() => { if (!shown) setShown(true); @@ -89,7 +83,7 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate const onTextChange = useCallback((e) => setText(e.target.value), []); - const needToShow = shown || error != null; + const needToShow = shown || outSegProblems.error != null || outSegProblems.sameAsInputFileNameWarning; const onVariableClick = useCallback((variable) => { const input = inputRef.current; @@ -132,7 +126,18 @@ const OutSegTemplateEditor = memo(({ outSegTemplate, setOutSegTemplate, generate ))}
- {error != null &&
{error}
} + {outSegProblems.error != null && ( +
+ {outSegProblems.error} +
+ )} + + {outSegProblems.error == null && outSegProblems.sameAsInputFileNameWarning && ( +
+ {' '} + {i18n.t('Output file name is the same as the source file name. This increases the risk of accidentally overwriting or deleting source files!')} +
+ )} {isMissingExtension && (
diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx index 336ae72a..062664b9 100644 --- a/src/components/Settings.jsx +++ b/src/components/Settings.jsx @@ -78,11 +78,11 @@ const Settings = memo(({ return ( <> -
+
{t('Hover mouse over buttons in the main interface to see which function they have')}
- +
@@ -321,8 +321,8 @@ const Settings = memo(({ {t('Mouse wheel zoom modifier key')} diff --git a/src/components/Sheet.jsx b/src/components/Sheet.jsx index 057c57a8..01f8a3a1 100644 --- a/src/components/Sheet.jsx +++ b/src/components/Sheet.jsx @@ -1,27 +1,33 @@ import React, { memo } from 'react'; import { IoIosCloseCircleOutline } from 'react-icons/io'; import { motion, AnimatePresence } from 'framer-motion'; +import { useTranslation } from 'react-i18next'; import styles from './Sheet.module.css'; -const Sheet = memo(({ visible, onClosePress, style, children }) => ( - - {visible && ( - - +const Sheet = memo(({ visible, onClosePress, children, maxWidth = 800, style }) => { + const { t } = useTranslation(); -
- {children} -
-
- )} -
-)); + return ( + + {visible && ( + +
+
+ {children} +
+ + +
+
+ )} +
+ ); +}); export default Sheet; diff --git a/src/components/Sheet.module.css b/src/components/Sheet.module.css index 5aeed925..5d34409e 100644 --- a/src/components/Sheet.module.css +++ b/src/components/Sheet.module.css @@ -1,11 +1,9 @@ .sheet { - padding: 1em 2em; position: fixed; left: 0; right: 0; top: 0; bottom: 0; - z-index: 10; background: var(--whiteA11); color: var(--gray12); backdrop-filter: blur(30px); diff --git a/src/components/ValueTuner.jsx b/src/components/ValueTuner.jsx index b9a26ced..dab12f36 100644 --- a/src/components/ValueTuner.jsx +++ b/src/components/ValueTuner.jsx @@ -1,27 +1,49 @@ -import React, { memo } from 'react'; +import React, { memo, useState, useCallback } from 'react'; import { Button } from 'evergreen-ui'; import { useTranslation } from 'react-i18next'; -const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution = 1000, min = 0, max = 1, resetToDefault }) => { +import Switch from './Switch'; + + +const ValueTuner = memo(({ style, title, value, setValue, onFinished, resolution = 1000, min: minIn = 0, max: maxIn = 1, resetToDefault }) => { const { t } = useTranslation(); + const [min, setMin] = useState(minIn); + const [max, setMax] = useState(maxIn); + function onChange(e) { e.target.blur(); setValue(Math.min(Math.max(min, ((e.target.value / resolution) * (max - min)) + min)), max); } + const isZoomed = !(min === minIn && max === maxIn); + + const toggleZoom = useCallback(() => { + if (isZoomed) { + setMin(minIn); + setMax(maxIn); + } else { + const zoomWindow = (maxIn - minIn) / 100; + setMin(Math.max(minIn, value - zoomWindow)); + setMax(Math.min(maxIn, value + zoomWindow)); + } + }, [isZoomed, maxIn, minIn, value]); + return ( -
-
-
{title}
-
{value.toFixed(2)}
-
- - +
+
+
{title}
+
{value.toFixed(4)}
+ {t('Precise')}
-
- +
+ +
+ +
+ +
); diff --git a/src/components/ValueTuners.jsx b/src/components/ValueTuners.jsx index 6d57d3d6..b62de73c 100644 --- a/src/components/ValueTuners.jsx +++ b/src/components/ValueTuners.jsx @@ -14,6 +14,8 @@ const ValueTuners = memo(({ type, onFinished }) => { title: t('Timeline trackpad/wheel sensitivity'), value: wheelSensitivity, setValue: setWheelSensitivity, + min: 0, + max: 4, default: 0.2, }, keyboardNormalSeekSpeed: { diff --git a/src/components/Working.jsx b/src/components/Working.jsx index bd40ac69..d78add4d 100644 --- a/src/components/Working.jsx +++ b/src/components/Working.jsx @@ -9,7 +9,7 @@ import loadingLottie from '../7077-magic-flow.json'; const Working = memo(({ text, cutProgress, onAbortClick }) => ( -
+
({ - ctrl: t('Ctrl'), - shift: t('Shift'), - alt: t('Alt'), - meta: t('⌘ Cmd / ⊞ Win'), + ctrl: [t('Ctrl')], + shift: [t('Shift')], + alt: [t('Alt')], + meta: [t('⌘ Cmd'), t('⊞ Win')], }); +export const getModifier = (key) => getModifierKeyNames()[key]; + function useTimelineScroll({ wheelSensitivity, mouseWheelZoomModifierKey, invertTimelineScroll, zoomRel, seekRel }) { const onWheel = useCallback((e) => { const { pixelX, pixelY } = normalizeWheel(e); diff --git a/src/util.js b/src/util.js index 96b8a581..579f6aa3 100644 --- a/src/util.js +++ b/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 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 { ipcRenderer } = window.require('electron'); const remote = window.require('@electron/remote'); @@ -90,7 +90,7 @@ export async function getPathReadAccessError(pathIn) { } 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; @@ -402,6 +402,22 @@ export async function readVideoTs(videoTsPath) { 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) { if (filePath.endsWith('Summary.txt')) return 'dv-analyzer-summary-txt'; const edlFormatForExtension = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' }; diff --git a/src/util/outputNameTemplate.js b/src/util/outputNameTemplate.js index ca12e9a5..cebcafa1 100644 --- a/src/util/outputNameTemplate.js +++ b/src/util/outputNameTemplate.js @@ -9,10 +9,11 @@ import { getSegmentTags, formatSegNum } from '../segments'; export const segNumVariable = 'SEG_NUM'; export const segSuffixVariable = 'SEG_SUFFIX'; -const { parse: parsePath, sep: pathSep, join: pathJoin, normalize: pathNormalize } = window.require('path'); +const { parse: parsePath, sep: pathSep, join: pathJoin, normalize: pathNormalize, basename } = window.require('path'); -function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileName }) { +function getOutSegProblems({ fileNames, filePath, outputDir, safeOutputFileName }) { let error; + let sameAsInputFileNameWarning = false; // eslint-disable-next-line no-restricted-syntax for (const fileName of fileNames) { @@ -49,6 +50,10 @@ function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileName }) const shouldCheckPathLength = isWindows || isDev; const shouldCheckFileEnd = isWindows || isDev; + if (basename(filePath) === fileName) { + sameAsInputFileNameWarning = true; // just an extra warning in case sameAsInputPath doesn't work + } + if (fileName.length === 0) { error = i18n.t('At least one resulting file name has no length'); break; @@ -73,11 +78,14 @@ function getOutSegError({ fileNames, filePath, outputDir, safeOutputFileName }) } } - if (error != null) return error; + if (error == null && hasDuplicates(fileNames)) { + error = i18n.t('Output file name template results in duplicate file names (you are trying to export multiple files with the same name). You can fix this for example by adding the "{{segNumVariable}}" variable.', { segNumVariable }); + } - if (hasDuplicates(fileNames)) return i18n.t('Output file name template results in duplicate file names (you are trying to export multiple files with the same name). You can fix this for example by adding the "{{segNumVariable}}" variable.', { segNumVariable }); - - return undefined; + return { + error, + sameAsInputFileNameWarning, + }; } // This is used as a fallback and so it has to always generate unique file names @@ -155,10 +163,10 @@ export function generateOutSegFileNames({ segments, template: desiredTemplate, f let outSegFileNames = generate({ template: desiredTemplate, forceSafeOutputFileName: false }); - const outSegError = getOutSegError({ fileNames: outSegFileNames, filePath, outputDir, safeOutputFileName }); - if (outSegError != null) { + const outSegProblems = getOutSegProblems({ fileNames: outSegFileNames, filePath, outputDir, safeOutputFileName }); + if (outSegProblems.error != null) { outSegFileNames = generate({ template: defaultOutSegTemplate, forceSafeOutputFileName: true }); } - return { outSegFileNames, outSegError }; + return { outSegFileNames, outSegProblems }; } diff --git a/vite.config.js b/vite.config.js index 57f9f52d..d0da754e 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,5 +8,6 @@ export default defineConfig({ base: '', build: { chunkSizeWarningLimit: 3e6, + sourcemap: true, }, }); diff --git a/yarn.lock b/yarn.lock index 4d974a1b..678ab928 100644 --- a/yarn.lock +++ b/yarn.lock @@ -569,16 +569,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm64@npm:0.17.19" +"@esbuild/android-arm64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/android-arm64@npm:0.17.8" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/android-arm64@npm:0.17.8" +"@esbuild/android-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm64@npm:0.18.20" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -590,16 +590,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-arm@npm:0.17.19" +"@esbuild/android-arm@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/android-arm@npm:0.17.8" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/android-arm@npm:0.17.8" +"@esbuild/android-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-arm@npm:0.18.20" conditions: os=android & cpu=arm languageName: node linkType: hard @@ -611,16 +611,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/android-x64@npm:0.17.19" +"@esbuild/android-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/android-x64@npm:0.17.8" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/android-x64@npm:0.17.8" +"@esbuild/android-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/android-x64@npm:0.18.20" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -632,16 +632,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-arm64@npm:0.17.19" +"@esbuild/darwin-arm64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/darwin-arm64@npm:0.17.8" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/darwin-arm64@npm:0.17.8" +"@esbuild/darwin-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-arm64@npm:0.18.20" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -653,16 +653,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/darwin-x64@npm:0.17.19" +"@esbuild/darwin-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/darwin-x64@npm:0.17.8" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/darwin-x64@npm:0.17.8" +"@esbuild/darwin-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/darwin-x64@npm:0.18.20" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -674,16 +674,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-arm64@npm:0.17.19" +"@esbuild/freebsd-arm64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/freebsd-arm64@npm:0.17.8" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/freebsd-arm64@npm:0.17.8" +"@esbuild/freebsd-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-arm64@npm:0.18.20" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -695,16 +695,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/freebsd-x64@npm:0.17.19" +"@esbuild/freebsd-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/freebsd-x64@npm:0.17.8" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/freebsd-x64@npm:0.17.8" +"@esbuild/freebsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/freebsd-x64@npm:0.18.20" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -716,16 +716,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm64@npm:0.17.19" +"@esbuild/linux-arm64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-arm64@npm:0.17.8" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-arm64@npm:0.17.8" +"@esbuild/linux-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm64@npm:0.18.20" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -737,16 +737,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-arm@npm:0.17.19" +"@esbuild/linux-arm@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-arm@npm:0.17.8" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-arm@npm:0.17.8" +"@esbuild/linux-arm@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-arm@npm:0.18.20" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -758,16 +758,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ia32@npm:0.17.19" +"@esbuild/linux-ia32@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-ia32@npm:0.17.8" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-ia32@npm:0.17.8" +"@esbuild/linux-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ia32@npm:0.18.20" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -779,16 +779,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-loong64@npm:0.17.19" +"@esbuild/linux-loong64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-loong64@npm:0.17.8" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-loong64@npm:0.17.8" +"@esbuild/linux-loong64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-loong64@npm:0.18.20" conditions: os=linux & cpu=loong64 languageName: node linkType: hard @@ -800,16 +800,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-mips64el@npm:0.17.19" +"@esbuild/linux-mips64el@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-mips64el@npm:0.17.8" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-mips64el@npm:0.17.8" +"@esbuild/linux-mips64el@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-mips64el@npm:0.18.20" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -821,16 +821,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-ppc64@npm:0.17.19" +"@esbuild/linux-ppc64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-ppc64@npm:0.17.8" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-ppc64@npm:0.17.8" +"@esbuild/linux-ppc64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-ppc64@npm:0.18.20" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -842,16 +842,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-riscv64@npm:0.17.19" +"@esbuild/linux-riscv64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-riscv64@npm:0.17.8" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-riscv64@npm:0.17.8" +"@esbuild/linux-riscv64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-riscv64@npm:0.18.20" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -863,16 +863,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-s390x@npm:0.17.19" +"@esbuild/linux-s390x@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-s390x@npm:0.17.8" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-s390x@npm:0.17.8" +"@esbuild/linux-s390x@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-s390x@npm:0.18.20" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -884,16 +884,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/linux-x64@npm:0.17.19" +"@esbuild/linux-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/linux-x64@npm:0.17.8" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/linux-x64@npm:0.17.8" +"@esbuild/linux-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/linux-x64@npm:0.18.20" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -905,16 +905,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/netbsd-x64@npm:0.17.19" +"@esbuild/netbsd-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/netbsd-x64@npm:0.17.8" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/netbsd-x64@npm:0.17.8" +"@esbuild/netbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/netbsd-x64@npm:0.18.20" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -926,16 +926,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/openbsd-x64@npm:0.17.19" +"@esbuild/openbsd-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/openbsd-x64@npm:0.17.8" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/openbsd-x64@npm:0.17.8" +"@esbuild/openbsd-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/openbsd-x64@npm:0.18.20" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -947,16 +947,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/sunos-x64@npm:0.17.19" +"@esbuild/sunos-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/sunos-x64@npm:0.17.8" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/sunos-x64@npm:0.17.8" +"@esbuild/sunos-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/sunos-x64@npm:0.18.20" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -968,16 +968,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-arm64@npm:0.17.19" +"@esbuild/win32-arm64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/win32-arm64@npm:0.17.8" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/win32-arm64@npm:0.17.8" +"@esbuild/win32-arm64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-arm64@npm:0.18.20" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard @@ -989,16 +989,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-ia32@npm:0.17.19" +"@esbuild/win32-ia32@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/win32-ia32@npm:0.17.8" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/win32-ia32@npm:0.17.8" +"@esbuild/win32-ia32@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-ia32@npm:0.18.20" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -1010,16 +1010,16 @@ __metadata: languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.19": - version: 0.17.19 - resolution: "@esbuild/win32-x64@npm:0.17.19" +"@esbuild/win32-x64@npm:0.17.8": + version: 0.17.8 + resolution: "@esbuild/win32-x64@npm:0.17.8" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.8": - version: 0.17.8 - resolution: "@esbuild/win32-x64@npm:0.17.8" +"@esbuild/win32-x64@npm:0.18.20": + version: 0.18.20 + resolution: "@esbuild/win32-x64@npm:0.18.20" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -4232,32 +4232,32 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.17.5": - version: 0.17.19 - resolution: "esbuild@npm:0.17.19" +"esbuild@npm:^0.18.10": + version: 0.18.20 + resolution: "esbuild@npm:0.18.20" dependencies: - "@esbuild/android-arm": "npm:0.17.19" - "@esbuild/android-arm64": "npm:0.17.19" - "@esbuild/android-x64": "npm:0.17.19" - "@esbuild/darwin-arm64": "npm:0.17.19" - "@esbuild/darwin-x64": "npm:0.17.19" - "@esbuild/freebsd-arm64": "npm:0.17.19" - "@esbuild/freebsd-x64": "npm:0.17.19" - "@esbuild/linux-arm": "npm:0.17.19" - "@esbuild/linux-arm64": "npm:0.17.19" - "@esbuild/linux-ia32": "npm:0.17.19" - "@esbuild/linux-loong64": "npm:0.17.19" - "@esbuild/linux-mips64el": "npm:0.17.19" - "@esbuild/linux-ppc64": "npm:0.17.19" - "@esbuild/linux-riscv64": "npm:0.17.19" - "@esbuild/linux-s390x": "npm:0.17.19" - "@esbuild/linux-x64": "npm:0.17.19" - "@esbuild/netbsd-x64": "npm:0.17.19" - "@esbuild/openbsd-x64": "npm:0.17.19" - "@esbuild/sunos-x64": "npm:0.17.19" - "@esbuild/win32-arm64": "npm:0.17.19" - "@esbuild/win32-ia32": "npm:0.17.19" - "@esbuild/win32-x64": "npm:0.17.19" + "@esbuild/android-arm": "npm:0.18.20" + "@esbuild/android-arm64": "npm:0.18.20" + "@esbuild/android-x64": "npm:0.18.20" + "@esbuild/darwin-arm64": "npm:0.18.20" + "@esbuild/darwin-x64": "npm:0.18.20" + "@esbuild/freebsd-arm64": "npm:0.18.20" + "@esbuild/freebsd-x64": "npm:0.18.20" + "@esbuild/linux-arm": "npm:0.18.20" + "@esbuild/linux-arm64": "npm:0.18.20" + "@esbuild/linux-ia32": "npm:0.18.20" + "@esbuild/linux-loong64": "npm:0.18.20" + "@esbuild/linux-mips64el": "npm:0.18.20" + "@esbuild/linux-ppc64": "npm:0.18.20" + "@esbuild/linux-riscv64": "npm:0.18.20" + "@esbuild/linux-s390x": "npm:0.18.20" + "@esbuild/linux-x64": "npm:0.18.20" + "@esbuild/netbsd-x64": "npm:0.18.20" + "@esbuild/openbsd-x64": "npm:0.18.20" + "@esbuild/sunos-x64": "npm:0.18.20" + "@esbuild/win32-arm64": "npm:0.18.20" + "@esbuild/win32-ia32": "npm:0.18.20" + "@esbuild/win32-x64": "npm:0.18.20" dependenciesMeta: "@esbuild/android-arm": optional: true @@ -4305,7 +4305,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 86ada7cad6d37a3445858fee31ca39fc6c0436c7c00b2e07b9ce308235be67f36aefe0dda25da9ab08653fde496d1e759d6ad891ce9479f9e1fb4964c8f2a0fa + checksum: 1f723ec71c3aa196473bf3298316eedc3f62d523924652dfeb60701b609792f918fc60db84b420d1d8ba9bfa7d69de2fc1d3157ba47c028bdae5d507a26a3c64 languageName: node linkType: hard @@ -5010,23 +5010,13 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.0": - version: 1.14.8 - resolution: "follow-redirects@npm:1.14.8" +"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9": + version: 1.15.4 + resolution: "follow-redirects@npm:1.15.4" peerDependenciesMeta: debug: optional: true - checksum: 94b8cca8123c719273788174728fea5789267ab077784eae095e41fba0b5944b9fabda6b98164d15f0166914489b4d3896e3e181dd2d67b9f1b3969eb14f7c0f - languageName: node - linkType: hard - -"follow-redirects@npm:^1.14.9": - version: 1.15.2 - resolution: "follow-redirects@npm:1.15.2" - peerDependenciesMeta: - debug: - optional: true - checksum: 8be0d39919770054812537d376850ccde0b4762b0501c440bd08724971a078123b55f57704f2984e0664fecc0c86adea85add63295804d9dce401cd9604c91d3 + checksum: 2e8f5f259a6b02dfa8dc199e08431848a7c3beed32eb4c19945966164a52c89f07b86c3afcc32ebe4279cf0a960520e45a63013d6350309c5ec90133c5d9351a languageName: node linkType: hard @@ -6885,7 +6875,7 @@ __metadata: use-debounce: "npm:^5.1.0" use-trace-update: "npm:^1.3.0" uuid: "npm:^8.3.2" - vite: "npm:^4.1.5" + vite: "npm:^4.5.2" vitest: "npm:^0.28.5" wait-on: "npm:^7.0.1" winston: "npm:^3.8.1" @@ -7400,6 +7390,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" + bin: + nanoid: bin/nanoid.cjs + checksum: ac1eb60f615b272bccb0e2b9cd933720dad30bf9708424f691b8113826bb91aca7e9d14ef5d9415a6ba15c266b37817256f58d8ce980c82b0ba3185352565679 + languageName: node + linkType: hard + "napi-build-utils@npm:^1.0.1": version: 1.0.2 resolution: "napi-build-utils@npm:1.0.2" @@ -8059,7 +8058,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.21, postcss@npm:^8.4.23": +"postcss@npm:^8.4.21": version: 8.4.31 resolution: "postcss@npm:8.4.31" dependencies: @@ -8070,6 +8069,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.4.27": + version: 8.4.33 + resolution: "postcss@npm:8.4.33" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.0.2" + checksum: e22a4594c255f26117f38419fb494d7ecab0f596cd409f7aadc8a6173abf180ed7ea970cd13fd366ab12b5840be901d2a09b25197700c2ebcb5a8077326bf519 + languageName: node + linkType: hard + "prebuild-install@npm:^7.0.0": version: 7.1.0 resolution: "prebuild-install@npm:7.1.0" @@ -8841,9 +8851,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.21.0": - version: 3.23.1 - resolution: "rollup@npm:3.23.1" +"rollup@npm:^3.27.1": + version: 3.29.4 + resolution: "rollup@npm:3.29.4" dependencies: fsevents: "npm:~2.3.2" dependenciesMeta: @@ -8851,7 +8861,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 242fb599cfdf0ddb76279ddfd543243b86ce6b71652031ac52e4b6c3141e437384b12cb2c82dc69185133da2defab10c5980d3d147e4e154977455404b11d17a + checksum: 9e39d54e23731a4c4067e9c02910cdf7479a0f9a7584796e2dc6efaa34bb1e5e015c062c87d1e64d96038baca76cefd47681ff22604fae5827147f54123dc6d0 languageName: node linkType: hard @@ -10536,17 +10546,18 @@ __metadata: languageName: node linkType: hard -"vite@npm:^4.1.5": - version: 4.3.9 - resolution: "vite@npm:4.3.9" +"vite@npm:^4.5.2": + version: 4.5.2 + resolution: "vite@npm:4.5.2" dependencies: - esbuild: "npm:^0.17.5" + esbuild: "npm:^0.18.10" fsevents: "npm:~2.3.2" - postcss: "npm:^8.4.23" - rollup: "npm:^3.21.0" + postcss: "npm:^8.4.27" + rollup: "npm:^3.27.1" peerDependencies: "@types/node": ">= 14" less: "*" + lightningcss: ^1.21.0 sass: "*" stylus: "*" sugarss: "*" @@ -10559,6 +10570,8 @@ __metadata: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true stylus: @@ -10569,7 +10582,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: c2f0b392a253318a1d3ffc6873885d4a03c6bda6f717682bd0c82b7a431a67fb1ba08de6e1bf7f3f31bde1615015c5ef4be264f20c6e34c590d8a7c9516e94f4 + checksum: 3feb39f8da038fb2b1ad074c19a9579c263c1d7a872c5c6e0269b82d67805bb8c93cf9fc393e852807483ae9a918b1ac2861c72f73ee92fb3935ea68333a2cf7 languageName: node linkType: hard
{t('Settings')}