From f67761903935d35fd85609cfb5c6f016a8f431c6 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Thu, 21 Mar 2024 23:28:25 +0800 Subject: [PATCH] upgrade to electron-vite --- .eslintignore | 2 +- .eslintrc.cjs | 10 +- .github/workflows/build.yml | 2 +- .gitignore | 2 +- .vscode/settings.json | 2 +- README.md | 2 +- cli.md | 2 +- developer-notes.md | 4 - electron.vite.config.js | 28 + i18next-parser.config.mjs | 6 +- .../locales => locales}/cs/translation.json | 0 .../locales => locales}/de/translation.json | 0 .../locales => locales}/en/translation.json | 0 .../locales => locales}/es/translation.json | 0 .../locales => locales}/et/translation.json | 0 .../locales => locales}/fa/translation.json | 0 .../locales => locales}/fi/translation.json | 0 .../locales => locales}/fr/translation.json | 0 .../locales => locales}/he/translation.json | 0 .../locales => locales}/hu/translation.json | 0 .../locales => locales}/id/translation.json | 0 .../locales => locales}/it/translation.json | 0 .../locales => locales}/ja/translation.json | 0 .../locales => locales}/ko/translation.json | 0 .../locales => locales}/lt/translation.json | 0 .../nb_NO/translation.json | 0 .../locales => locales}/nl/translation.json | 0 .../locales => locales}/nn/translation.json | 0 .../locales => locales}/pl/translation.json | 0 .../locales => locales}/pt/translation.json | 0 .../pt_BR/translation.json | 0 .../locales => locales}/ro/translation.json | 0 .../locales => locales}/ru/translation.json | 0 .../locales => locales}/si/translation.json | 0 .../locales => locales}/sl/translation.json | 0 .../locales => locales}/sr/translation.json | 0 .../locales => locales}/sv/translation.json | 0 .../locales => locales}/tr/translation.json | 0 .../locales => locales}/uk/translation.json | 0 .../locales => locales}/vi/translation.json | 0 .../zh_Hans/translation.json | 0 .../zh_Hant/translation.json | 0 package.json | 66 +- public/constants.js | 11 - public/util.js | 20 - script/icon-gen.mjs | 29 - script/icon-gen.mts | 32 + script/{postversion.mjs => postversion.mts} | 3 +- .../{xcrun-wrapper.mjs => xcrun-wrapper.mts} | 11 +- src/isDev.ts | 3 - .../main/compatPlayer.ts | 77 +- .../configStore.js => src/main/configStore.ts | 47 +- src/main/constants.ts | 4 + .../contextMenu.js => src/main/contextMenu.ts | 8 +- public/ffmpeg.js => src/main/ffmpeg.ts | 331 +++-- .../httpServer.js => src/main/httpServer.ts | 25 +- public/i18n.js => src/main/i18n.ts | 10 +- .../i18n-common.js => src/main/i18nCommon.ts | 38 +- public/electron.js => src/main/index.ts | 123 +- src/main/isDev.ts | 2 + public/logger.js => src/main/logger.ts | 23 +- public/menu.js => src/main/menu.ts | 15 +- .../main/updateChecker.ts | 31 +- src/main/util.ts | 8 + src/preload/index.ts | 2 + index.html => src/renderer/index.html | 0 src/{ => renderer/src}/7077-magic-flow.json | 0 src/{ => renderer/src}/App.tsx | 15 +- src/{ => renderer/src}/BetweenSegments.tsx | 0 src/{ => renderer/src}/BottomBar.jsx | 0 src/{ => renderer/src}/ErrorBoundary.jsx | 0 src/{ => renderer/src}/LastCommandsSheet.tsx | 0 src/{ => renderer/src}/MediaSourcePlayer.tsx | 11 +- src/{ => renderer/src}/NoFileLoaded.tsx | 0 src/{ => renderer/src}/SegmentList.tsx | 0 src/{ => renderer/src}/StreamsSelector.jsx | 0 src/{ => renderer/src}/Timeline.tsx | 0 src/{ => renderer/src}/TimelineSeg.tsx | 0 src/{ => renderer/src}/TopMenu.tsx | 0 .../__snapshots__/edlFormats.test.ts.snap | 0 .../src}/__snapshots__/segments.test.ts.snap | 0 src/{ => renderer/src}/animations.js | 0 src/{ => renderer/src}/colors.js | 0 .../src}/components/AutoExportToggler.tsx | 0 .../src}/components/BatchFile.tsx | 0 .../src}/components/BatchFilesList.jsx | 0 .../src}/components/BigWaveform.tsx | 0 .../src}/components/Button.module.css | 0 src/{ => renderer/src}/components/Button.tsx | 0 .../src}/components/CaptureFormatButton.tsx | 0 .../src}/components/ConcatDialog.tsx | 2 +- .../src}/components/CopyClipboardButton.tsx | 0 .../src}/components/ExportButton.tsx | 0 .../src}/components/ExportConfirm.module.css | 0 .../src}/components/ExportConfirm.tsx | 4 +- .../src}/components/ExportModeButton.tsx | 0 .../src}/components/HighlightedText.tsx | 0 .../src}/components/KeyboardShortcuts.tsx | 2 +- .../src}/components/MergedOutFileName.tsx | 0 .../src}/components/MovFastStartButton.jsx | 0 .../src}/components/OutSegTemplateEditor.tsx | 0 .../src}/components/OutputFormatSelect.tsx | 0 .../components/PlaybackStreamSelector.tsx | 0 .../src}/components/PreserveMovDataButton.jsx | 0 .../src}/components/SegmentCutpointButton.tsx | 0 .../src}/components/Select.module.css | 0 src/{ => renderer/src}/components/Select.tsx | 0 .../src}/components/SetCutpointButton.tsx | 0 .../src}/components/Settings.module.css | 0 .../src}/components/Settings.tsx | 2 +- .../src}/components/Sheet.module.css | 0 src/{ => renderer/src}/components/Sheet.tsx | 0 .../src}/components/SimpleModeButton.tsx | 0 .../src}/components/Switch.module.css | 0 src/{ => renderer/src}/components/Switch.tsx | 0 .../src}/components/TagEditor.jsx | 0 .../src}/components/TextInput.tsx | 0 .../src}/components/ToggleExportConfirm.tsx | 0 .../src}/components/ValueTuner.tsx | 0 .../src}/components/ValueTuners.tsx | 2 +- .../src}/components/VolumeControl.tsx | 0 src/{ => renderer/src}/components/Working.tsx | 0 src/{ => renderer/src}/contexts.ts | 0 .../src}/dialogs/extractFrames.jsx | 0 src/{ => renderer/src}/dialogs/html5ify.tsx | 2 +- src/{ => renderer/src}/dialogs/index.tsx | 0 src/{ => renderer/src}/dialogs/parameters.tsx | 5 +- src/{ => renderer/src}/edlFormats.test.ts | 0 src/{ => renderer/src}/edlFormats.ts | 0 src/{ => renderer/src}/edlStore.ts | 0 src/{ => renderer/src}/ffmpeg-parameters.js | 0 src/{ => renderer/src}/ffmpeg.ts | 32 +- src/{ => renderer/src}/ffprobe.js | 0 .../src}/fixtures/DV Analyzer Summary.txt | 0 .../src}/fixtures/FCPXML_1_9.fcpxml | 0 .../src}/fixtures/Final Cut Pro XMEML 2.xml | 0 .../src}/fixtures/Final Cut Pro XMEML 3.xml | 0 .../src}/fixtures/Final Cut Pro XMEML.xml | 0 src/{ => renderer/src}/fixtures/mplayer.edl | 0 ...ayer bookmark format utf16le issue 867.pbf | Bin src/{ => renderer/src}/fixtures/sample.srt | 0 src/{ => renderer/src}/fixtures/test1.csv | 0 src/{ => renderer/src}/fixtures/test1.pbf | Bin src/{ => renderer/src}/fixtures/test2.csv | 0 src/{ => renderer/src}/fixtures/test2.pbf | Bin src/{ => renderer/src}/fixtures/test3.csv | 0 src/{ => renderer/src}/fixtures/test3.pbf | Bin .../src}/hooks/normalizeWheel.ts | 0 .../src}/hooks/useContextMenu.ts | 0 .../src/hooks/useDirectoryAccess.ts} | 11 +- .../src}/hooks/useFfmpegOperations.ts | 8 +- .../src}/hooks/useFileFormatState.ts | 0 .../src}/hooks/useFrameCapture.ts | 4 +- src/{ => renderer/src}/hooks/useKeyboard.ts | 2 +- src/{ => renderer/src}/hooks/useKeyframes.ts | 2 +- src/{ => renderer/src}/hooks/useNativeMenu.ts | 0 src/{ => renderer/src}/hooks/useSegments.ts | 18 +- .../src}/hooks/useTimelineScroll.ts | 0 .../src}/hooks/useUserSettings.ts | 0 .../src}/hooks/useUserSettingsRoot.ts | 6 +- src/{ => renderer/src}/hooks/useWaveform.ts | 2 +- .../src}/hooks/useWhatChanged.js | 0 src/{ => renderer/src}/i18n.ts | 4 +- src/{ => renderer/src}/icon-mac.svg | 0 src/{ => renderer/src}/icon.svg | 0 src/{ => renderer/src}/index.tsx | 16 +- src/renderer/src/isDev.ts | 3 + src/{ => renderer/src}/main.css | 0 src/{ => renderer/src}/mifi.js | 0 src/{ => renderer/src}/outFormats.js | 0 .../src/reporting.tsx} | 33 +- src/{ => renderer/src}/segments.test.ts | 0 src/{ => renderer/src}/segments.ts | 0 src/{ => renderer/src}/smartcut.ts | 2 +- src/{ => renderer/src}/swal.ts | 0 src/{ => renderer/src}/theme.ts | 0 src/{ => renderer/src}/types.ts | 2 - src/{ => renderer/src}/util.ts | 17 +- src/{ => renderer/src}/util/colors.ts | 0 src/{ => renderer/src}/util/constants.ts | 0 src/{ => renderer/src}/util/duration.test.ts | 0 src/{ => renderer/src}/util/duration.ts | 0 .../src}/util/outputNameTemplate.ts | 0 .../src}/util/rate-calculator.js | 0 .../src}/util/rate-calculator.test.ts | 0 src/{ => renderer/src}/util/streams.test.ts | 2 +- src/{ => renderer/src}/util/streams.ts | 2 +- translation.md | 4 +- tsconfig.json | 1 + tsconfig.main.json | 7 +- tsconfig.node.json | 9 + tsconfig.web.json | 2 +- types.ts | 11 +- vite.config.js | 13 - yarn.lock | 1158 +++++++++++------ 195 files changed, 1399 insertions(+), 996 deletions(-) create mode 100644 electron.vite.config.js rename {public/locales => locales}/cs/translation.json (100%) rename {public/locales => locales}/de/translation.json (100%) rename {public/locales => locales}/en/translation.json (100%) rename {public/locales => locales}/es/translation.json (100%) rename {public/locales => locales}/et/translation.json (100%) rename {public/locales => locales}/fa/translation.json (100%) rename {public/locales => locales}/fi/translation.json (100%) rename {public/locales => locales}/fr/translation.json (100%) rename {public/locales => locales}/he/translation.json (100%) rename {public/locales => locales}/hu/translation.json (100%) rename {public/locales => locales}/id/translation.json (100%) rename {public/locales => locales}/it/translation.json (100%) rename {public/locales => locales}/ja/translation.json (100%) rename {public/locales => locales}/ko/translation.json (100%) rename {public/locales => locales}/lt/translation.json (100%) rename {public/locales => locales}/nb_NO/translation.json (100%) rename {public/locales => locales}/nl/translation.json (100%) rename {public/locales => locales}/nn/translation.json (100%) rename {public/locales => locales}/pl/translation.json (100%) rename {public/locales => locales}/pt/translation.json (100%) rename {public/locales => locales}/pt_BR/translation.json (100%) rename {public/locales => locales}/ro/translation.json (100%) rename {public/locales => locales}/ru/translation.json (100%) rename {public/locales => locales}/si/translation.json (100%) rename {public/locales => locales}/sl/translation.json (100%) rename {public/locales => locales}/sr/translation.json (100%) rename {public/locales => locales}/sv/translation.json (100%) rename {public/locales => locales}/tr/translation.json (100%) rename {public/locales => locales}/uk/translation.json (100%) rename {public/locales => locales}/vi/translation.json (100%) rename {public/locales => locales}/zh_Hans/translation.json (100%) rename {public/locales => locales}/zh_Hant/translation.json (100%) delete mode 100644 public/constants.js delete mode 100644 public/util.js delete mode 100644 script/icon-gen.mjs create mode 100644 script/icon-gen.mts rename script/{postversion.mjs => postversion.mts} (91%) rename script/{xcrun-wrapper.mjs => xcrun-wrapper.mts} (87%) delete mode 100644 src/isDev.ts rename public/compatPlayer.js => src/main/compatPlayer.ts (54%) rename public/configStore.js => src/main/configStore.ts (89%) create mode 100644 src/main/constants.ts rename public/contextMenu.js => src/main/contextMenu.ts (81%) rename public/ffmpeg.js => src/main/ffmpeg.ts (57%) rename public/httpServer.js => src/main/httpServer.ts (68%) rename public/i18n.js => src/main/i18n.ts (75%) rename public/i18n-common.js => src/main/i18nCommon.ts (59%) rename public/electron.js => src/main/index.ts (75%) create mode 100644 src/main/isDev.ts rename public/logger.js => src/main/logger.ts (56%) rename public/menu.js => src/main/menu.ts (97%) rename public/update-checker.js => src/main/updateChecker.ts (55%) create mode 100644 src/main/util.ts create mode 100644 src/preload/index.ts rename index.html => src/renderer/index.html (100%) rename src/{ => renderer/src}/7077-magic-flow.json (100%) rename src/{ => renderer/src}/App.tsx (99%) rename src/{ => renderer/src}/BetweenSegments.tsx (100%) rename src/{ => renderer/src}/BottomBar.jsx (100%) rename src/{ => renderer/src}/ErrorBoundary.jsx (100%) rename src/{ => renderer/src}/LastCommandsSheet.tsx (100%) rename src/{ => renderer/src}/MediaSourcePlayer.tsx (97%) rename src/{ => renderer/src}/NoFileLoaded.tsx (100%) rename src/{ => renderer/src}/SegmentList.tsx (100%) rename src/{ => renderer/src}/StreamsSelector.jsx (100%) rename src/{ => renderer/src}/Timeline.tsx (100%) rename src/{ => renderer/src}/TimelineSeg.tsx (100%) rename src/{ => renderer/src}/TopMenu.tsx (100%) rename src/{ => renderer/src}/__snapshots__/edlFormats.test.ts.snap (100%) rename src/{ => renderer/src}/__snapshots__/segments.test.ts.snap (100%) rename src/{ => renderer/src}/animations.js (100%) rename src/{ => renderer/src}/colors.js (100%) rename src/{ => renderer/src}/components/AutoExportToggler.tsx (100%) rename src/{ => renderer/src}/components/BatchFile.tsx (100%) rename src/{ => renderer/src}/components/BatchFilesList.jsx (100%) rename src/{ => renderer/src}/components/BigWaveform.tsx (100%) rename src/{ => renderer/src}/components/Button.module.css (100%) rename src/{ => renderer/src}/components/Button.tsx (100%) rename src/{ => renderer/src}/components/CaptureFormatButton.tsx (100%) rename src/{ => renderer/src}/components/ConcatDialog.tsx (99%) rename src/{ => renderer/src}/components/CopyClipboardButton.tsx (100%) rename src/{ => renderer/src}/components/ExportButton.tsx (100%) rename src/{ => renderer/src}/components/ExportConfirm.module.css (100%) rename src/{ => renderer/src}/components/ExportConfirm.tsx (99%) rename src/{ => renderer/src}/components/ExportModeButton.tsx (100%) rename src/{ => renderer/src}/components/HighlightedText.tsx (100%) rename src/{ => renderer/src}/components/KeyboardShortcuts.tsx (99%) rename src/{ => renderer/src}/components/MergedOutFileName.tsx (100%) rename src/{ => renderer/src}/components/MovFastStartButton.jsx (100%) rename src/{ => renderer/src}/components/OutSegTemplateEditor.tsx (100%) rename src/{ => renderer/src}/components/OutputFormatSelect.tsx (100%) rename src/{ => renderer/src}/components/PlaybackStreamSelector.tsx (100%) rename src/{ => renderer/src}/components/PreserveMovDataButton.jsx (100%) rename src/{ => renderer/src}/components/SegmentCutpointButton.tsx (100%) rename src/{ => renderer/src}/components/Select.module.css (100%) rename src/{ => renderer/src}/components/Select.tsx (100%) rename src/{ => renderer/src}/components/SetCutpointButton.tsx (100%) rename src/{ => renderer/src}/components/Settings.module.css (100%) rename src/{ => renderer/src}/components/Settings.tsx (99%) rename src/{ => renderer/src}/components/Sheet.module.css (100%) rename src/{ => renderer/src}/components/Sheet.tsx (100%) rename src/{ => renderer/src}/components/SimpleModeButton.tsx (100%) rename src/{ => renderer/src}/components/Switch.module.css (100%) rename src/{ => renderer/src}/components/Switch.tsx (100%) rename src/{ => renderer/src}/components/TagEditor.jsx (100%) rename src/{ => renderer/src}/components/TextInput.tsx (100%) rename src/{ => renderer/src}/components/ToggleExportConfirm.tsx (100%) rename src/{ => renderer/src}/components/ValueTuner.tsx (100%) rename src/{ => renderer/src}/components/ValueTuners.tsx (95%) rename src/{ => renderer/src}/components/VolumeControl.tsx (100%) rename src/{ => renderer/src}/components/Working.tsx (100%) rename src/{ => renderer/src}/contexts.ts (100%) rename src/{ => renderer/src}/dialogs/extractFrames.jsx (100%) rename src/{ => renderer/src}/dialogs/html5ify.tsx (98%) rename src/{ => renderer/src}/dialogs/index.tsx (100%) rename src/{ => renderer/src}/dialogs/parameters.tsx (96%) rename src/{ => renderer/src}/edlFormats.test.ts (100%) rename src/{ => renderer/src}/edlFormats.ts (100%) rename src/{ => renderer/src}/edlStore.ts (100%) rename src/{ => renderer/src}/ffmpeg-parameters.js (100%) rename src/{ => renderer/src}/ffmpeg.ts (95%) rename src/{ => renderer/src}/ffprobe.js (100%) rename src/{ => renderer/src}/fixtures/DV Analyzer Summary.txt (100%) rename src/{ => renderer/src}/fixtures/FCPXML_1_9.fcpxml (100%) rename src/{ => renderer/src}/fixtures/Final Cut Pro XMEML 2.xml (100%) rename src/{ => renderer/src}/fixtures/Final Cut Pro XMEML 3.xml (100%) rename src/{ => renderer/src}/fixtures/Final Cut Pro XMEML.xml (100%) rename src/{ => renderer/src}/fixtures/mplayer.edl (100%) rename src/{ => renderer/src}/fixtures/potplayer bookmark format utf16le issue 867.pbf (100%) rename src/{ => renderer/src}/fixtures/sample.srt (100%) rename src/{ => renderer/src}/fixtures/test1.csv (100%) rename src/{ => renderer/src}/fixtures/test1.pbf (100%) rename src/{ => renderer/src}/fixtures/test2.csv (100%) rename src/{ => renderer/src}/fixtures/test2.pbf (100%) rename src/{ => renderer/src}/fixtures/test3.csv (100%) rename src/{ => renderer/src}/fixtures/test3.pbf (100%) rename src/{ => renderer/src}/hooks/normalizeWheel.ts (100%) rename src/{ => renderer/src}/hooks/useContextMenu.ts (100%) rename src/{hooks/useDirectoryAccess.js => renderer/src/hooks/useDirectoryAccess.ts} (91%) rename src/{ => renderer/src}/hooks/useFfmpegOperations.ts (98%) rename src/{ => renderer/src}/hooks/useFileFormatState.ts (100%) rename src/{ => renderer/src}/hooks/useFrameCapture.ts (96%) rename src/{ => renderer/src}/hooks/useKeyboard.ts (96%) rename src/{ => renderer/src}/hooks/useKeyframes.ts (98%) rename src/{ => renderer/src}/hooks/useNativeMenu.ts (100%) rename src/{ => renderer/src}/hooks/useSegments.ts (97%) rename src/{ => renderer/src}/hooks/useTimelineScroll.ts (100%) rename src/{ => renderer/src}/hooks/useUserSettings.ts (100%) rename src/{ => renderer/src}/hooks/useUserSettingsRoot.ts (98%) rename src/{ => renderer/src}/hooks/useWaveform.ts (98%) rename src/{ => renderer/src}/hooks/useWhatChanged.js (100%) rename src/{ => renderer/src}/i18n.ts (90%) rename src/{ => renderer/src}/icon-mac.svg (100%) rename src/{ => renderer/src}/icon.svg (100%) rename src/{ => renderer/src}/index.tsx (79%) create mode 100644 src/renderer/src/isDev.ts rename src/{ => renderer/src}/main.css (100%) rename src/{ => renderer/src}/mifi.js (100%) rename src/{ => renderer/src}/outFormats.js (100%) rename src/{reporting.jsx => renderer/src/reporting.tsx} (76%) rename src/{ => renderer/src}/segments.test.ts (100%) rename src/{ => renderer/src}/segments.ts (100%) rename src/{ => renderer/src}/smartcut.ts (98%) rename src/{ => renderer/src}/swal.ts (100%) rename src/{ => renderer/src}/theme.ts (100%) rename src/{ => renderer/src}/types.ts (95%) rename src/{ => renderer/src}/util.ts (98%) rename src/{ => renderer/src}/util/colors.ts (100%) rename src/{ => renderer/src}/util/constants.ts (100%) rename src/{ => renderer/src}/util/duration.test.ts (100%) rename src/{ => renderer/src}/util/duration.ts (100%) rename src/{ => renderer/src}/util/outputNameTemplate.ts (100%) rename src/{ => renderer/src}/util/rate-calculator.js (100%) rename src/{ => renderer/src}/util/rate-calculator.test.ts (100%) rename src/{ => renderer/src}/util/streams.test.ts (98%) rename src/{ => renderer/src}/util/streams.ts (99%) create mode 100644 tsconfig.node.json delete mode 100644 vite.config.js diff --git a/.eslintignore b/.eslintignore index 65c7365..dbdaf0f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,3 @@ /dist -/vite-dist +/out /ts-dist \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 62ce0b3..5fcf282 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -12,7 +12,7 @@ module.exports = { overrides: [ { - files: ['./src/**/*.{js,cjs,mjs,jsx,ts,tsx,mts}'], + files: ['./src/renderer/**/*.{js,cjs,mjs,jsx,ts,tsx,mts}'], env: { node: false, browser: true, @@ -22,7 +22,13 @@ module.exports = { }, }, { - files: ['./script/**/*.{js,cjs,mjs,jsx,ts,tsx,mts}', 'vite.config.js'], + files: ['./src/preload/**/*.{js,cjs,jsx,ts,tsx}'], + env: { + browser: true, + }, + }, + { + files: ['./script/**/*.{js,cjs,mjs,jsx,ts,tsx,mts}', 'electron.vite.config.js'], rules: { 'import/no-extraneous-dependencies': ['error', { devDependencies: true, diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b6a2b7..6473325 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,7 +98,7 @@ jobs: - name: (MacOS) Upload to Mac App Store if: startsWith(matrix.os, 'macos') && env.is_tag == 'true' run: | - node script/xcrun-wrapper.mjs dist/mas-universal/LosslessCut-mac-universal.pkg ${{ secrets.api_key_id }} ${{ secrets.api_key_issuer_id }} 1505323402 no.mifi.losslesscut-mac + npx tsx script/xcrun-wrapper.mts dist/mas-universal/LosslessCut-mac-universal.pkg ${{ secrets.api_key_id }} ${{ secrets.api_key_issuer_id }} 1505323402 no.mifi.losslesscut-mac - name: (MacOS) Upload artifacts uses: actions/upload-artifact@v3 diff --git a/.gitignore b/.gitignore index ccfeb8f..e658818 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,7 @@ node_modules !.yarn/versions /dist -/vite-dist +/out /icon-build /build-resources /doc diff --git a/.vscode/settings.json b/.vscode/settings.json index 5f3300c..37b0157 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { "search.exclude": { - "/public/locales/**": true, + "/src/main/locales/**": true, } } \ No newline at end of file diff --git a/README.md b/README.md index 5d93b15..1f3f501 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-

LosslessCut

+

LosslessCut

LosslessCut

The swiss army knife of lossless video/audio editing
diff --git a/cli.md b/cli.md index 42fe4d3..67ce519 100644 --- a/cli.md +++ b/cli.md @@ -26,7 +26,7 @@ LosslessCut file1.mp4 file2.mkv ``` ## Override settings (experimental) -See [available settings](https://github.com/mifi/lossless-cut/blob/master/public/configStore.js). Note that this is subject to change in newer versions. ⚠️ If you specify incorrect values it could corrupt your configuration file. You may use JSON or JSON5. Example: +See [available settings](https://github.com/mifi/lossless-cut/blob/master/src/main/configStore.js). Note that this is subject to change in newer versions. ⚠️ If you specify incorrect values it could corrupt your configuration file. You may use JSON or JSON5. Example: ```bash LosslessCut --settings-json '{captureFormat:"jpeg", "keyframeCut":true}' ``` diff --git a/developer-notes.md b/developer-notes.md index 43fee72..1345e05 100644 --- a/developer-notes.md +++ b/developer-notes.md @@ -5,10 +5,6 @@ This app is built using Electron. Make sure you have at least Node v16. The app uses ffmpeg from PATH when developing. -```bash -npm install -g yarn -``` - ```bash git clone https://github.com/mifi/lossless-cut.git cd lossless-cut diff --git a/electron.vite.config.js b/electron.vite.config.js new file mode 100644 index 0000000..a198c3c --- /dev/null +++ b/electron.vite.config.js @@ -0,0 +1,28 @@ +import { defineConfig, externalizeDepsPlugin } from 'electron-vite'; +import react from '@vitejs/plugin-react'; + + +export default defineConfig({ + main: { + // https://electron-vite.org/guide/dev#dependencies-vs-devdependencies + // For the main process and preload, the best practice is to externalize dependencies and only bundle our own code. + // However, until we use ESM for electron main, we need to include ESM-only deps in the bundle: (exclude from externalize) + plugins: [externalizeDepsPlugin({ exclude: ['p-map', 'execa', 'nanoid'] })], + }, + preload: { + // https://electron-vite.org/guide/dev#dependencies-vs-devdependencies + plugins: [externalizeDepsPlugin({ exclude: [] })], + }, + renderer: { + plugins: [react()], + build: { + chunkSizeWarningLimit: 3e6, + sourcemap: true, + }, + server: { + port: 3001, + host: '127.0.0.1', + https: false, + }, + }, +}); diff --git a/i18next-parser.config.mjs b/i18next-parser.config.mjs index 4bb1dc2..0fb603a 100644 --- a/i18next-parser.config.mjs +++ b/i18next-parser.config.mjs @@ -1,8 +1,8 @@ // eslint-disable-line unicorn/filename-case export default { - input: ['src/**/*.{js,jsx,ts,tsx}', 'public/*.{js,ts}'], + input: ['src/renderer/**/*.{js,jsx,ts,tsx}', 'src/main/*.{js,ts}'], - output: 'public/locales/$LOCALE/$NAMESPACE.json', + output: 'src/main/locales/$LOCALE/$NAMESPACE.json', indentation: 4, sort: true, @@ -16,7 +16,7 @@ export default { defaultValue: (lng, ns, key) => key, - // Keep in sync between i18next-parser.config.js and i18n-common.js: + // Keep in sync between i18next-parser.config.js and i18nCommon.js: keySeparator: false, namespaceSeparator: false, }; diff --git a/public/locales/cs/translation.json b/locales/cs/translation.json similarity index 100% rename from public/locales/cs/translation.json rename to locales/cs/translation.json diff --git a/public/locales/de/translation.json b/locales/de/translation.json similarity index 100% rename from public/locales/de/translation.json rename to locales/de/translation.json diff --git a/public/locales/en/translation.json b/locales/en/translation.json similarity index 100% rename from public/locales/en/translation.json rename to locales/en/translation.json diff --git a/public/locales/es/translation.json b/locales/es/translation.json similarity index 100% rename from public/locales/es/translation.json rename to locales/es/translation.json diff --git a/public/locales/et/translation.json b/locales/et/translation.json similarity index 100% rename from public/locales/et/translation.json rename to locales/et/translation.json diff --git a/public/locales/fa/translation.json b/locales/fa/translation.json similarity index 100% rename from public/locales/fa/translation.json rename to locales/fa/translation.json diff --git a/public/locales/fi/translation.json b/locales/fi/translation.json similarity index 100% rename from public/locales/fi/translation.json rename to locales/fi/translation.json diff --git a/public/locales/fr/translation.json b/locales/fr/translation.json similarity index 100% rename from public/locales/fr/translation.json rename to locales/fr/translation.json diff --git a/public/locales/he/translation.json b/locales/he/translation.json similarity index 100% rename from public/locales/he/translation.json rename to locales/he/translation.json diff --git a/public/locales/hu/translation.json b/locales/hu/translation.json similarity index 100% rename from public/locales/hu/translation.json rename to locales/hu/translation.json diff --git a/public/locales/id/translation.json b/locales/id/translation.json similarity index 100% rename from public/locales/id/translation.json rename to locales/id/translation.json diff --git a/public/locales/it/translation.json b/locales/it/translation.json similarity index 100% rename from public/locales/it/translation.json rename to locales/it/translation.json diff --git a/public/locales/ja/translation.json b/locales/ja/translation.json similarity index 100% rename from public/locales/ja/translation.json rename to locales/ja/translation.json diff --git a/public/locales/ko/translation.json b/locales/ko/translation.json similarity index 100% rename from public/locales/ko/translation.json rename to locales/ko/translation.json diff --git a/public/locales/lt/translation.json b/locales/lt/translation.json similarity index 100% rename from public/locales/lt/translation.json rename to locales/lt/translation.json diff --git a/public/locales/nb_NO/translation.json b/locales/nb_NO/translation.json similarity index 100% rename from public/locales/nb_NO/translation.json rename to locales/nb_NO/translation.json diff --git a/public/locales/nl/translation.json b/locales/nl/translation.json similarity index 100% rename from public/locales/nl/translation.json rename to locales/nl/translation.json diff --git a/public/locales/nn/translation.json b/locales/nn/translation.json similarity index 100% rename from public/locales/nn/translation.json rename to locales/nn/translation.json diff --git a/public/locales/pl/translation.json b/locales/pl/translation.json similarity index 100% rename from public/locales/pl/translation.json rename to locales/pl/translation.json diff --git a/public/locales/pt/translation.json b/locales/pt/translation.json similarity index 100% rename from public/locales/pt/translation.json rename to locales/pt/translation.json diff --git a/public/locales/pt_BR/translation.json b/locales/pt_BR/translation.json similarity index 100% rename from public/locales/pt_BR/translation.json rename to locales/pt_BR/translation.json diff --git a/public/locales/ro/translation.json b/locales/ro/translation.json similarity index 100% rename from public/locales/ro/translation.json rename to locales/ro/translation.json diff --git a/public/locales/ru/translation.json b/locales/ru/translation.json similarity index 100% rename from public/locales/ru/translation.json rename to locales/ru/translation.json diff --git a/public/locales/si/translation.json b/locales/si/translation.json similarity index 100% rename from public/locales/si/translation.json rename to locales/si/translation.json diff --git a/public/locales/sl/translation.json b/locales/sl/translation.json similarity index 100% rename from public/locales/sl/translation.json rename to locales/sl/translation.json diff --git a/public/locales/sr/translation.json b/locales/sr/translation.json similarity index 100% rename from public/locales/sr/translation.json rename to locales/sr/translation.json diff --git a/public/locales/sv/translation.json b/locales/sv/translation.json similarity index 100% rename from public/locales/sv/translation.json rename to locales/sv/translation.json diff --git a/public/locales/tr/translation.json b/locales/tr/translation.json similarity index 100% rename from public/locales/tr/translation.json rename to locales/tr/translation.json diff --git a/public/locales/uk/translation.json b/locales/uk/translation.json similarity index 100% rename from public/locales/uk/translation.json rename to locales/uk/translation.json diff --git a/public/locales/vi/translation.json b/locales/vi/translation.json similarity index 100% rename from public/locales/vi/translation.json rename to locales/vi/translation.json diff --git a/public/locales/zh_Hans/translation.json b/locales/zh_Hans/translation.json similarity index 100% rename from public/locales/zh_Hans/translation.json rename to locales/zh_Hans/translation.json diff --git a/public/locales/zh_Hant/translation.json b/locales/zh_Hant/translation.json similarity index 100% rename from public/locales/zh_Hant/translation.json rename to locales/zh_Hant/translation.json diff --git a/package.json b/package.json index 321280d..de479eb 100644 --- a/package.json +++ b/package.json @@ -4,31 +4,27 @@ "description": "The swiss army knife of lossless video/audio editing", "copyright": "Copyright © 2021 ${author}", "version": "3.60.0", - "main": "public/electron.js", + "main": "./out/main/index.js", "homepage": "./", "scripts": { - "dev": "concurrently -k \"npm run dev:frontend\" \"npm run dev:electron\"", - "dev:frontend": "cross-env vite --port 3001", - "dev:electron": "wait-on tcp:3001 && electron .", - "icon-gen": "mkdirp icon-build build-resources/appx && node script/icon-gen.mjs", + "clean": "rimraf dist out ts-dist build-resources icon-build", + "start": "electron-vite preview", + "dev": "electron-vite dev -w", + "icon-gen": "mkdirp icon-build build-resources/appx && tsx script/icon-gen.mts", "download-ffmpeg-darwin-x64": "mkdirp ffmpeg/darwin-x64 && cd ffmpeg/darwin-x64 && wget https://github.com/mifi/ffmpeg-build-script/releases/download/6.0-1/ffmpeg-macos-X64 -O ffmpeg && wget https://github.com/mifi/ffmpeg-build-script/releases/download/6.0-1/ffprobe-macos-X64 -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-build-script/releases/download/6.0-1/ffmpeg-macos-ARM64 -O ffmpeg && wget https://github.com/mifi/ffmpeg-build-script/releases/download/6.0-1/ffprobe-macos-ARM64 -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 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", + "build": "yarn icon-gen && electron-vite build", "tsc": "tsc --build", "test": "vitest", - "lint": "eslint --ext .js,.ts,.jsx,.tsx,.mjs .", - "pack-mac": "electron-builder --mac -m dmg", - "prepack-mac": "yarn build", - "pack-mas-dev": "electron-builder --mac -m mas-dev -c.mas.provisioningProfile=LosslessCut_Dev.provisionprofile -c.mas.identity='Apple Development: Mikael Finstad (JH4PH8B3C8)'", - "prepack-mas-dev": "yarn build", - "pack-win": "electron-builder --win", - "prepack-win": "yarn build", + "lint": "eslint --ext .js,.ts,.jsx,.tsx,.mjs,.mts .", + "pack-mac": "yarn build && electron-builder --mac -m dmg", + "pack-mas-dev": "yarn build && electron-builder --mac -m mas-dev -c.mas.provisioningProfile=LosslessCut_Dev.provisionprofile -c.mas.identity='Apple Development: Mikael Finstad (JH4PH8B3C8)'", + "pack-win": "yarn build && electron-builder --win", "postinstall": "electron-builder install-app-deps", - "version": "node script/postversion.mjs && git add no.mifi.losslesscut.appdata.xml", - "pack-linux": "electron-builder --linux", - "prepack-linux": "yarn build", + "version": "tsx script/postversion.mts && git add no.mifi.losslesscut.appdata.xml", + "pack-linux": "yarn build && electron-builder --linux", "scan-i18n": "i18next --config i18next-parser.config.mjs", "generate-licenses": "yarn licenses generate-disclaimer > licenses.txt && echo '\n\nffmpeg is licensed under GPL v2+:\n\nhttp://www.gnu.org/licenses/old-licenses/gpl-2.0.html' >> licenses.txt" }, @@ -44,29 +40,36 @@ "license": "GPL-2.0-only", "devDependencies": { "@fontsource/open-sans": "^4.5.14", + "@radix-ui/colors": "^0.1.8", "@radix-ui/react-switch": "^1.0.1", + "@tsconfig/node18": "^18.2.2", "@tsconfig/strictest": "^2.0.2", "@tsconfig/vite-react": "^3.0.0", "@types/color": "^3.0.6", "@types/css-modules": "^1.0.5", "@types/eslint": "^8", + "@types/express": "^4.17.21", "@types/lodash": "^4.14.202", + "@types/luxon": "^3.4.2", + "@types/morgan": "^1.9.9", "@types/node": "18", "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", "@types/sortablejs": "^1.15.0", + "@types/yargs-parser": "^21.0.3", "@typescript-eslint/eslint-plugin": "^6.12.0", "@typescript-eslint/parser": "^6.12.0", "@uidotdev/usehooks": "^2.4.1", "@vitejs/plugin-react": "^3.1.0", "color": "^3.1.0", "concurrently": "^6.0.0", - "cross-env": "^7.0.3", "csv-parse": "^4.15.3", "csv-stringify": "^5.6.2", + "data-uri-to-buffer": "^4.0.0", "electron": "^27.0.0", "electron-builder": "^24.6.4", "electron-devtools-installer": "^3.2.0", + "electron-vite": "^2.1.0", "eslint": "^8.2.0", "eslint-config-mifi": "^0.0.3", "eslint-plugin-import": "^2.25.3", @@ -78,7 +81,7 @@ "fast-xml-parser": "^4.2.5", "framer-motion": "^9.0.3", "i18next-parser": "^7.6.0", - "icon-gen": "^3.0.0", + "icon-gen": "^4.0.0", "immer": "^10.0.2", "ky": "^0.33.1", "luxon": "^3.3.0", @@ -97,6 +100,7 @@ "react-sortablejs": "^6.1.4", "react-syntax-highlighter": "^15.4.3", "react-use": "^17.4.0", + "rimraf": "^5.0.5", "screenfull": "^6.0.2", "scroll-into-view-if-needed": "^2.2.28", "sharp": "^0.32.6", @@ -105,28 +109,25 @@ "sweetalert2": "^11.0.0", "sweetalert2-react-content": "^5.0.7", "tiny-invariant": "^1.3.3", + "tsx": "^4.7.1", "typescript": "~5.2.0", "use-debounce": "^5.1.0", "use-trace-update": "^1.3.0", "vite": "^4.5.2", - "vitest": "^1.2.2", - "wait-on": "^7.0.1" + "vitest": "^1.2.2" }, "dependencies": { "@electron/remote": "^2.0.10", - "@radix-ui/colors": "^0.1.8", + "@octokit/core": "5", "cue-parser": "^0.3.0", - "data-uri-to-buffer": "^4.0.0", - "electron-is-dev": "^2.0.0", "electron-store": "5.1.1", "electron-unhandled": "^4.0.1", - "execa": "5", + "execa": "^8.0.1", "express": "^4.18.2", "express-async-handler": "^1.2.0", "file-type": "16", "file-url": "^3.0.0", "fs-extra": "^8.1.0", - "github-api": "^3.2.2", "i18next": "^22.4.10", "i18next-fs-backend": "^2.1.1", "json5": "^2.2.2", @@ -134,25 +135,28 @@ "mime-types": "^2.1.14", "morgan": "^1.10.0", "semver": "^7.5.2", - "string-to-stream": "^1.1.1", + "string-to-stream": "^3.0.1", "winston": "^3.8.1", - "yargs-parser": "^21.0.0" + "yargs-parser": "^21.1.1" }, "build": { "directories": { "buildResources": "build-resources" }, - "extraMetadata": { - "main": "vite-dist/electron.js" - }, "files": [ - "vite-dist/**/*" + "out/**/*" ], "asar": { "smartUnpack": false }, "appId": "no.mifi.losslesscut", "artifactName": "${productName}-${os}-${arch}.${ext}", + "extraResources": [ + { + "from": "locales", + "to": "locales" + } + ], "mac": { "hardenedRuntime": true, "appId": "no.mifi.losslesscut-mac", diff --git a/public/constants.js b/public/constants.js deleted file mode 100644 index 2d6dd7b..0000000 --- a/public/constants.js +++ /dev/null @@ -1,11 +0,0 @@ -const homepage = 'https://mifi.no/losslesscut/'; -const githubLink = 'https://github.com/mifi/lossless-cut/'; -const getReleaseUrl = (version) => `https://github.com/mifi/lossless-cut/releases/tag/v${version}`; -const licensesPage = 'https://losslesscut.mifi.no/licenses.txt'; - -module.exports = { - homepage, - getReleaseUrl, - githubLink, - licensesPage, -}; diff --git a/public/util.js b/public/util.js deleted file mode 100644 index eb11f81..0000000 --- a/public/util.js +++ /dev/null @@ -1,20 +0,0 @@ -const os = require('os'); - -const frontendBuildDir = 'vite-dist'; - -const platform = os.platform(); -const arch = os.arch(); - -// todo dedupe between renderer and main -const isWindows = platform === 'win32'; -const isMac = platform === 'darwin'; -const isLinux = platform === 'linux'; - -module.exports = { - frontendBuildDir, - isWindows, - isMac, - isLinux, - platform, - arch, -}; diff --git a/script/icon-gen.mjs b/script/icon-gen.mjs deleted file mode 100644 index ba1b0d7..0000000 --- a/script/icon-gen.mjs +++ /dev/null @@ -1,29 +0,0 @@ -// eslint-disable-line unicorn/filename-case -import sharp from 'sharp'; -import icongen from 'icon-gen'; - -const svg2png = (from, to, width, height) => sharp(from) - .png() - .resize(width, height, { - fit: sharp.fit.contain, - background: { r: 0, g: 0, b: 0, alpha: 0 }, - }) - .toFile(to); - -// Linux: -await svg2png('src/icon.svg', './icon-build/app-512.png', 512, 512); - -// Windows Store -await svg2png('src/icon.svg', './build-resources/appx/StoreLogo.png', 50, 50); -await svg2png('src/icon.svg', './build-resources/appx/Square150x150Logo.png', 300, 300); -await svg2png('src/icon.svg', './build-resources/appx/Square44x44Logo.png', 44, 44); -await svg2png('src/icon.svg', './build-resources/appx/Wide310x150Logo.png', 620, 300); - -// MacOS: -// https://github.com/mifi/lossless-cut/issues/1820 -await icongen('./src/icon-mac.svg', './icon-build', { icns: { sizes: [512, 1024] } }); - -// Windows ICO: -// https://github.com/mifi/lossless-cut/issues/778 -// https://stackoverflow.com/questions/3236115/which-icon-sizes-should-my-windows-applications-icon-include -await icongen('./src/icon.svg', './icon-build', { ico: { sizes: [16, 24, 32, 40, 48, 64, 96, 128, 256, 512] } }); diff --git a/script/icon-gen.mts b/script/icon-gen.mts new file mode 100644 index 0000000..6064b79 --- /dev/null +++ b/script/icon-gen.mts @@ -0,0 +1,32 @@ +// eslint-disable-line unicorn/filename-case +import sharp from 'sharp'; +import icongenRaw from 'icon-gen'; + +const icongen = icongenRaw as unknown as typeof icongenRaw['default']; + +const svg2png = (from: string, to: string, width: number, height: number) => sharp(from) + .png() + .resize(width, height, { + fit: sharp.fit.contain, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toFile(to); + +const srcIcon = 'src/renderer/src/icon.svg'; +// Linux: +await svg2png(srcIcon, './icon-build/app-512.png', 512, 512); + +// Windows Store +await svg2png(srcIcon, './build-resources/appx/StoreLogo.png', 50, 50); +await svg2png(srcIcon, './build-resources/appx/Square150x150Logo.png', 300, 300); +await svg2png(srcIcon, './build-resources/appx/Square44x44Logo.png', 44, 44); +await svg2png(srcIcon, './build-resources/appx/Wide310x150Logo.png', 620, 300); + +// MacOS: +// https://github.com/mifi/lossless-cut/issues/1820 +await icongen('./src/renderer/src/icon-mac.svg', './icon-build', { icns: { sizes: [512, 1024] }, report: false }); + +// Windows ICO: +// https://github.com/mifi/lossless-cut/issues/778 +// https://stackoverflow.com/questions/3236115/which-icon-sizes-should-my-windows-applications-icon-include +await icongen(srcIcon, './icon-build', { ico: { sizes: [16, 24, 32, 40, 48, 64, 96, 128, 256, 512] }, report: false }); diff --git a/script/postversion.mjs b/script/postversion.mts similarity index 91% rename from script/postversion.mjs rename to script/postversion.mts index 6d0d0b3..5c0fd4e 100644 --- a/script/postversion.mjs +++ b/script/postversion.mts @@ -1,12 +1,11 @@ import { readFile, writeFile } from 'fs/promises'; import { XMLParser, XMLBuilder } from 'fast-xml-parser'; -// eslint-disable-next-line import/no-unresolved import { DateTime } from 'luxon'; const xmlUrl = new URL('../no.mifi.losslesscut.appdata.xml', import.meta.url); const xmlData = await readFile(xmlUrl); -const packageJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url))); +const packageJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url)) as unknown as string); const parser = new XMLParser({ alwaysCreateTextNode: true, ignoreAttributes: false, ignoreDeclaration: false }); const xml = parser.parse(xmlData); diff --git a/script/xcrun-wrapper.mjs b/script/xcrun-wrapper.mts similarity index 87% rename from script/xcrun-wrapper.mjs rename to script/xcrun-wrapper.mts index 1c3c6e5..0a28d7c 100644 --- a/script/xcrun-wrapper.mjs +++ b/script/xcrun-wrapper.mts @@ -1,5 +1,5 @@ // eslint-disable-line unicorn/filename-case -import execa from 'execa'; +import { execa } from 'execa'; import { readFile } from 'fs/promises'; // we need a wrapper script because altool tends to error out very often @@ -17,7 +17,7 @@ const bundleId = args[4]; // seems to be the same const ascPublicId = apiIssuer; -const packageJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url))); +const packageJson = JSON.parse(await readFile(new URL('../package.json', import.meta.url)) as unknown as string); console.log('Using version', packageJson.version); @@ -74,8 +74,11 @@ async function runAttempt() { console.log('stdout', stdout); return false; } catch (err) { - if (err.exitCode === 1 && err.stdout) { - const errorJson = JSON.parse(err.stdout); + if (err instanceof Error && 'exitCode' in err && err.exitCode === 1 && 'stdout' in err && err.stdout && typeof err.stdout === 'string') { + const errorJson = JSON.parse(err.stdout) as unknown; + if (!(errorJson != null && typeof errorJson === 'object' && 'product-errors' in errorJson && Array.isArray(errorJson['product-errors']))) { + throw new TypeError('Invalid JSON'); + } const productErrors = errorJson['product-errors']; // Unable to authenticate if (productErrors.some((error) => error.code === -19209)) { diff --git a/src/isDev.ts b/src/isDev.ts deleted file mode 100644 index b62ee03..0000000 --- a/src/isDev.ts +++ /dev/null @@ -1,3 +0,0 @@ -const { isDev }: { isDev: boolean } = window.require('@electron/remote').require('./electron'); - -export default isDev; diff --git a/public/compatPlayer.js b/src/main/compatPlayer.ts similarity index 54% rename from public/compatPlayer.js rename to src/main/compatPlayer.ts index 016d928..3883265 100644 --- a/public/compatPlayer.js +++ b/src/main/compatPlayer.ts @@ -1,8 +1,12 @@ -const logger = require('./logger'); -const { createMediaSourceProcess, readOneJpegFrame } = require('./ffmpeg'); +import assert from 'assert'; + +import logger from './logger.js'; +import { createMediaSourceProcess, readOneJpegFrame as readOneJpegFrameRaw } from './ffmpeg.js'; -function createMediaSourceStream({ path, videoStreamIndex, audioStreamIndex, seekTo, size, fps }) { +export function createMediaSourceStream({ path, videoStreamIndex, audioStreamIndex, seekTo, size, fps }: { + path: string, videoStreamIndex?: number | undefined, audioStreamIndex?: number | undefined, seekTo: number, size?: number | undefined, fps?: number | undefined, +}) { const abortController = new AbortController(); logger.info('Starting preview process', { videoStreamIndex, audioStreamIndex, seekTo }); const process = createMediaSourceProcess({ path, videoStreamIndex, audioStreamIndex, seekTo, size, fps }); @@ -13,38 +17,39 @@ function createMediaSourceStream({ path, videoStreamIndex, audioStreamIndex, see process.kill('SIGKILL'); }; - process.stdout.pause(); + const { stdout } = process; + assert(stdout != null); - async function readChunk() { - return new Promise((resolve, reject) => { - let cleanup; + stdout.pause(); - const onClose = () => { - cleanup(); - resolve(null); - }; - const onData = (chunk) => { - process.stdout.pause(); - cleanup(); - resolve(chunk); - }; - const onError = (err) => { - cleanup(); - reject(err); - }; - cleanup = () => { - process.stdout.off('data', onData); - process.stdout.off('error', onError); - process.stdout.off('close', onClose); - }; + const readChunk = async () => new Promise((resolve, reject) => { + let cleanup: () => void; - process.stdout.once('data', onData); - process.stdout.once('error', onError); - process.stdout.once('close', onClose); + const onClose = () => { + cleanup(); + resolve(null); + }; + const onData = (chunk: Buffer) => { + stdout.pause(); + cleanup(); + resolve(chunk); + }; + const onError = (err: Error) => { + cleanup(); + reject(err); + }; + cleanup = () => { + stdout.off('data', onData); + stdout.off('error', onError); + stdout.off('close', onClose); + }; - process.stdout.resume(); - }); - } + stdout.once('data', onData); + stdout.once('error', onError); + stdout.once('close', onClose); + + stdout.resume(); + }); function abort() { abortController.abort(); @@ -75,9 +80,9 @@ function createMediaSourceStream({ path, videoStreamIndex, audioStreamIndex, see return { abort, readChunk }; } -function readOneJpegFrameWrapper({ path, seekTo, videoStreamIndex }) { +export function readOneJpegFrame({ path, seekTo, videoStreamIndex }: { path: string, seekTo: number, videoStreamIndex: number }) { const abortController = new AbortController(); - const process = readOneJpegFrame({ path, seekTo, videoStreamIndex }); + const process = readOneJpegFrameRaw({ path, seekTo, videoStreamIndex }); // eslint-disable-next-line unicorn/prefer-add-event-listener abortController.signal.onabort = () => process.kill('SIGKILL'); @@ -99,9 +104,3 @@ function readOneJpegFrameWrapper({ path, seekTo, videoStreamIndex }) { return { promise, abort }; } - - -module.exports = { - createMediaSourceStream, - readOneJpegFrame: readOneJpegFrameWrapper, -}; diff --git a/public/configStore.js b/src/main/configStore.ts similarity index 89% rename from public/configStore.js rename to src/main/configStore.ts index 6e77d67..76e24a5 100644 --- a/public/configStore.js +++ b/src/main/configStore.ts @@ -1,17 +1,17 @@ -const Store = require('electron-store'); +import Store from 'electron-store'; // eslint-disable-next-line import/no-extraneous-dependencies -const electron = require('electron'); -const os = require('os'); -const { join, dirname } = require('path'); -const { pathExists } = require('fs-extra'); +import electron from 'electron'; +import { join, dirname } from 'path'; +import { pathExists } from 'fs-extra'; -const logger = require('./logger'); +import { KeyBinding, Config } from '../../types.js'; +import logger from './logger.js'; +import { isWindows } from './util.js'; const { app } = electron; -/** @type {import('../types').KeyBinding[]} */ -const defaultKeyBindings = [ +const defaultKeyBindings: KeyBinding[] = [ { keys: 'plus', action: 'addSegment' }, { keys: 'space', action: 'togglePlayResetSpeed' }, { keys: 'k', action: 'togglePlayNoResetSpeed' }, @@ -83,8 +83,7 @@ const defaultKeyBindings = [ { keys: 'alt+down', action: 'decreaseVolume' }, ]; -/** @type {import('../types').Config} */ -const defaults = { +const defaults: Config = { captureFormat: 'jpeg', customOutDir: undefined, keyframeCut: true, @@ -145,7 +144,6 @@ const defaults = { // For portable app: https://github.com/mifi/lossless-cut/issues/645 async function getCustomStoragePath() { try { - const isWindows = os.platform() === 'win32'; if (!isWindows || process.windowsStore) return undefined; // https://github.com/mifi/lossless-cut/issues/645#issuecomment-1001363314 @@ -161,28 +159,28 @@ async function getCustomStoragePath() { } } -let store; +let store: Store; -/** @type {import('../types').StoreGetConfig} */ -function get(key) { +export function get(key: T): Config[T] { return store.get(key); } -/** @type {import('../types').StoreSetConfig} */ -function set(key, val) { +export function set(key: T, val: Config[T]) { if (val === undefined) store.delete(key); else store.set(key, val); } -/** @type {import('../types').StoreResetConfig} */ -function reset(key) { +export function reset(key: T) { set(key, defaults[key]); } -async function tryCreateStore({ customStoragePath }) { +async function tryCreateStore({ customStoragePath }: { customStoragePath: string | undefined }) { for (let i = 0; i < 5; i += 1) { try { - store = new Store({ defaults, cwd: customStoragePath }); + store = new Store({ + defaults, + ...(customStoragePath != null ? { cwd: customStoragePath } : {}), + }); return; } catch (err) { // eslint-disable-next-line no-await-in-loop @@ -194,7 +192,7 @@ async function tryCreateStore({ customStoragePath }) { throw new Error('Timed out while creating config store'); } -async function init() { +export async function init() { const customStoragePath = await getCustomStoragePath(); if (customStoragePath) logger.info('customStoragePath', customStoragePath); @@ -214,10 +212,3 @@ async function init() { set('cleanupChoices', { ...cleanupChoices, closeFile: true }); } } - -module.exports = { - init, - get, - set, - reset, -}; diff --git a/src/main/constants.ts b/src/main/constants.ts new file mode 100644 index 0000000..23c2c9f --- /dev/null +++ b/src/main/constants.ts @@ -0,0 +1,4 @@ +export const homepage = 'https://mifi.no/losslesscut/'; +export const githubLink = 'https://github.com/mifi/lossless-cut/'; +export const getReleaseUrl = (version: string) => `https://github.com/mifi/lossless-cut/releases/tag/v${version}`; +export const licensesPage = 'https://losslesscut.mifi.no/licenses.txt'; diff --git a/public/contextMenu.js b/src/main/contextMenu.ts similarity index 81% rename from public/contextMenu.js rename to src/main/contextMenu.ts index 6aadef5..d757085 100644 --- a/public/contextMenu.js +++ b/src/main/contextMenu.ts @@ -1,8 +1,8 @@ // eslint-disable-next-line import/no-extraneous-dependencies -const { Menu } = require('electron'); +import { BrowserWindow, Menu } from 'electron'; // https://github.com/electron/electron/issues/4068#issuecomment-274159726 -module.exports = (window) => { +export default (window: BrowserWindow) => { const selectionMenu = Menu.buildFromTemplate([ { role: 'copy' }, { type: 'separator' }, @@ -23,9 +23,9 @@ module.exports = (window) => { window.webContents.on('context-menu', (_e, props) => { const { selectionText, isEditable } = props; if (isEditable) { - inputMenu.popup(window); + inputMenu.popup({ window }); } else if (selectionText && selectionText.trim() !== '') { - selectionMenu.popup(window); + selectionMenu.popup({ window }); } }); }; diff --git a/public/ffmpeg.js b/src/main/ffmpeg.ts similarity index 57% rename from public/ffmpeg.js rename to src/main/ffmpeg.ts index 5115681..3d68d7c 100644 --- a/public/ffmpeg.js +++ b/src/main/ffmpeg.ts @@ -1,53 +1,60 @@ -const { join } = require('path'); -const isDev = require('electron-is-dev'); -const readline = require('readline'); -const stringToStream = require('string-to-stream'); -const execa = require('execa'); +import { join } from 'path'; +import readline from 'readline'; +import stringToStream from 'string-to-stream'; +import { BufferEncodingOption, execa, ExecaChildProcess, Options as ExecaOptions } from 'execa'; +import assert from 'assert'; +import { Readable } from 'stream'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { app } from 'electron'; -const { platform, arch, isWindows, isMac, isLinux } = require('./util'); +import { platform, arch, isWindows, isMac, isLinux } from './util.js'; +import { CaptureFormat, Html5ifyMode, Waveform } from '../../types.js'; +import isDev from './isDev.js'; -const runningFfmpegs = new Set(); +const runningFfmpegs = new Set>(); // setInterval(() => console.log(runningFfmpegs.size), 1000); -let customFfPath; +let customFfPath: string | undefined; // Note that this does not work on MAS because of sandbox restrictions -function setCustomFfPath(path) { +export function setCustomFfPath(path: string | undefined) { customFfPath = path; } -function getFfCommandLine(cmd, args) { +export function getFfCommandLine(cmd: string, args: readonly string[]) { return `${cmd} ${args.map((arg) => (/[^\w-]/.test(arg) ? `'${arg}'` : arg)).join(' ')}`; } -function getFfPath(cmd) { +function getFfPath(cmd: string) { const exeName = isWindows ? `${cmd}.exe` : cmd; if (customFfPath) return join(customFfPath, exeName); - if (isDev) { - const components = ['ffmpeg', `${platform}-${arch}`]; - if (isWindows || isLinux) components.push('lib'); - components.push(exeName); - return join(...components); + if (app.isPackaged) { + return join(process.resourcesPath, exeName); } - return join(process.resourcesPath, exeName); + // local dev + const components = ['ffmpeg', `${platform}-${arch}`]; + if (isWindows || isLinux) components.push('lib'); + components.push(exeName); + return join(...components); } const getFfprobePath = () => getFfPath('ffprobe'); -const getFfmpegPath = () => getFfPath('ffmpeg'); +export const getFfmpegPath = () => getFfPath('ffmpeg'); -function abortFfmpegs() { +export function abortFfmpegs() { console.log('Aborting', runningFfmpegs.size, 'ffmpeg process(es)'); runningFfmpegs.forEach((process) => { process.kill('SIGTERM', { forceKillAfterTimeout: 10000 }); }); } -function handleProgress(process, durationIn, onProgress, customMatcher = () => undefined) { +function handleProgress(process: { stderr: Readable | null }, durationIn: number | undefined, onProgress: (a: number) => void, customMatcher: (a: string) => void = () => undefined) { if (!onProgress) return; + if (process.stderr == null) return; onProgress(0); const rl = readline.createInterface({ input: process.stderr }); @@ -61,20 +68,19 @@ function handleProgress(process, durationIn, onProgress, customMatcher = () => u // eslint-disable-next-line unicorn/better-regex if (!match) match = line.match(/(?:size|Lsize)=\s*[^\s]+\s+time=\s*([^\s]+)\s+/); if (!match) { - // @ts-expect-error todo customMatcher(line); return; } const timeStr = match[1]; // console.log(timeStr); - const match2 = timeStr.match(/^(\d+):(\d+):(\d+)\.(\d+)$/); + const match2 = timeStr!.match(/^(\d+):(\d+):(\d+)\.(\d+)$/); if (!match2) throw new Error(`Invalid time from ffmpeg progress ${timeStr}`); - const h = parseInt(match2[1], 10); - const m = parseInt(match2[2], 10); - const s = parseInt(match2[3], 10); - const cs = parseInt(match2[4], 10); + const h = parseInt(match2[1]!, 10); + const m = parseInt(match2[2]!, 10); + const s = parseInt(match2[3]!, 10); + const cs = parseInt(match2[4]!, 10); const time = (((h * 60) + m) * 60 + s) + cs / 100; // console.log(time); @@ -93,18 +99,22 @@ function handleProgress(process, durationIn, onProgress, customMatcher = () => u }); } -// @ts-expect-error todo -function getExecaOptions({ env, ...customExecaOptions } = {}) { - const execaOptions = { ...customExecaOptions, env: { ...env } }; +function getExecaOptions({ env, ...customExecaOptions }: Omit, 'buffer'> = {}) { + const execaOptions: Omit, 'buffer'> = { ...customExecaOptions, encoding: 'buffer' }; // https://github.com/mifi/lossless-cut/issues/1143#issuecomment-1500883489 - if (isLinux && !isDev && !customFfPath) execaOptions.env.LD_LIBRARY_PATH = process.resourcesPath; + if (isLinux && !isDev && !customFfPath) { + return { + ...execaOptions, + env: { ...env, LD_LIBRARY_PATH: process.resourcesPath }, + }; + } return execaOptions; } // todo collect warnings from ffmpeg output and show them after export? example: https://github.com/mifi/lossless-cut/issues/1469 -function runFfmpegProcess(args, customExecaOptions, { logCli = true } = {}) { +function runFfmpegProcess(args: readonly string[], customExecaOptions?: Omit, 'encoding'>, additionalOptions?: { logCli?: boolean }) { const ffmpegPath = getFfmpegPath(); - if (logCli) console.log(getFfCommandLine('ffmpeg', args)); + if (additionalOptions?.logCli) console.log(getFfCommandLine('ffmpeg', args)); const process = execa(ffmpegPath, args, getExecaOptions(customExecaOptions)); @@ -121,23 +131,29 @@ function runFfmpegProcess(args, customExecaOptions, { logCli = true } = {}) { return process; } -async function runFfmpegConcat({ ffmpegArgs, concatTxt, totalDuration, onProgress }) { +export async function runFfmpegConcat({ ffmpegArgs, concatTxt, totalDuration, onProgress }: { + ffmpegArgs: string[], concatTxt: string, totalDuration: number, onProgress: (a: number) => void +}) { const process = runFfmpegProcess(ffmpegArgs); handleProgress(process, totalDuration, onProgress); + assert(process.stdin != null); stringToStream(concatTxt).pipe(process.stdin); return process; } -async function runFfmpegWithProgress({ ffmpegArgs, duration, onProgress }) { +export async function runFfmpegWithProgress({ ffmpegArgs, duration, onProgress }: { + ffmpegArgs: string[], duration: number | undefined, onProgress: (a: number) => void, +}) { const process = runFfmpegProcess(ffmpegArgs); + assert(process.stderr != null); handleProgress(process, duration, onProgress); return process; } -async function runFfprobe(args, { timeout = isDev ? 10000 : 30000 } = {}) { +export async function runFfprobe(args: readonly string[], { timeout = isDev ? 10000 : 30000 } = {}) { const ffprobePath = getFfprobePath(); console.log(getFfCommandLine('ffprobe', args)); const ps = execa(ffprobePath, args, getExecaOptions()); @@ -152,13 +168,14 @@ async function runFfprobe(args, { timeout = isDev ? 10000 : 30000 } = {}) { } } -/** @type {(a: any) => Promise} */ -async function renderWaveformPng({ filePath, start, duration, color, streamIndex }) { +export async function renderWaveformPng({ filePath, start, duration, color, streamIndex }: { + filePath: string, start: number, duration: number, color: string, streamIndex: number, +}): Promise { const args1 = [ '-hide_banner', '-i', filePath, - '-ss', start, - '-t', duration, + '-ss', String(start), + '-t', String(duration), '-c', 'copy', '-vn', '-map', `0:${streamIndex}`, @@ -179,16 +196,18 @@ async function renderWaveformPng({ filePath, start, duration, color, streamIndex console.log(getFfCommandLine('ffmpeg1', args1)); console.log('|', getFfCommandLine('ffmpeg2', args2)); - let ps1; - let ps2; + let ps1: ExecaChildProcess | undefined; + let ps2: ExecaChildProcess | undefined; try { - ps1 = runFfmpegProcess(args1, { encoding: null, buffer: false }, { logCli: false }); - ps2 = runFfmpegProcess(args2, { encoding: null }, { logCli: false }); + ps1 = runFfmpegProcess(args1, { buffer: false }, { logCli: false }); + ps2 = runFfmpegProcess(args2, undefined, { logCli: false }); + assert(ps1.stdout != null); + assert(ps2.stdin != null); ps1.stdout.pipe(ps2.stdin); const timer = setTimeout(() => { - ps1.kill(); - ps2.kill(); + ps1?.kill(); + ps2?.kill(); console.warn('ffmpeg timed out'); }, 10000); @@ -209,14 +228,14 @@ async function renderWaveformPng({ filePath, start, duration, color, streamIndex } } -const getInputSeekArgs = ({ filePath, from, to }) => [ +const getInputSeekArgs = ({ filePath, from, to }: { filePath: string, from?: number | undefined, to?: number | undefined }) => [ ...(from != null ? ['-ss', from.toFixed(5)] : []), '-i', filePath, - ...(to != null ? ['-t', (to - from).toFixed(5)] : []), + ...(from != null && to != null ? ['-t', (to - from).toFixed(5)] : []), ]; -function mapTimesToSegments(times) { - const segments = []; +export function mapTimesToSegments(times: number[]) { + const segments: { start: number, end: number | undefined }[] = []; for (let i = 0; i < times.length; i += 1) { const start = times[i]; const end = times[i + 1]; @@ -225,32 +244,35 @@ function mapTimesToSegments(times) { return segments; } -const getSegmentOffset = (from) => (from != null ? from : 0); +const getSegmentOffset = (from?: number) => (from != null ? from : 0); -function adjustSegmentsWithOffset({ segments, from }) { +function adjustSegmentsWithOffset({ segments, from }: { segments: { start: number, end: number | undefined }[], from?: number | undefined }) { const offset = getSegmentOffset(from); return segments.map(({ start, end }) => ({ start: start + offset, end: end != null ? end + offset : end })); } // https://stackoverflow.com/questions/35675529/using-ffmpeg-how-to-do-a-scene-change-detection-with-timecode -async function detectSceneChanges({ filePath, minChange, onProgress, from, to }) { +export async function detectSceneChanges({ filePath, minChange, onProgress, from, to }: { + filePath: string, minChange: number | string, onProgress: (p: number) => void, from: number, to: number, +}) { const args = [ '-hide_banner', ...getInputSeekArgs({ filePath, from, to }), '-filter_complex', `select='gt(scene,${minChange})',metadata=print:file=-`, '-f', 'null', '-', ]; - const process = runFfmpegProcess(args, { encoding: null, buffer: false }); + const process = runFfmpegProcess(args, { buffer: false }); const times = [0]; handleProgress(process, to - from, onProgress); + assert(process.stdout != null); const rl = readline.createInterface({ input: process.stdout }); rl.on('line', (line) => { // eslint-disable-next-line unicorn/better-regex const match = line.match(/^frame:\d+\s+pts:\d+\s+pts_time:([\d.]+)/); if (!match) return; - const time = parseFloat(match[1]); + const time = parseFloat(match[1]!); // @ts-expect-error todo if (Number.isNaN(time) || time <= times.at(-1)) return; times.push(time); @@ -263,89 +285,134 @@ async function detectSceneChanges({ filePath, minChange, onProgress, from, to }) return adjustSegmentsWithOffset({ segments, from }); } -async function detectIntervals({ filePath, customArgs, onProgress, from, to, matchLineTokens }) { +async function detectIntervals({ filePath, customArgs, onProgress, from, to, matchLineTokens }: { + filePath: string, customArgs: string[], onProgress: (p: number) => void, from: number, to: number, matchLineTokens: (line: string) => { start?: string | number | undefined, end?: string | number | undefined }, +}) { const args = [ '-hide_banner', ...getInputSeekArgs({ filePath, from, to }), ...customArgs, '-f', 'null', '-', ]; - const process = runFfmpegProcess(args, { encoding: null, buffer: false }); + const process = runFfmpegProcess(args, { buffer: false }); - const segments = []; + const segments: { start: number, end: number }[] = []; - function customMatcher(line) { - const { start: startStr, end: endStr } = matchLineTokens(line); - const start = parseFloat(startStr); - const end = parseFloat(endStr); - if (start == null || end == null || Number.isNaN(start) || Number.isNaN(end)) return; - segments.push({ start, end }); + function customMatcher(line: string) { + const { start: startRaw, end: endRaw } = matchLineTokens(line); + if (typeof startRaw === 'number' && typeof endRaw === 'number') { + if (startRaw == null || endRaw == null) return; + if (Number.isNaN(startRaw) || Number.isNaN(endRaw)) return; + segments.push({ start: startRaw, end: endRaw }); + } else if (typeof startRaw === 'string' && typeof endRaw === 'string') { + if (startRaw == null || endRaw == null) return; + const start = parseFloat(startRaw); + const end = parseFloat(endRaw); + if (Number.isNaN(start) || Number.isNaN(end)) return; + segments.push({ start, end }); + } else { + throw new TypeError('Invalid line match'); + } } - // @ts-expect-error todo handleProgress(process, to - from, onProgress, customMatcher); await process; return adjustSegmentsWithOffset({ segments, from }); } -const mapFilterOptions = (options) => Object.entries(options).map(([key, value]) => `${key}=${value}`).join(':'); +const mapFilterOptions = (options: Record) => Object.entries(options).map(([key, value]) => `${key}=${value}`).join(':'); -async function blackDetect({ filePath, filterOptions, onProgress, from, to }) { - function matchLineTokens(line) { - // eslint-disable-next-line unicorn/better-regex - const match = line.match(/^[blackdetect\s*@\s*0x[0-9a-f]+] black_start:([\d\\.]+) black_end:([\d\\.]+) black_duration:[\d\\.]+/); - if (!match) return {}; - return { - start: parseFloat(match[1]), - end: parseFloat(match[2]), - }; - } +export async function blackDetect({ filePath, filterOptions, onProgress, from, to }: { filePath: string, filterOptions: Record, onProgress: (p: number) => void, from: number, to: number }) { const customArgs = ['-vf', `blackdetect=${mapFilterOptions(filterOptions)}`, '-an']; - return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs }); + return detectIntervals({ + filePath, + onProgress, + from, + to, + matchLineTokens: (line) => { + // eslint-disable-next-line unicorn/better-regex + const match = line.match(/^[blackdetect\s*@\s*0x[0-9a-f]+] black_start:([\d\\.]+) black_end:([\d\\.]+) black_duration:[\d\\.]+/); + if (!match) { + return { + start: undefined, + end: undefined, + }; + } + return { + start: match[1], + end: match[2], + }; + }, + customArgs, + }); } -async function silenceDetect({ filePath, filterOptions, onProgress, from, to }) { - function matchLineTokens(line) { - // eslint-disable-next-line unicorn/better-regex - const match = line.match(/^[silencedetect\s*@\s*0x[0-9a-f]+] silence_end: ([\d\\.]+)[|\s]+silence_duration: ([\d\\.]+)/); - if (!match) return {}; - const end = parseFloat(match[1]); - const silenceDuration = parseFloat(match[2]); - if (Number.isNaN(end) || Number.isNaN(silenceDuration)) return {}; - const start = end - silenceDuration; - if (start < 0 || end <= 0 || start >= end) return {}; - return { - start, - end, - }; - } - const customArgs = ['-af', `silencedetect=${mapFilterOptions(filterOptions)}`, '-vn']; - return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs }); +export async function silenceDetect({ filePath, filterOptions, onProgress, from, to }: { + filePath: string, filterOptions: Record, onProgress: (p: number) => void, from: number, to: number, +}) { + return detectIntervals({ + filePath, + onProgress, + from, + to, + matchLineTokens: (line) => { + // eslint-disable-next-line unicorn/better-regex + const match = line.match(/^[silencedetect\s*@\s*0x[0-9a-f]+] silence_end: ([\d\\.]+)[|\s]+silence_duration: ([\d\\.]+)/); + if (!match) { + return { + start: undefined, + end: undefined, + }; + } + const end = parseFloat(match[1]!); + const silenceDuration = parseFloat(match[2]!); + if (Number.isNaN(end) || Number.isNaN(silenceDuration)) { + return { + start: undefined, + end: undefined, + }; + } + const start = end - silenceDuration; + if (start < 0 || end <= 0 || start >= end) { + return { + start: undefined, + end: undefined, + }; + } + return { + start, + end, + }; + }, + customArgs: ['-af', `silencedetect=${mapFilterOptions(filterOptions)}`, '-vn'], + }); } -function getFffmpegJpegQuality(quality) { +function getFffmpegJpegQuality(quality: number) { // Normal range for JPEG is 2-31 with 31 being the worst quality. const qMin = 2; const qMax = 31; return Math.min(Math.max(qMin, quality, Math.round((1 - quality) * (qMax - qMin) + qMin)), qMax); } -function getQualityOpts({ captureFormat, quality }) { - if (captureFormat === 'jpeg') return ['-q:v', getFffmpegJpegQuality(quality)]; - if (captureFormat === 'webp') return ['-q:v', Math.max(0, Math.min(100, Math.round(quality * 100)))]; +function getQualityOpts({ captureFormat, quality }: { captureFormat: CaptureFormat, quality: number }) { + if (captureFormat === 'jpeg') return ['-q:v', String(getFffmpegJpegQuality(quality))]; + if (captureFormat === 'webp') return ['-q:v', String(Math.max(0, Math.min(100, Math.round(quality * 100))))]; return []; } -function getCodecOpts(captureFormat) { +function getCodecOpts(captureFormat: CaptureFormat) { if (captureFormat === 'webp') return ['-c:v', 'libwebp']; // else we get only a single file for webp https://github.com/mifi/lossless-cut/issues/1693 return []; } -async function captureFrames({ from, to, videoPath, outPathTemplate, quality, filter, framePts, onProgress, captureFormat }) { +export async function captureFrames({ from, to, videoPath, outPathTemplate, quality, filter, framePts, onProgress, captureFormat }: { + from: number, to: number, videoPath: string, outPathTemplate: string, quality: number, filter?: string | undefined, framePts?: boolean | undefined, onProgress: (p: number) => void, captureFormat: CaptureFormat, +}) { const args = [ - '-ss', from, + '-ss', String(from), '-i', videoPath, - '-t', Math.max(0, to - from), + '-t', String(Math.max(0, to - from)), ...getQualityOpts({ captureFormat, quality }), ...(filter != null ? ['-vf', filter] : []), // https://superuser.com/questions/1336285/use-ffmpeg-for-thumbnail-selections @@ -356,39 +423,43 @@ async function captureFrames({ from, to, videoPath, outPathTemplate, quality, fi '-y', outPathTemplate, ]; - const process = runFfmpegProcess(args, { encoding: null, buffer: false }); + const process = runFfmpegProcess(args, { buffer: false }); handleProgress(process, to - from, onProgress); await process; } -async function captureFrame({ timestamp, videoPath, outPath, quality }) { +export async function captureFrame({ timestamp, videoPath, outPath, quality }: { + timestamp: number, videoPath: string, outPath: string, quality: number, +}) { const ffmpegQuality = getFffmpegJpegQuality(quality); await runFfmpegProcess([ - '-ss', timestamp, + '-ss', String(timestamp), '-i', videoPath, '-vframes', '1', - '-q:v', ffmpegQuality, + '-q:v', String(ffmpegQuality), '-y', outPath, ]); } -async function readFormatData(filePath) { +async function readFormatData(filePath: string) { console.log('readFormatData', filePath); const { stdout } = await runFfprobe([ '-of', 'json', '-show_format', '-i', filePath, '-hide_banner', ]); - return JSON.parse(stdout).format; + return JSON.parse(stdout as unknown as string).format; } -async function getDuration(filePath) { +export async function getDuration(filePath: string) { return parseFloat((await readFormatData(filePath)).duration); } -async function html5ify({ outPath, filePath: filePathArg, speed, hasAudio, hasVideo, onProgress }) { +export async function html5ify({ outPath, filePath: filePathArg, speed, hasAudio, hasVideo, onProgress }: { + outPath: string, filePath: string, speed: Html5ifyMode, hasAudio: boolean, hasVideo: boolean, onProgress: (p: number) => void, +}) { let audio; if (hasAudio) { if (speed === 'slowest') audio = 'hq'; @@ -492,14 +563,14 @@ async function html5ify({ outPath, filePath: filePathArg, speed, hasAudio, hasVi if (duration) handleProgress(process, duration, onProgress); const { stdout } = await process; - console.log(stdout); + console.log(stdout.toString('utf8')); } -function readOneJpegFrame({ path, seekTo, videoStreamIndex }) { +export function readOneJpegFrame({ path, seekTo, videoStreamIndex }: { path: string, seekTo: number, videoStreamIndex: number }) { const args = [ '-hide_banner', '-loglevel', 'error', - '-ss', seekTo, + '-ss', String(seekTo), '-noautorotate', @@ -516,17 +587,19 @@ function readOneJpegFrame({ path, seekTo, videoStreamIndex }) { // console.log(args); - return runFfmpegProcess(args, { encoding: 'buffer' }, { logCli: true }); + return runFfmpegProcess(args, undefined, { logCli: true }); } const enableLog = false; const encode = true; -function createMediaSourceProcess({ path, videoStreamIndex, audioStreamIndex, seekTo, size, fps }) { +export function createMediaSourceProcess({ path, videoStreamIndex, audioStreamIndex, seekTo, size, fps }: { + path: string, videoStreamIndex?: number | undefined, audioStreamIndex?: number | undefined, seekTo: number, size?: number | undefined, fps?: number | undefined, +}) { function getVideoFilters() { if (videoStreamIndex == null) return []; - const filters = []; + const filters: string[] = []; if (fps != null) filters.push(`fps=${fps}`); if (size != null) filters.push(`scale=${size}:${size}:flags=lanczos:force_original_aspect_ratio=decrease`); if (filters.length === 0) return []; @@ -547,7 +620,7 @@ function createMediaSourceProcess({ path, videoStreamIndex, audioStreamIndex, se '-vsync', 'passthrough', - '-ss', seekTo, + '-ss', String(seekTo), '-noautorotate', @@ -582,27 +655,5 @@ function createMediaSourceProcess({ path, videoStreamIndex, audioStreamIndex, se return execa(getFfmpegPath(), args, { encoding: null, buffer: false, stderr: enableLog ? 'inherit' : 'pipe' }); } -// Don't pass complex objects over the bridge -const runFfmpeg = async (...args) => runFfmpegProcess(...args); - -module.exports = { - setCustomFfPath, - abortFfmpegs, - getFfmpegPath, - runFfprobe, - runFfmpeg, - runFfmpegConcat, - runFfmpegWithProgress, - renderWaveformPng, - mapTimesToSegments, - detectSceneChanges, - captureFrames, - captureFrame, - getFfCommandLine, - html5ify, - getDuration, - readOneJpegFrame, - blackDetect, - silenceDetect, - createMediaSourceProcess, -}; +// Don't pass complex objects over the bridge (process) +export const runFfmpeg = async (...args: Parameters) => runFfmpegProcess(...args); diff --git a/public/httpServer.js b/src/main/httpServer.ts similarity index 68% rename from public/httpServer.js rename to src/main/httpServer.ts index dcb8bd9..2ce4a5e 100644 --- a/public/httpServer.js +++ b/src/main/httpServer.ts @@ -1,14 +1,16 @@ -const express = require('express'); -const morgan = require('morgan'); -const http = require('http'); -const asyncHandler = require('express-async-handler'); -const { homepage } = require('./constants'); +import express from 'express'; +import morgan from 'morgan'; +import http from 'http'; +import asyncHandler from 'express-async-handler'; +import assert from 'assert'; + +import { homepage } from './constants.js'; +import logger from './logger.js'; -const logger = require('./logger'); - - -module.exports = ({ port, onKeyboardAction }) => { +export default ({ port, onKeyboardAction }: { + port: number, onKeyboardAction: (a: string) => Promise, +}) => { const app = express(); // https://expressjs.com/en/resources/middleware/morgan.html @@ -25,7 +27,10 @@ module.exports = ({ port, onKeyboardAction }) => { app.use('/api', apiRouter); apiRouter.post('/shortcuts/:action', express.json(), asyncHandler(async (req, res) => { - await onKeyboardAction(req.params.action); + // eslint-disable-next-line prefer-destructuring + const action = req.params['action']; + assert(action != null); + await onKeyboardAction(action); res.end(); })); diff --git a/public/i18n.js b/src/main/i18n.ts similarity index 75% rename from public/i18n.js rename to src/main/i18n.ts index b13c8d9..12417aa 100644 --- a/public/i18n.js +++ b/src/main/i18n.ts @@ -1,12 +1,12 @@ -const i18n = require('i18next'); -const Backend = require('i18next-fs-backend'); +import i18n from 'i18next'; +import Backend from 'i18next-fs-backend'; -const { commonI18nOptions, loadPath, addPath } = require('./i18n-common'); +import { commonI18nOptions, loadPath, addPath } from './i18nCommon.js'; // See also renderer // https://github.com/i18next/i18next/issues/869 -i18n +export default i18n .use(Backend) // detect user language // learn more: https://github.com/i18next/i18next-browser-languageDetector @@ -23,5 +23,3 @@ i18n addPath, }, }); - -module.exports = i18n; diff --git a/public/i18n-common.js b/src/main/i18nCommon.ts similarity index 59% rename from public/i18n-common.js rename to src/main/i18nCommon.ts index ef091ce..3738ab1 100644 --- a/public/i18n-common.js +++ b/src/main/i18nCommon.ts @@ -1,28 +1,26 @@ -// eslint-disable-line unicorn/filename-case // intentionally disabled because I don't know the quality of the languages, so better to default to english // const LanguageDetector = window.require('i18next-electron-language-detector'); -const isDev = require('electron-is-dev'); // eslint-disable-next-line import/no-extraneous-dependencies -const { app } = require('electron'); -const { join } = require('path'); +import { app } from 'electron'; +import { join } from 'path'; +import { InitOptions } from 'i18next'; -const { frontendBuildDir } = require('./util'); -let customLocalesPath; -function setCustomLocalesPath(p) { +let customLocalesPath: string | undefined; +export function setCustomLocalesPath(p: string) { customLocalesPath = p; } -function getLangPath(subPath) { +function getLangPath(subPath: string) { if (customLocalesPath != null) return join(customLocalesPath, subPath); - if (isDev) return join('public', subPath); - return join(app.getAppPath(), frontendBuildDir, subPath); + if (app.isPackaged) return join(process.resourcesPath, 'locales', subPath); + return join('locales', subPath); } // Weblate hardcodes different lang codes than electron // https://www.electronjs.org/docs/api/app#appgetlocale // https://source.chromium.org/chromium/chromium/src/+/master:ui/base/l10n/l10n_util.cc -const mapLang = (lng) => ({ +const mapLang = (lng: string) => ({ nb: 'nb_NO', no: 'nb_NO', zh: 'zh_Hans', @@ -39,29 +37,21 @@ const mapLang = (lng) => ({ 'ru-RU': 'ru', }[lng] || lng); -const fallbackLng = 'en'; +export const fallbackLng = 'en'; -const commonI18nOptions = { +export const commonI18nOptions: InitOptions = { fallbackLng, // debug: isDev, // saveMissing: isDev, // updateMissing: isDev, // saveMissingTo: 'all', - // Keep in sync between i18next-parser.config.js and i18n-common.js: + // Keep in sync between i18next-parser.config.js and i18nCommon.js: // TODO improve keys? // Maybe do something like this: https://stackoverflow.com/a/19405314/6519037 keySeparator: false, nsSeparator: false, }; -const loadPath = (lng, ns) => getLangPath(`locales/${mapLang(lng)}/${ns}.json`); -const addPath = (lng, ns) => getLangPath(`locales/${mapLang(lng)}/${ns}.missing.json`); - -module.exports = { - fallbackLng, - loadPath, - addPath, - commonI18nOptions, - setCustomLocalesPath, -}; +export const loadPath = (lng: string, ns: string) => getLangPath(`${mapLang(lng)}/${ns}.json`); +export const addPath = (lng: string, ns: string) => getLangPath(`${mapLang(lng)}/${ns}.missing.json`); diff --git a/public/electron.js b/src/main/index.ts similarity index 75% rename from public/electron.js rename to src/main/index.ts index a6444b9..2b406cc 100644 --- a/public/electron.js +++ b/src/main/index.ts @@ -1,31 +1,55 @@ +/// process.traceDeprecation = true; process.traceProcessWarnings = true; +/* eslint-disable import/first */ // eslint-disable-next-line import/no-extraneous-dependencies -const electron = require('electron'); -const isDev = require('electron-is-dev'); -const unhandled = require('electron-unhandled'); -const i18n = require('i18next'); -const debounce = require('lodash/debounce'); -const yargsParser = require('yargs-parser'); -const JSON5 = require('json5'); -const remote = require('@electron/remote/main'); -const { stat } = require('fs/promises'); +import electron, { AboutPanelOptionsOptions, BrowserWindow, BrowserWindowConstructorOptions, nativeTheme, shell, app, ipcMain } from 'electron'; +import unhandled from 'electron-unhandled'; +import i18n from 'i18next'; +import debounce from 'lodash/debounce'; +import yargsParser from 'yargs-parser'; +import JSON5 from 'json5'; +import remote from '@electron/remote/main'; +import { stat } from 'fs/promises'; +import assert from 'assert'; -const logger = require('./logger'); -const menu = require('./menu'); -const configStore = require('./configStore'); -const { frontendBuildDir, isLinux } = require('./util'); -const attachContextMenu = require('./contextMenu'); -const HttpServer = require('./httpServer'); +import logger from './logger.js'; +import menu from './menu.js'; +import * as configStore from './configStore.js'; +import { isLinux } from './util.js'; +import attachContextMenu from './contextMenu.js'; +import HttpServer from './httpServer.js'; +import isDev from './isDev.js'; -const { checkNewVersion } = require('./update-checker'); +import { checkNewVersion } from './updateChecker.js'; -const i18nCommon = require('./i18n-common'); +import * as i18nCommon from './i18nCommon.js'; -require('./i18n'); +import './i18n.js'; +import { ApiKeyboardActionRequest } from '../../types.js'; -const { app, ipcMain, shell, BrowserWindow, nativeTheme } = electron; +export * as ffmpeg from './ffmpeg.js'; + +export * as i18n from './i18nCommon.js'; + +export * as compatPlayer from './compatPlayer.js'; + +export * as configStore from './configStore.js'; + +export { isLinux, isWindows, isMac, platform } from './util.js'; + + +// https://www.i18next.com/overview/typescript#argument-of-type-defaulttfuncreturn-is-not-assignable-to-parameter-of-type-xyz +// todo This should not be necessary anymore since v23.0.0 +declare module 'i18next' { + interface CustomTypeOptions { + returnNull: false; + } +} + +// eslint-disable-next-line unicorn/prefer-export-from +export { isDev }; // https://chromestatus.com/feature/5748496434987008 // https://peter.sh/experiments/chromium-command-line-switches/ @@ -49,8 +73,7 @@ const isStoreBuild = process.windowsStore || process.mas; const showVersion = !isStoreBuild; -/** @type import('electron').AboutPanelOptionsOptions */ -const aboutPanelOptions = { +const aboutPanelOptions: AboutPanelOptionsOptions = { applicationName: appName, copyright: `Copyright © ${copyrightYear} Mikael Finstad ❤️ 🇳🇴`, version: '', // not very useful (MacOS only, and same as applicationVersion) @@ -69,28 +92,28 @@ if (!showVersion) { // https://www.electronjs.org/docs/latest/api/app#appsetaboutpaneloptionsoptions app.setAboutPanelOptions(aboutPanelOptions); -let filesToOpen = []; +let filesToOpen: string[] = []; // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. -let mainWindow; +let mainWindow: BrowserWindow | null; let askBeforeClose = false; let rendererReady = false; -let newVersion; -let disableNetworking; +let newVersion: string | undefined; +let disableNetworking: boolean; -const openFiles = (paths) => mainWindow.webContents.send('openFiles', paths); +const openFiles = (paths: string[]) => mainWindow!.webContents.send('openFiles', paths); let apiKeyboardActionRequestsId = 0; -const apiKeyboardActionRequests = new Map(); +const apiKeyboardActionRequests = new Map void>(); -async function sendApiKeyboardAction(action) { +async function sendApiKeyboardAction(action: string) { try { const id = apiKeyboardActionRequestsId; apiKeyboardActionRequestsId += 1; - mainWindow.webContents.send('apiKeyboardAction', { id, action }); - await new Promise((resolve) => { + mainWindow!.webContents.send('apiKeyboardAction', { id, action } satisfies ApiKeyboardActionRequest); + await new Promise((resolve) => { apiKeyboardActionRequests.set(id, resolve); }); } catch (err) { @@ -101,7 +124,7 @@ async function sendApiKeyboardAction(action) { // https://github.com/electron/electron/issues/526#issuecomment-563010533 function getSizeOptions() { const bounds = configStore.get('windowBounds'); - const options = {}; + const options: BrowserWindowConstructorOptions = {}; if (bounds) { const area = electron.screen.getDisplayMatching(bounds).workArea; // If the saved position still valid (the window is entirely inside the display area), use it. @@ -147,7 +170,7 @@ function createWindow() { 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`); + else mainWindow.loadFile('out/renderer/index.html'); // Open the DevTools. // mainWindow.webContents.openDevTools() @@ -164,6 +187,7 @@ function createWindow() { mainWindow.on('close', (e) => { if (!askBeforeClose) return; + assert(mainWindow); const choice = electron.dialog.showMessageBoxSync(mainWindow, { type: 'question', buttons: ['Yes', 'No'], @@ -186,10 +210,11 @@ function createWindow() { } function updateMenu() { + assert(mainWindow); menu({ app, mainWindow, newVersion, isStoreBuild }); } -function openFilesEventually(paths) { +function openFilesEventually(paths: string[]) { if (rendererReady) openFiles(paths); else filesToOpen = paths; } @@ -201,18 +226,18 @@ function openFilesEventually(paths) { function parseCliArgs(rawArgv = process.argv) { const ignoreFirstArgs = process.defaultApp ? 2 : 1; // production: First arg is the LosslessCut executable - // dev: First 2 args are electron and the electron.js + // dev: First 2 args are electron and the index.js const argsWithoutAppName = rawArgv.length > ignoreFirstArgs ? rawArgv.slice(ignoreFirstArgs) : []; - return yargsParser(argsWithoutAppName, { boolean: ['allow-multiple-instances', 'disable-networking'] }); + return yargsParser(argsWithoutAppName, { boolean: ['allow-multiple-instances', 'disable-networking'], string: ['settings-json'] }); } const argv = parseCliArgs(); -if (argv.localesPath != null) i18nCommon.setCustomLocalesPath(argv.localesPath); +if (argv['localesPath'] != null) i18nCommon.setCustomLocalesPath(argv['localesPath']); -function safeRequestSingleInstanceLock(additionalData) { +function safeRequestSingleInstanceLock(additionalData: Record) { if (process.mas) return true; // todo remove when fixed https://github.com/electron/electron/issues/35540 // using additionalData because the built in "argv" passing is a bit broken: @@ -232,16 +257,14 @@ function initApp() { mainWindow.focus(); } - // @ts-expect-error todo - if (!Array.isArray(additionalData?.argv)) return; + if (!(additionalData != null && typeof additionalData === 'object' && 'argv' in additionalData) || !Array.isArray(additionalData.argv)) return; - // @ts-expect-error todo const argv2 = parseCliArgs(additionalData.argv); logger.info('second-instance', argv2); - if (argv2._ && argv2._.length > 0) openFilesEventually(argv2._); - else if (argv2.keyboardAction) sendApiKeyboardAction(argv2.keyboardAction); + if (argv2._ && argv2._.length > 0) openFilesEventually(argv2._.map(String)); + else if (argv2['keyboardAction']) sendApiKeyboardAction(argv2['keyboardAction']); }); // Quit when all windows are closed. @@ -322,7 +345,7 @@ const readyPromise = app.whenReady(); logger.info('CLI arguments', argv); // Only if no files to open already (open-file might have already added some files) - if (filesToOpen.length === 0) filesToOpen = argv._; + if (filesToOpen.length === 0) filesToOpen = argv._.map(String); const { settingsJson } = argv; ({ disableNetworking } = argv); @@ -330,6 +353,7 @@ const readyPromise = app.whenReady(); if (settingsJson != null) { logger.info('initializing settings', settingsJson); Object.entries(JSON5.parse(settingsJson)).forEach(([key, value]) => { + // @ts-expect-error todo use zod? configStore.set(key, value); }); } @@ -340,6 +364,7 @@ const readyPromise = app.whenReady(); const port = typeof httpApi === 'number' ? httpApi : 8080; const { startHttpServer } = HttpServer({ port, onKeyboardAction: sendApiKeyboardAction }); await startHttpServer(); + logger.info('HTTP API listening on port', port); } @@ -347,8 +372,8 @@ const readyPromise = app.whenReady(); const { default: installExtension, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer'); // eslint-disable-line global-require,import/no-extraneous-dependencies installExtension(REACT_DEVELOPER_TOOLS) - .then((name) => logger.info('Added Extension', name)) - .catch((err) => logger.error('Failed to add extension', err)); + .then((name: string) => logger.info('Added Extension', name)) + .catch((err: unknown) => logger.error('Failed to add extension', err)); } createWindow(); @@ -366,7 +391,7 @@ const readyPromise = app.whenReady(); } })(); -function focusWindow() { +export function focusWindow() { try { app.focus({ steal: true }); } catch (err) { @@ -374,10 +399,8 @@ function focusWindow() { } } -function quitApp() { +export function quitApp() { electron.app.quit(); } -const hasDisabledNetworking = () => !!disableNetworking; - -module.exports = { focusWindow, isDev, hasDisabledNetworking, quitApp }; +export const hasDisabledNetworking = () => !!disableNetworking; diff --git a/src/main/isDev.ts b/src/main/isDev.ts new file mode 100644 index 0000000..bd7448b --- /dev/null +++ b/src/main/isDev.ts @@ -0,0 +1,2 @@ +const isDev = import.meta.env.MODE === 'development'; +export default isDev; diff --git a/public/logger.js b/src/main/logger.ts similarity index 56% rename from public/logger.js rename to src/main/logger.ts index a436abf..fafeab2 100644 --- a/public/logger.js +++ b/src/main/logger.ts @@ -1,15 +1,18 @@ -const winston = require('winston'); -const util = require('util'); -const isDev = require('electron-is-dev'); +import winston from 'winston'; +import util from 'util'; // eslint-disable-next-line import/no-extraneous-dependencies -const { app } = require('electron'); -const { join } = require('path'); +import { app } from 'electron'; +import { join } from 'path'; +// eslint-disable-next-line import/no-extraneous-dependencies +import type { TransformableInfo } from 'logform'; + // https://mifi.no/blog/winston-electron-logger/ // https://github.com/winstonjs/winston/issues/1427 const combineMessageAndSplat = () => ({ - transform(info) { + transform(info: TransformableInfo) { + // @ts-expect-error todo const { [Symbol.for('splat')]: args = [], message } = info; // eslint-disable-next-line no-param-reassign info.message = util.format(message, ...args); @@ -21,14 +24,14 @@ const createLogger = () => winston.createLogger({ format: winston.format.combine( winston.format.timestamp(), combineMessageAndSplat(), - winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`), + winston.format.printf((info) => `${info['timestamp']} ${info.level}: ${info.message}`), ), }); -const logDirPath = isDev ? '.' : app.getPath('userData'); +const logDirPath = app.isPackaged ? app.getPath('userData') : '.'; const logger = createLogger(); logger.add(new winston.transports.File({ level: 'debug', filename: join(logDirPath, 'app.log'), options: { flags: 'a' } })); -if (isDev) logger.add(new winston.transports.Console()); +if (!app.isPackaged) logger.add(new winston.transports.Console()); -module.exports = logger; +export default logger; diff --git a/public/menu.js b/src/main/menu.ts similarity index 97% rename from public/menu.js rename to src/main/menu.ts index 2cd15ac..7dbdda7 100644 --- a/public/menu.js +++ b/src/main/menu.ts @@ -1,16 +1,19 @@ // eslint-disable-next-line import/no-extraneous-dependencies -const electron = require('electron'); -const { t } = require('i18next'); +import electron, { BrowserWindow } from 'electron'; +import { t } from 'i18next'; + +import { homepage, getReleaseUrl, licensesPage } from './constants.js'; + // menu-safe i18n.t: // https://github.com/mifi/lossless-cut/issues/1456 -const esc = (val) => val.replaceAll('&', '&&'); +const esc = (val: string) => val.replaceAll('&', '&&'); const { Menu } = electron; -const { homepage, getReleaseUrl, licensesPage } = require('./constants'); - -module.exports = ({ app, mainWindow, newVersion, isStoreBuild }) => { +export default ({ app, mainWindow, newVersion, isStoreBuild }: { + app: Electron.App, mainWindow: BrowserWindow, newVersion?: string | undefined, isStoreBuild: boolean, +}) => { const menu = [ ...(process.platform === 'darwin' ? [{ role: 'appMenu' }] : []), diff --git a/public/update-checker.js b/src/main/updateChecker.ts similarity index 55% rename from public/update-checker.js rename to src/main/updateChecker.ts index 95fe75f..a761e73 100644 --- a/public/update-checker.js +++ b/src/main/updateChecker.ts @@ -1,24 +1,33 @@ -// eslint-disable-line unicorn/filename-case -const GitHub = require('github-api'); // eslint-disable-next-line import/no-extraneous-dependencies -const electron = require('electron'); -const semver = require('semver'); +import electron from 'electron'; +import semver from 'semver'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { Octokit } from '@octokit/core'; -const logger = require('./logger'); +import logger from './logger.js'; const { app } = electron; -const gh = new GitHub(); -const repo = gh.getRepo('mifi', 'lossless-cut'); +const octokit = new Octokit(); -async function checkNewVersion() { + +// eslint-disable-next-line import/prefer-default-export +export async function checkNewVersion() { try { // From API: https://developer.github.com/v3/repos/releases/#get-the-latest-release // View the latest published full release for the repository. // Draft releases and prereleases are not returned by this endpoint. - const res = (await repo.getRelease('latest')).data; - const newestVersion = res.tag_name.replace(/^v?/, ''); + + const { data } = await octokit.request('GET /repos/{owner}/{repo}/releases/latest', { + owner: 'mifi', + repo: 'lossless-cut', + headers: { + 'X-GitHub-Api-Version': '2022-11-28', + }, + }); + + const newestVersion = data.tag_name.replace(/^v?/, ''); const currentVersion = app.getVersion(); // const currentVersion = '3.17.2'; @@ -34,5 +43,3 @@ async function checkNewVersion() { return undefined; } } - -module.exports = { checkNewVersion }; diff --git a/src/main/util.ts b/src/main/util.ts new file mode 100644 index 0000000..75724c9 --- /dev/null +++ b/src/main/util.ts @@ -0,0 +1,8 @@ +import os from 'os'; + +export const platform = os.platform(); +export const arch = os.arch(); + +export const isWindows = platform === 'win32'; +export const isMac = platform === 'darwin'; +export const isLinux = platform === 'linux'; diff --git a/src/preload/index.ts b/src/preload/index.ts new file mode 100644 index 0000000..07d67e5 --- /dev/null +++ b/src/preload/index.ts @@ -0,0 +1,2 @@ +// todo +console.log('preload'); diff --git a/index.html b/src/renderer/index.html similarity index 100% rename from index.html rename to src/renderer/index.html diff --git a/src/7077-magic-flow.json b/src/renderer/src/7077-magic-flow.json similarity index 100% rename from src/7077-magic-flow.json rename to src/renderer/src/7077-magic-flow.json diff --git a/src/App.tsx b/src/renderer/src/App.tsx similarity index 99% rename from src/App.tsx rename to src/renderer/src/App.tsx index d2eb2b8..9b323ca 100644 --- a/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -86,9 +86,9 @@ import { rightBarWidth, leftBarWidth, ffmpegExtractWindow, zoomMax } from './uti import BigWaveform from './components/BigWaveform'; import isDev from './isDev'; -import { ChromiumHTMLVideoElement, EdlFileType, FfmpegCommandLog, FormatTimecode, Html5ifyMode, PlaybackMode, SegmentColorIndex, SegmentTags, SegmentToExport, StateSegment, Thumbnail, TunerType } from './types'; -import { CaptureFormat, KeyboardAction } from '../types'; -import { FFprobeChapter, FFprobeFormat, FFprobeStream } from '../ffprobe'; +import { ChromiumHTMLVideoElement, EdlFileType, FfmpegCommandLog, FormatTimecode, PlaybackMode, SegmentColorIndex, SegmentTags, SegmentToExport, StateSegment, Thumbnail, TunerType } from './types'; +import { CaptureFormat, KeyboardAction, Html5ifyMode } from '../../../types'; +import { FFprobeChapter, FFprobeFormat, FFprobeStream } from '../../../ffprobe'; const electron = window.require('electron'); const { exists } = window.require('fs-extra'); @@ -96,8 +96,7 @@ const { lstat } = window.require('fs/promises'); const filePathToUrl = window.require('file-url'); const { parse: parsePath, join: pathJoin, basename, dirname } = window.require('path'); -const remote = window.require('@electron/remote'); -const { focusWindow, hasDisabledNetworking, quitApp } = remote.require('./electron'); +const { focusWindow, hasDisabledNetworking, quitApp } = window.require('@electron/remote').require('./index.js'); const videoStyle: CSSProperties = { width: '100%', height: '100%', objectFit: 'contain' }; @@ -1338,8 +1337,10 @@ function App() { return; } - if ('stdout' in err) console.error('stdout:', err.stdout); - if ('stderr' in err) console.error('stderr:', err.stderr); + // @ts-expect-error todo + if ('stdout' in err && err.stdout != null) console.error('stdout:', err.stdout.toString('utf8')); + // @ts-expect-error todo + if ('stderr' in err && err.stderr != null) console.error('stderr:', err.stderr.toString('utf8')); if (isExecaFailure(err)) { if (isOutOfSpaceError(err)) { diff --git a/src/BetweenSegments.tsx b/src/renderer/src/BetweenSegments.tsx similarity index 100% rename from src/BetweenSegments.tsx rename to src/renderer/src/BetweenSegments.tsx diff --git a/src/BottomBar.jsx b/src/renderer/src/BottomBar.jsx similarity index 100% rename from src/BottomBar.jsx rename to src/renderer/src/BottomBar.jsx diff --git a/src/ErrorBoundary.jsx b/src/renderer/src/ErrorBoundary.jsx similarity index 100% rename from src/ErrorBoundary.jsx rename to src/renderer/src/ErrorBoundary.jsx diff --git a/src/LastCommandsSheet.tsx b/src/renderer/src/LastCommandsSheet.tsx similarity index 100% rename from src/LastCommandsSheet.tsx rename to src/renderer/src/LastCommandsSheet.tsx diff --git a/src/MediaSourcePlayer.tsx b/src/renderer/src/MediaSourcePlayer.tsx similarity index 97% rename from src/MediaSourcePlayer.tsx rename to src/renderer/src/MediaSourcePlayer.tsx index 8f8ac3e..e254021 100644 --- a/src/MediaSourcePlayer.tsx +++ b/src/renderer/src/MediaSourcePlayer.tsx @@ -4,10 +4,9 @@ import { useDebounce } from 'use-debounce'; import isDev from './isDev'; import { ChromiumHTMLVideoElement } from './types'; -import { FFprobeStream } from '../ffprobe'; +import { FFprobeStream } from '../../../ffprobe'; -const remote = window.require('@electron/remote'); -const { createMediaSourceStream, readOneJpegFrame } = remote.require('./compatPlayer'); +const { compatPlayer: { createMediaSourceStream, readOneJpegFrame } } = window.require('@electron/remote').require('./index.js'); async function startPlayback({ path, video, videoStreamIndex, audioStreamIndex, seekTo, signal, playSafe, onCanPlay, getTargetTime, size, fps }: { @@ -231,7 +230,7 @@ async function startPlayback({ path, video, videoStreamIndex, audioStreamIndex, processChunk(); } -function drawJpegFrame(canvas: HTMLCanvasElement, jpegImage: Buffer) { +function drawJpegFrame(canvas: HTMLCanvasElement | null, jpegImage: Buffer) { if (!canvas) return; const ctx = canvas.getContext('2d'); @@ -248,7 +247,9 @@ function drawJpegFrame(canvas: HTMLCanvasElement, jpegImage: Buffer) { img.src = `data:image/jpeg;base64,${jpegImage.toString('base64')}`; } -async function createPauseImage({ path, seekTo, videoStreamIndex, canvas, signal }) { +async function createPauseImage({ path, seekTo, videoStreamIndex, canvas, signal }: { + path: string, seekTo: number, videoStreamIndex: number, canvas: HTMLCanvasElement | null, signal: AbortSignal, +}) { const { promise, abort } = readOneJpegFrame({ path, seekTo, videoStreamIndex }); signal.addEventListener('abort', () => abort()); const jpegImage = await promise; diff --git a/src/NoFileLoaded.tsx b/src/renderer/src/NoFileLoaded.tsx similarity index 100% rename from src/NoFileLoaded.tsx rename to src/renderer/src/NoFileLoaded.tsx diff --git a/src/SegmentList.tsx b/src/renderer/src/SegmentList.tsx similarity index 100% rename from src/SegmentList.tsx rename to src/renderer/src/SegmentList.tsx diff --git a/src/StreamsSelector.jsx b/src/renderer/src/StreamsSelector.jsx similarity index 100% rename from src/StreamsSelector.jsx rename to src/renderer/src/StreamsSelector.jsx diff --git a/src/Timeline.tsx b/src/renderer/src/Timeline.tsx similarity index 100% rename from src/Timeline.tsx rename to src/renderer/src/Timeline.tsx diff --git a/src/TimelineSeg.tsx b/src/renderer/src/TimelineSeg.tsx similarity index 100% rename from src/TimelineSeg.tsx rename to src/renderer/src/TimelineSeg.tsx diff --git a/src/TopMenu.tsx b/src/renderer/src/TopMenu.tsx similarity index 100% rename from src/TopMenu.tsx rename to src/renderer/src/TopMenu.tsx diff --git a/src/__snapshots__/edlFormats.test.ts.snap b/src/renderer/src/__snapshots__/edlFormats.test.ts.snap similarity index 100% rename from src/__snapshots__/edlFormats.test.ts.snap rename to src/renderer/src/__snapshots__/edlFormats.test.ts.snap diff --git a/src/__snapshots__/segments.test.ts.snap b/src/renderer/src/__snapshots__/segments.test.ts.snap similarity index 100% rename from src/__snapshots__/segments.test.ts.snap rename to src/renderer/src/__snapshots__/segments.test.ts.snap diff --git a/src/animations.js b/src/renderer/src/animations.js similarity index 100% rename from src/animations.js rename to src/renderer/src/animations.js diff --git a/src/colors.js b/src/renderer/src/colors.js similarity index 100% rename from src/colors.js rename to src/renderer/src/colors.js diff --git a/src/components/AutoExportToggler.tsx b/src/renderer/src/components/AutoExportToggler.tsx similarity index 100% rename from src/components/AutoExportToggler.tsx rename to src/renderer/src/components/AutoExportToggler.tsx diff --git a/src/components/BatchFile.tsx b/src/renderer/src/components/BatchFile.tsx similarity index 100% rename from src/components/BatchFile.tsx rename to src/renderer/src/components/BatchFile.tsx diff --git a/src/components/BatchFilesList.jsx b/src/renderer/src/components/BatchFilesList.jsx similarity index 100% rename from src/components/BatchFilesList.jsx rename to src/renderer/src/components/BatchFilesList.jsx diff --git a/src/components/BigWaveform.tsx b/src/renderer/src/components/BigWaveform.tsx similarity index 100% rename from src/components/BigWaveform.tsx rename to src/renderer/src/components/BigWaveform.tsx diff --git a/src/components/Button.module.css b/src/renderer/src/components/Button.module.css similarity index 100% rename from src/components/Button.module.css rename to src/renderer/src/components/Button.module.css diff --git a/src/components/Button.tsx b/src/renderer/src/components/Button.tsx similarity index 100% rename from src/components/Button.tsx rename to src/renderer/src/components/Button.tsx diff --git a/src/components/CaptureFormatButton.tsx b/src/renderer/src/components/CaptureFormatButton.tsx similarity index 100% rename from src/components/CaptureFormatButton.tsx rename to src/renderer/src/components/CaptureFormatButton.tsx diff --git a/src/components/ConcatDialog.tsx b/src/renderer/src/components/ConcatDialog.tsx similarity index 99% rename from src/components/ConcatDialog.tsx rename to src/renderer/src/components/ConcatDialog.tsx index 06e437b..2f0e3bc 100644 --- a/src/components/ConcatDialog.tsx +++ b/src/renderer/src/components/ConcatDialog.tsx @@ -14,7 +14,7 @@ import OutputFormatSelect from './OutputFormatSelect'; import useUserSettings from '../hooks/useUserSettings'; import { isMov } from '../util/streams'; import { getOutFileExtension, getSuffixedFileName } from '../util'; -import { FFprobeChapter, FFprobeFormat, FFprobeStream } from '../../ffprobe'; +import { FFprobeChapter, FFprobeFormat, FFprobeStream } from '../../../../ffprobe'; const { basename } = window.require('path'); diff --git a/src/components/CopyClipboardButton.tsx b/src/renderer/src/components/CopyClipboardButton.tsx similarity index 100% rename from src/components/CopyClipboardButton.tsx rename to src/renderer/src/components/CopyClipboardButton.tsx diff --git a/src/components/ExportButton.tsx b/src/renderer/src/components/ExportButton.tsx similarity index 100% rename from src/components/ExportButton.tsx rename to src/renderer/src/components/ExportButton.tsx diff --git a/src/components/ExportConfirm.module.css b/src/renderer/src/components/ExportConfirm.module.css similarity index 100% rename from src/components/ExportConfirm.module.css rename to src/renderer/src/components/ExportConfirm.module.css diff --git a/src/components/ExportConfirm.tsx b/src/renderer/src/components/ExportConfirm.tsx similarity index 99% rename from src/components/ExportConfirm.tsx rename to src/renderer/src/components/ExportConfirm.tsx index 991492d..56ef360 100644 --- a/src/components/ExportConfirm.tsx +++ b/src/renderer/src/components/ExportConfirm.tsx @@ -26,8 +26,8 @@ import useUserSettings from '../hooks/useUserSettings'; import styles from './ExportConfirm.module.css'; import { InverseCutSegment, SegmentToExport } from '../types'; import { GenerateOutSegFileNames } from '../util/outputNameTemplate'; -import { FFprobeStream } from '../../ffprobe'; -import { AvoidNegativeTs } from '../../types'; +import { FFprobeStream } from '../../../../ffprobe'; +import { AvoidNegativeTs } from '../../../../types'; const boxStyle: CSSProperties = { margin: '15px 15px 50px 15px', borderRadius: 10, padding: '10px 20px', minHeight: 500, position: 'relative' }; diff --git a/src/components/ExportModeButton.tsx b/src/renderer/src/components/ExportModeButton.tsx similarity index 100% rename from src/components/ExportModeButton.tsx rename to src/renderer/src/components/ExportModeButton.tsx diff --git a/src/components/HighlightedText.tsx b/src/renderer/src/components/HighlightedText.tsx similarity index 100% rename from src/components/HighlightedText.tsx rename to src/renderer/src/components/HighlightedText.tsx diff --git a/src/components/KeyboardShortcuts.tsx b/src/renderer/src/components/KeyboardShortcuts.tsx similarity index 99% rename from src/components/KeyboardShortcuts.tsx rename to src/renderer/src/components/KeyboardShortcuts.tsx index 34a65f2..0071f9d 100644 --- a/src/components/KeyboardShortcuts.tsx +++ b/src/renderer/src/components/KeyboardShortcuts.tsx @@ -12,7 +12,7 @@ import Swal from '../swal'; import SetCutpointButton from './SetCutpointButton'; import SegmentCutpointButton from './SegmentCutpointButton'; import { getModifier } from '../hooks/useTimelineScroll'; -import { KeyBinding, KeyboardAction } from '../../types'; +import { KeyBinding, KeyboardAction } from '../../../../types'; import { StateSegment } from '../types'; diff --git a/src/components/MergedOutFileName.tsx b/src/renderer/src/components/MergedOutFileName.tsx similarity index 100% rename from src/components/MergedOutFileName.tsx rename to src/renderer/src/components/MergedOutFileName.tsx diff --git a/src/components/MovFastStartButton.jsx b/src/renderer/src/components/MovFastStartButton.jsx similarity index 100% rename from src/components/MovFastStartButton.jsx rename to src/renderer/src/components/MovFastStartButton.jsx diff --git a/src/components/OutSegTemplateEditor.tsx b/src/renderer/src/components/OutSegTemplateEditor.tsx similarity index 100% rename from src/components/OutSegTemplateEditor.tsx rename to src/renderer/src/components/OutSegTemplateEditor.tsx diff --git a/src/components/OutputFormatSelect.tsx b/src/renderer/src/components/OutputFormatSelect.tsx similarity index 100% rename from src/components/OutputFormatSelect.tsx rename to src/renderer/src/components/OutputFormatSelect.tsx diff --git a/src/components/PlaybackStreamSelector.tsx b/src/renderer/src/components/PlaybackStreamSelector.tsx similarity index 100% rename from src/components/PlaybackStreamSelector.tsx rename to src/renderer/src/components/PlaybackStreamSelector.tsx diff --git a/src/components/PreserveMovDataButton.jsx b/src/renderer/src/components/PreserveMovDataButton.jsx similarity index 100% rename from src/components/PreserveMovDataButton.jsx rename to src/renderer/src/components/PreserveMovDataButton.jsx diff --git a/src/components/SegmentCutpointButton.tsx b/src/renderer/src/components/SegmentCutpointButton.tsx similarity index 100% rename from src/components/SegmentCutpointButton.tsx rename to src/renderer/src/components/SegmentCutpointButton.tsx diff --git a/src/components/Select.module.css b/src/renderer/src/components/Select.module.css similarity index 100% rename from src/components/Select.module.css rename to src/renderer/src/components/Select.module.css diff --git a/src/components/Select.tsx b/src/renderer/src/components/Select.tsx similarity index 100% rename from src/components/Select.tsx rename to src/renderer/src/components/Select.tsx diff --git a/src/components/SetCutpointButton.tsx b/src/renderer/src/components/SetCutpointButton.tsx similarity index 100% rename from src/components/SetCutpointButton.tsx rename to src/renderer/src/components/SetCutpointButton.tsx diff --git a/src/components/Settings.module.css b/src/renderer/src/components/Settings.module.css similarity index 100% rename from src/components/Settings.module.css rename to src/renderer/src/components/Settings.module.css diff --git a/src/components/Settings.tsx b/src/renderer/src/components/Settings.tsx similarity index 99% rename from src/components/Settings.tsx rename to src/renderer/src/components/Settings.tsx index eee0cbb..e79fd93 100644 --- a/src/components/Settings.tsx +++ b/src/renderer/src/components/Settings.tsx @@ -11,7 +11,7 @@ import Switch from './Switch'; import useUserSettings from '../hooks/useUserSettings'; import { askForFfPath } from '../dialogs'; import { isMasBuild, isStoreBuild } from '../util'; -import { LanguageKey, TimecodeFormat, langNames } from '../../types'; +import { LanguageKey, TimecodeFormat, langNames } from '../../../../types'; import styles from './Settings.module.css'; import Select from './Select'; diff --git a/src/components/Sheet.module.css b/src/renderer/src/components/Sheet.module.css similarity index 100% rename from src/components/Sheet.module.css rename to src/renderer/src/components/Sheet.module.css diff --git a/src/components/Sheet.tsx b/src/renderer/src/components/Sheet.tsx similarity index 100% rename from src/components/Sheet.tsx rename to src/renderer/src/components/Sheet.tsx diff --git a/src/components/SimpleModeButton.tsx b/src/renderer/src/components/SimpleModeButton.tsx similarity index 100% rename from src/components/SimpleModeButton.tsx rename to src/renderer/src/components/SimpleModeButton.tsx diff --git a/src/components/Switch.module.css b/src/renderer/src/components/Switch.module.css similarity index 100% rename from src/components/Switch.module.css rename to src/renderer/src/components/Switch.module.css diff --git a/src/components/Switch.tsx b/src/renderer/src/components/Switch.tsx similarity index 100% rename from src/components/Switch.tsx rename to src/renderer/src/components/Switch.tsx diff --git a/src/components/TagEditor.jsx b/src/renderer/src/components/TagEditor.jsx similarity index 100% rename from src/components/TagEditor.jsx rename to src/renderer/src/components/TagEditor.jsx diff --git a/src/components/TextInput.tsx b/src/renderer/src/components/TextInput.tsx similarity index 100% rename from src/components/TextInput.tsx rename to src/renderer/src/components/TextInput.tsx diff --git a/src/components/ToggleExportConfirm.tsx b/src/renderer/src/components/ToggleExportConfirm.tsx similarity index 100% rename from src/components/ToggleExportConfirm.tsx rename to src/renderer/src/components/ToggleExportConfirm.tsx diff --git a/src/components/ValueTuner.tsx b/src/renderer/src/components/ValueTuner.tsx similarity index 100% rename from src/components/ValueTuner.tsx rename to src/renderer/src/components/ValueTuner.tsx diff --git a/src/components/ValueTuners.tsx b/src/renderer/src/components/ValueTuners.tsx similarity index 95% rename from src/components/ValueTuners.tsx rename to src/renderer/src/components/ValueTuners.tsx index 3e9a1e3..3606559 100644 --- a/src/components/ValueTuners.tsx +++ b/src/renderer/src/components/ValueTuners.tsx @@ -9,7 +9,7 @@ const ValueTuners = memo(({ type, onFinished }: { type: TunerType, onFinished: ( const { t } = useTranslation(); const { wheelSensitivity, setWheelSensitivity, keyboardNormalSeekSpeed, setKeyboardNormalSeekSpeed, keyboardSeekAccFactor, setKeyboardSeekAccFactor } = useUserSettings(); - // NOTE default values are duplicated in public/configStore.js + // NOTE default values are duplicated in src/main/configStore.js const types = { wheelSensitivity: { title: t('Timeline trackpad/wheel sensitivity'), diff --git a/src/components/VolumeControl.tsx b/src/renderer/src/components/VolumeControl.tsx similarity index 100% rename from src/components/VolumeControl.tsx rename to src/renderer/src/components/VolumeControl.tsx diff --git a/src/components/Working.tsx b/src/renderer/src/components/Working.tsx similarity index 100% rename from src/components/Working.tsx rename to src/renderer/src/components/Working.tsx diff --git a/src/contexts.ts b/src/renderer/src/contexts.ts similarity index 100% rename from src/contexts.ts rename to src/renderer/src/contexts.ts diff --git a/src/dialogs/extractFrames.jsx b/src/renderer/src/dialogs/extractFrames.jsx similarity index 100% rename from src/dialogs/extractFrames.jsx rename to src/renderer/src/dialogs/extractFrames.jsx diff --git a/src/dialogs/html5ify.tsx b/src/renderer/src/dialogs/html5ify.tsx similarity index 98% rename from src/dialogs/html5ify.tsx rename to src/renderer/src/dialogs/html5ify.tsx index a94243f..9b577c5 100644 --- a/src/dialogs/html5ify.tsx +++ b/src/renderer/src/dialogs/html5ify.tsx @@ -4,7 +4,7 @@ import i18n from 'i18next'; import withReactContent from 'sweetalert2-react-content'; import Swal from '../swal'; -import { Html5ifyMode } from '../types'; +import { Html5ifyMode } from '../../../../types'; const ReactSwal = withReactContent(Swal); diff --git a/src/dialogs/index.tsx b/src/renderer/src/dialogs/index.tsx similarity index 100% rename from src/dialogs/index.tsx rename to src/renderer/src/dialogs/index.tsx diff --git a/src/dialogs/parameters.tsx b/src/renderer/src/dialogs/parameters.tsx similarity index 96% rename from src/dialogs/parameters.tsx rename to src/renderer/src/dialogs/parameters.tsx index 36459ba..3854dec 100644 --- a/src/dialogs/parameters.tsx +++ b/src/renderer/src/dialogs/parameters.tsx @@ -53,12 +53,11 @@ const ParametersInput = ({ description, parameters: parametersIn, onChange, onSu ); }; -// eslint-disable-next-line import/prefer-default-export export async function showParametersDialog({ title, description, parameters: parametersIn, docUrl }: { title?: string, description?: string, parameters: ParameterDialogParameters, docUrl?: string }) { let parameters = parametersIn; - let resolve1; + let resolve1: (value: boolean) => void; - const promise1 = new Promise((resolve) => { + const promise1 = new Promise((resolve) => { resolve1 = resolve; }); const handleSubmit = () => { diff --git a/src/edlFormats.test.ts b/src/renderer/src/edlFormats.test.ts similarity index 100% rename from src/edlFormats.test.ts rename to src/renderer/src/edlFormats.test.ts diff --git a/src/edlFormats.ts b/src/renderer/src/edlFormats.ts similarity index 100% rename from src/edlFormats.ts rename to src/renderer/src/edlFormats.ts diff --git a/src/edlStore.ts b/src/renderer/src/edlStore.ts similarity index 100% rename from src/edlStore.ts rename to src/renderer/src/edlStore.ts diff --git a/src/ffmpeg-parameters.js b/src/renderer/src/ffmpeg-parameters.js similarity index 100% rename from src/ffmpeg-parameters.js rename to src/renderer/src/ffmpeg-parameters.js diff --git a/src/ffmpeg.ts b/src/renderer/src/ffmpeg.ts similarity index 95% rename from src/ffmpeg.ts rename to src/renderer/src/ffmpeg.ts index 5d4bd11..0234220 100644 --- a/src/ffmpeg.ts +++ b/src/renderer/src/ffmpeg.ts @@ -8,16 +8,12 @@ import invariant from 'tiny-invariant'; import { pcmAudioCodecs, getMapStreamsArgs, isMov, LiteFFprobeStream } from './util/streams'; import { getSuffixedOutPath, isExecaFailure } from './util'; import { isDurationValid } from './segments'; -import { Waveform } from '../types'; -import { FFprobeChapter, FFprobeFormat, FFprobeProbeResult, FFprobeStream } from '../ffprobe'; +import { FFprobeChapter, FFprobeFormat, FFprobeProbeResult, FFprobeStream } from '../../../ffprobe'; const FileType = window.require('file-type'); const { pathExists } = window.require('fs-extra'); -const remote = window.require('@electron/remote'); - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const ffmpeg: { renderWaveformPng: (a: any) => Promise, mapTimesToSegments, detectSceneChanges, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfmpeg, runFfprobe, getFfmpegPath, setCustomFfPath } = remote.require('./ffmpeg'); +const { ffmpeg } = window.require('@electron/remote').require('./index.js'); const { renderWaveformPng, mapTimesToSegments, detectSceneChanges, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfmpeg, runFfprobe, getFfmpegPath, setCustomFfPath } = ffmpeg; @@ -32,14 +28,14 @@ export class RefuseOverwriteError extends Error { } } -export function logStdoutStderr({ stdout, stderr }) { +export function logStdoutStderr({ stdout, stderr }: { stdout: Buffer, stderr: Buffer }) { if (stdout.length > 0) { console.log('%cSTDOUT:', 'color: green; font-weight: bold'); - console.log(stdout); + console.log(stdout.toString('utf8')); } if (stderr.length > 0) { console.log('%cSTDERR:', 'color: blue; font-weight: bold'); - console.log(stderr); + console.log(stderr.toString('utf8')); } } @@ -72,10 +68,8 @@ export async function readFrames({ filePath, from, to, streamIndex }: { filePath: string, from?: number | undefined, to?: number | undefined, streamIndex: number, }) { const intervalsArgs = from != null && to != null ? ['-read_intervals', `${from}%${to}`] : []; - const { stdout } = await runFfprobe(['-v', 'error', ...intervalsArgs, '-show_packets', '-select_streams', streamIndex, '-show_entries', 'packet=pts_time,flags', '-of', 'json', filePath]); - // todo types - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const packetsFiltered: Frame[] = (JSON.parse(stdout).packets as any[]) + const { stdout } = await runFfprobe(['-v', 'error', ...intervalsArgs, '-show_packets', '-select_streams', String(streamIndex), '-show_entries', 'packet=pts_time,flags', '-of', 'json', filePath]); + const packetsFiltered: Frame[] = (JSON.parse(stdout as unknown as string).packets as { flags: string, pts_time: string }[]) .map((p) => ({ keyframe: p.flags[0] === 'K', time: parseFloat(p.pts_time), @@ -337,7 +331,7 @@ export async function readFileMeta(filePath: string) { let parsedJson: FFprobeProbeResult; try { // https://github.com/mifi/lossless-cut/issues/1342 - parsedJson = JSON.parse(stdout); + parsedJson = JSON.parse(stdout.toString('utf8')); } catch { console.log('ffprobe stdout', stdout); throw new Error('ffprobe returned malformed data'); @@ -423,7 +417,7 @@ async function extractNonAttachmentStreams({ customOutDir, filePath, streams, en ]; const { stdout } = await runFfmpeg(ffmpegArgs); - console.log(stdout); + console.log(stdout.toString('utf8')); return outPaths; } @@ -459,7 +453,7 @@ async function extractAttachmentStreams({ customOutDir, filePath, streams, enabl try { const { stdout } = await runFfmpeg(ffmpegArgs); - console.log(stdout); + console.log(stdout.toString('utf8')); } catch (err) { // Unfortunately ffmpeg will exit with code 1 even though it's a success // Note: This is kind of hacky: @@ -487,7 +481,7 @@ export async function extractStreams({ filePath, customOutDir, streams, enableOv async function renderThumbnail(filePath: string, timestamp: number) { const args = [ - '-ss', timestamp, + '-ss', String(timestamp), '-i', filePath, '-vf', 'scale=-2:200', '-f', 'image2', @@ -496,7 +490,7 @@ async function renderThumbnail(filePath: string, timestamp: number) { '-', ]; - const { stdout } = await runFfmpeg(args, { encoding: null }); + const { stdout } = await runFfmpeg(args); const blob = new Blob([stdout], { type: 'image/jpeg' }); return URL.createObjectURL(blob); @@ -511,7 +505,7 @@ export async function extractSubtitleTrack(filePath: string, streamId: number) { '-', ]; - const { stdout } = await runFfmpeg(args, { encoding: null }); + const { stdout } = await runFfmpeg(args); const blob = new Blob([stdout], { type: 'text/vtt' }); return URL.createObjectURL(blob); diff --git a/src/ffprobe.js b/src/renderer/src/ffprobe.js similarity index 100% rename from src/ffprobe.js rename to src/renderer/src/ffprobe.js diff --git a/src/fixtures/DV Analyzer Summary.txt b/src/renderer/src/fixtures/DV Analyzer Summary.txt similarity index 100% rename from src/fixtures/DV Analyzer Summary.txt rename to src/renderer/src/fixtures/DV Analyzer Summary.txt diff --git a/src/fixtures/FCPXML_1_9.fcpxml b/src/renderer/src/fixtures/FCPXML_1_9.fcpxml similarity index 100% rename from src/fixtures/FCPXML_1_9.fcpxml rename to src/renderer/src/fixtures/FCPXML_1_9.fcpxml diff --git a/src/fixtures/Final Cut Pro XMEML 2.xml b/src/renderer/src/fixtures/Final Cut Pro XMEML 2.xml similarity index 100% rename from src/fixtures/Final Cut Pro XMEML 2.xml rename to src/renderer/src/fixtures/Final Cut Pro XMEML 2.xml diff --git a/src/fixtures/Final Cut Pro XMEML 3.xml b/src/renderer/src/fixtures/Final Cut Pro XMEML 3.xml similarity index 100% rename from src/fixtures/Final Cut Pro XMEML 3.xml rename to src/renderer/src/fixtures/Final Cut Pro XMEML 3.xml diff --git a/src/fixtures/Final Cut Pro XMEML.xml b/src/renderer/src/fixtures/Final Cut Pro XMEML.xml similarity index 100% rename from src/fixtures/Final Cut Pro XMEML.xml rename to src/renderer/src/fixtures/Final Cut Pro XMEML.xml diff --git a/src/fixtures/mplayer.edl b/src/renderer/src/fixtures/mplayer.edl similarity index 100% rename from src/fixtures/mplayer.edl rename to src/renderer/src/fixtures/mplayer.edl diff --git a/src/fixtures/potplayer bookmark format utf16le issue 867.pbf b/src/renderer/src/fixtures/potplayer bookmark format utf16le issue 867.pbf similarity index 100% rename from src/fixtures/potplayer bookmark format utf16le issue 867.pbf rename to src/renderer/src/fixtures/potplayer bookmark format utf16le issue 867.pbf diff --git a/src/fixtures/sample.srt b/src/renderer/src/fixtures/sample.srt similarity index 100% rename from src/fixtures/sample.srt rename to src/renderer/src/fixtures/sample.srt diff --git a/src/fixtures/test1.csv b/src/renderer/src/fixtures/test1.csv similarity index 100% rename from src/fixtures/test1.csv rename to src/renderer/src/fixtures/test1.csv diff --git a/src/fixtures/test1.pbf b/src/renderer/src/fixtures/test1.pbf similarity index 100% rename from src/fixtures/test1.pbf rename to src/renderer/src/fixtures/test1.pbf diff --git a/src/fixtures/test2.csv b/src/renderer/src/fixtures/test2.csv similarity index 100% rename from src/fixtures/test2.csv rename to src/renderer/src/fixtures/test2.csv diff --git a/src/fixtures/test2.pbf b/src/renderer/src/fixtures/test2.pbf similarity index 100% rename from src/fixtures/test2.pbf rename to src/renderer/src/fixtures/test2.pbf diff --git a/src/fixtures/test3.csv b/src/renderer/src/fixtures/test3.csv similarity index 100% rename from src/fixtures/test3.csv rename to src/renderer/src/fixtures/test3.csv diff --git a/src/fixtures/test3.pbf b/src/renderer/src/fixtures/test3.pbf similarity index 100% rename from src/fixtures/test3.pbf rename to src/renderer/src/fixtures/test3.pbf diff --git a/src/hooks/normalizeWheel.ts b/src/renderer/src/hooks/normalizeWheel.ts similarity index 100% rename from src/hooks/normalizeWheel.ts rename to src/renderer/src/hooks/normalizeWheel.ts diff --git a/src/hooks/useContextMenu.ts b/src/renderer/src/hooks/useContextMenu.ts similarity index 100% rename from src/hooks/useContextMenu.ts rename to src/renderer/src/hooks/useContextMenu.ts diff --git a/src/hooks/useDirectoryAccess.js b/src/renderer/src/hooks/useDirectoryAccess.ts similarity index 91% rename from src/hooks/useDirectoryAccess.js rename to src/renderer/src/hooks/useDirectoryAccess.ts index bb43ac5..754b293 100644 --- a/src/hooks/useDirectoryAccess.js +++ b/src/renderer/src/hooks/useDirectoryAccess.ts @@ -1,11 +1,11 @@ import { useCallback } from 'react'; import i18n from 'i18next'; +import invariant from 'tiny-invariant'; import { getOutDir, getFileDir, checkDirWriteAccess, dirExists, isMasBuild } from '../util'; import { askForOutDir, askForInputDir } from '../dialogs'; import { errorToast } from '../swal'; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import isDev from '../isDev'; +// import isDev from '../isDev'; export class DirectoryAccessDeclinedError extends Error { constructor() { @@ -26,10 +26,11 @@ const simulateMasBuild = false; const masMode = isMasBuild || simulateMasBuild; -export default ({ setCustomOutDir }) => { - const ensureAccessToSourceDir = useCallback(async (inputPath) => { +export default ({ setCustomOutDir }: { setCustomOutDir: (a: string | undefined) => void }) => { + const ensureAccessToSourceDir = useCallback(async (inputPath: string) => { // Called if we need to read/write to the source file's directory (probably to read/write the project file) const inputFileDir = getFileDir(inputPath); + invariant(inputFileDir != null); let simulateMasPermissionError = simulateMasBuild; @@ -55,7 +56,7 @@ export default ({ setCustomOutDir }) => { } }, []); - const ensureWritableOutDir = useCallback(async ({ inputPath, outDir }) => { + const ensureWritableOutDir = useCallback(async ({ inputPath, outDir }: { inputPath: string | undefined, outDir: string | undefined }) => { // we might need to change the output directory if the user chooses to give us a different one. let newCustomOutDir = outDir; diff --git a/src/hooks/useFfmpegOperations.ts b/src/renderer/src/hooks/useFfmpegOperations.ts similarity index 98% rename from src/hooks/useFfmpegOperations.ts rename to src/renderer/src/hooks/useFfmpegOperations.ts index cbabc25..9f92de4 100644 --- a/src/hooks/useFfmpegOperations.ts +++ b/src/renderer/src/hooks/useFfmpegOperations.ts @@ -9,7 +9,8 @@ import { isCuttingStart, isCuttingEnd, runFfmpegWithProgress, getFfCommandLine, import { getMapStreamsArgs, getStreamIdsToCopy } from '../util/streams'; import { getSmartCutParams } from '../smartcut'; import { isDurationValid } from '../segments'; -import { FFprobeStream } from '../../ffprobe'; +import { FFprobeStream } from '../../../../ffprobe'; +import { Html5ifyMode } from '../../../../types'; const { join, resolve, dirname } = window.require('path'); const { pathExists } = window.require('fs-extra'); @@ -470,8 +471,11 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea if (autoDeleteMergedSegments) await tryDeleteFiles(segmentPaths); }, [concatFiles, filePath, shouldSkipExistingFile]); - const html5ify = useCallback(async ({ customOutDir, filePath: filePathArg, speed, hasAudio, hasVideo, onProgress }) => { + const html5ify = useCallback(async ({ customOutDir, filePath: filePathArg, speed, hasAudio, hasVideo, onProgress }: { + customOutDir: string | undefined, filePath: string, speed: Html5ifyMode, hasAudio: boolean, hasVideo: boolean, onProgress: (p: number) => void, + }) => { const outPath = getHtml5ifiedPath(customOutDir, filePathArg, speed); + invariant(outPath != null); await ffmpegHtml5ify({ filePath: filePathArg, outPath, speed, hasAudio, hasVideo, onProgress }); invariant(outPath != null); await transferTimestamps({ inPath: filePathArg, outPath, treatOutputFileModifiedTimeAsStart }); diff --git a/src/hooks/useFileFormatState.ts b/src/renderer/src/hooks/useFileFormatState.ts similarity index 100% rename from src/hooks/useFileFormatState.ts rename to src/renderer/src/hooks/useFileFormatState.ts diff --git a/src/hooks/useFrameCapture.ts b/src/renderer/src/hooks/useFrameCapture.ts similarity index 96% rename from src/hooks/useFrameCapture.ts rename to src/renderer/src/hooks/useFrameCapture.ts index 10a4918..9823b58 100644 --- a/src/hooks/useFrameCapture.ts +++ b/src/renderer/src/hooks/useFrameCapture.ts @@ -8,7 +8,7 @@ import { getNumDigits } from '../segments'; import { captureFrame as ffmpegCaptureFrame, captureFrames as ffmpegCaptureFrames } from '../ffmpeg'; import { FormatTimecode } from '../types'; -import { CaptureFormat } from '../../types'; +import { CaptureFormat } from '../../../../types'; const mime = window.require('mime-types'); const { rename, readdir, writeFile }: typeof FsPromises = window.require('fs/promises'); @@ -28,7 +28,7 @@ function getFrameFromVideo(video: HTMLVideoElement, format: CaptureFormat, quali export default ({ formatTimecode, treatOutputFileModifiedTimeAsStart }: { formatTimecode: FormatTimecode, treatOutputFileModifiedTimeAsStart?: boolean | undefined | null }) => { const captureFramesRange = useCallback(async ({ customOutDir, filePath, fps, fromTime, toTime, estimatedMaxNumFiles, captureFormat, quality, filter, onProgress, outputTimestamps }: { - customOutDir, filePath: string, fps: number, fromTime: number, toTime: number, estimatedMaxNumFiles: number, captureFormat: string, quality: number, filter?: string | undefined, onProgress: (a: number) => void, outputTimestamps: boolean + customOutDir, filePath: string, fps: number, fromTime: number, toTime: number, estimatedMaxNumFiles: number, captureFormat: CaptureFormat, quality: number, filter?: string | undefined, onProgress: (a: number) => void, outputTimestamps: boolean }) => { const getSuffix = (prefix: string) => `${prefix}.${captureFormat}`; diff --git a/src/hooks/useKeyboard.ts b/src/renderer/src/hooks/useKeyboard.ts similarity index 96% rename from src/hooks/useKeyboard.ts rename to src/renderer/src/hooks/useKeyboard.ts index 5bfc29f..3692c34 100644 --- a/src/hooks/useKeyboard.ts +++ b/src/renderer/src/hooks/useKeyboard.ts @@ -4,7 +4,7 @@ import { useEffect, useRef } from 'react'; // Also document.addEventListener needs custom handling of modifier keys or C will be triggered by CTRL+C, etc import Mousetrap from 'mousetrap'; -import { KeyBinding, KeyboardAction } from '../../types'; +import { KeyBinding, KeyboardAction } from '../../../../types'; // for all dialog actions (e.g. detectSceneChanges) we must use keyup, or we risk having the button press inserted into the dialog's input element right after the dialog opens diff --git a/src/hooks/useKeyframes.ts b/src/renderer/src/hooks/useKeyframes.ts similarity index 98% rename from src/hooks/useKeyframes.ts rename to src/renderer/src/hooks/useKeyframes.ts index a17c9d6..6236933 100644 --- a/src/hooks/useKeyframes.ts +++ b/src/renderer/src/hooks/useKeyframes.ts @@ -3,7 +3,7 @@ import sortBy from 'lodash/sortBy'; import useDebounceOld from 'react-use/lib/useDebounce'; // Want to phase out this import { readFramesAroundTime, findNearestKeyFrameTime as ffmpegFindNearestKeyFrameTime, Frame } from '../ffmpeg'; -import { FFprobeStream } from '../../ffprobe'; +import { FFprobeStream } from '../../../../ffprobe'; const maxKeyframes = 1000; // const maxKeyframes = 100; diff --git a/src/hooks/useNativeMenu.ts b/src/renderer/src/hooks/useNativeMenu.ts similarity index 100% rename from src/hooks/useNativeMenu.ts rename to src/renderer/src/hooks/useNativeMenu.ts diff --git a/src/hooks/useSegments.ts b/src/renderer/src/hooks/useSegments.ts similarity index 97% rename from src/hooks/useSegments.ts rename to src/renderer/src/hooks/useSegments.ts index 7483ae4..4761e79 100644 --- a/src/hooks/useSegments.ts +++ b/src/renderer/src/hooks/useSegments.ts @@ -16,9 +16,7 @@ import * as ffmpegParameters from '../ffmpeg-parameters'; import { maxSegmentsAllowed } from '../util/constants'; import { SegmentBase, SegmentToExport, StateSegment, UpdateSegAtIndex } from '../types'; -const remote = window.require('@electron/remote'); - -const { blackDetect, silenceDetect } = remote.require('./ffmpeg'); +const { ffmpeg: { blackDetect, silenceDetect } } = window.require('@electron/remote').require('./index.js'); function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly }: { @@ -81,7 +79,9 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt }); }, [clearSegCounter, createIndexedSegment, setCutSegments]); - const detectSegments = useCallback(async ({ name, workingText, errorText, fn }) => { + const detectSegments = useCallback(async ({ name, workingText, errorText, fn }: { + name: string, workingText: string, errorText: string, fn: () => Promise, + }) => { if (!filePath) return; if (workingRef.current) return; try { @@ -92,7 +92,7 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt console.log(name, newSegments); loadCutSegments(newSegments, true); } catch (err) { - handleError(errorText, err); + if (!(err instanceof Error && err.name === 'AbortError')) handleError(errorText, err); } finally { setWorking(undefined); setCutProgress(undefined); @@ -131,19 +131,25 @@ function useSegments({ filePath, workingRef, setWorking, setCutProgress, videoSt const detectBlackScenes = useCallback(async () => { const filterOptions = await showParametersDialog({ title: i18n.t('Enter parameters'), parameters: ffmpegParameters.blackdetect(), docUrl: 'https://ffmpeg.org/ffmpeg-filters.html#blackdetect' }); if (filterOptions == null) return; + invariant(filePath != null); await detectSegments({ name: 'blackScenes', workingText: i18n.t('Detecting black scenes'), errorText: i18n.t('Failed to detect black scenes'), fn: async () => blackDetect({ filePath, filterOptions, onProgress: setCutProgress, from: currentApparentCutSeg.start, to: currentApparentCutSeg.end }) }); }, [currentApparentCutSeg.end, currentApparentCutSeg.start, detectSegments, filePath, setCutProgress]); const detectSilentScenes = useCallback(async () => { const filterOptions = await showParametersDialog({ title: i18n.t('Enter parameters'), parameters: ffmpegParameters.silencedetect(), docUrl: 'https://ffmpeg.org/ffmpeg-filters.html#silencedetect' }); if (filterOptions == null) return; + invariant(filePath != null); await detectSegments({ name: 'silentScenes', workingText: i18n.t('Detecting silent scenes'), errorText: i18n.t('Failed to detect silent scenes'), fn: async () => silenceDetect({ filePath, filterOptions, onProgress: setCutProgress, from: currentApparentCutSeg.start, to: currentApparentCutSeg.end }) }); }, [currentApparentCutSeg.end, currentApparentCutSeg.start, detectSegments, filePath, setCutProgress]); const detectSceneChanges = useCallback(async () => { const filterOptions = await showParametersDialog({ title: i18n.t('Enter parameters'), parameters: ffmpegParameters.sceneChange() }); if (filterOptions == null) return; - await detectSegments({ name: 'sceneChanges', workingText: i18n.t('Detecting scene changes'), errorText: i18n.t('Failed to detect scene changes'), fn: async () => ffmpegDetectSceneChanges({ filePath, minChange: filterOptions['minChange'], onProgress: setCutProgress, from: currentApparentCutSeg.start, to: currentApparentCutSeg.end }) }); + invariant(filePath != null); + // eslint-disable-next-line prefer-destructuring + const minChange = filterOptions['minChange']; + invariant(minChange != null); + await detectSegments({ name: 'sceneChanges', workingText: i18n.t('Detecting scene changes'), errorText: i18n.t('Failed to detect scene changes'), fn: async () => ffmpegDetectSceneChanges({ filePath, minChange, onProgress: setCutProgress, from: currentApparentCutSeg.start, to: currentApparentCutSeg.end }) }); }, [currentApparentCutSeg.end, currentApparentCutSeg.start, detectSegments, filePath, setCutProgress]); const createSegmentsFromKeyframes = useCallback(async () => { diff --git a/src/hooks/useTimelineScroll.ts b/src/renderer/src/hooks/useTimelineScroll.ts similarity index 100% rename from src/hooks/useTimelineScroll.ts rename to src/renderer/src/hooks/useTimelineScroll.ts diff --git a/src/hooks/useUserSettings.ts b/src/renderer/src/hooks/useUserSettings.ts similarity index 100% rename from src/hooks/useUserSettings.ts rename to src/renderer/src/hooks/useUserSettings.ts diff --git a/src/hooks/useUserSettingsRoot.ts b/src/renderer/src/hooks/useUserSettingsRoot.ts similarity index 98% rename from src/hooks/useUserSettingsRoot.ts rename to src/renderer/src/hooks/useUserSettingsRoot.ts index a80914c..94f0f12 100644 --- a/src/hooks/useUserSettingsRoot.ts +++ b/src/renderer/src/hooks/useUserSettingsRoot.ts @@ -1,13 +1,11 @@ import { useEffect, useState, useRef, useCallback } from 'react'; import i18n from 'i18next'; -import { StoreGetConfig, StoreResetConfig, StoreSetConfig, Config } from '../../types'; +import { Config } from '../../../../types'; import { errorToast } from '../swal'; import isDev from '../isDev'; -const remote = window.require('@electron/remote'); - -const configStore: { get: StoreGetConfig, set: StoreSetConfig, reset: StoreResetConfig } = remote.require('./configStore'); +const { configStore } = window.require('@electron/remote').require('./index.js'); export default () => { const firstUpdateRef = useRef(true); diff --git a/src/hooks/useWaveform.ts b/src/renderer/src/hooks/useWaveform.ts similarity index 98% rename from src/hooks/useWaveform.ts rename to src/renderer/src/hooks/useWaveform.ts index 7083ef9..1fbe0c4 100644 --- a/src/hooks/useWaveform.ts +++ b/src/renderer/src/hooks/useWaveform.ts @@ -5,7 +5,7 @@ import { waveformColorDark, waveformColorLight } from '../colors'; import { renderWaveformPng } from '../ffmpeg'; import { RenderableWaveform } from '../types'; -import { FFprobeStream } from '../../ffprobe'; +import { FFprobeStream } from '../../../../ffprobe'; const maxWaveforms = 100; diff --git a/src/hooks/useWhatChanged.js b/src/renderer/src/hooks/useWhatChanged.js similarity index 100% rename from src/hooks/useWhatChanged.js rename to src/renderer/src/hooks/useWhatChanged.js diff --git a/src/i18n.ts b/src/renderer/src/i18n.ts similarity index 90% rename from src/i18n.ts rename to src/renderer/src/i18n.ts index 603b054..dbad35f 100644 --- a/src/i18n.ts +++ b/src/renderer/src/i18n.ts @@ -3,9 +3,7 @@ import { initReactI18next } from 'react-i18next'; const Backend = window.require('i18next-fs-backend'); -const remote = window.require('@electron/remote'); - -const { commonI18nOptions, fallbackLng, loadPath, addPath } = remote.require('./i18n-common'); +const { i18n: { commonI18nOptions, fallbackLng, loadPath, addPath } } = window.require('@electron/remote').require('./index.js'); // https://www.i18next.com/overview/typescript#argument-of-type-defaulttfuncreturn-is-not-assignable-to-parameter-of-type-xyz // todo This should not be necessary anymore since v23.0.0 diff --git a/src/icon-mac.svg b/src/renderer/src/icon-mac.svg similarity index 100% rename from src/icon-mac.svg rename to src/renderer/src/icon-mac.svg diff --git a/src/icon.svg b/src/renderer/src/icon.svg similarity index 100% rename from src/icon.svg rename to src/renderer/src/icon.svg diff --git a/src/index.tsx b/src/renderer/src/index.tsx similarity index 79% rename from src/index.tsx rename to src/renderer/src/index.tsx index f120570..6645e69 100644 --- a/src/index.tsx +++ b/src/renderer/src/index.tsx @@ -20,6 +20,8 @@ import '@fontsource/open-sans/700-italic.css'; import '@fontsource/open-sans/800.css'; import '@fontsource/open-sans/800-italic.css'; +import type * as main from '../../main/index'; + import App from './App'; import ErrorBoundary from './ErrorBoundary'; import './i18n'; @@ -27,12 +29,22 @@ import './i18n'; import './main.css'; +type TypedRemote = Omit & { + require: (module: T) => ( + T extends './index.js' ? typeof main : + // eslint-disable-next-line @typescript-eslint/no-explicit-any + any + ); +} + declare global { interface Window { - require: (module: T) => T extends '@electron/remote' ? typeof Remote : + require: (module: T) => ( + T extends '@electron/remote' ? TypedRemote : T extends 'electron' ? typeof Electron : // eslint-disable-next-line @typescript-eslint/no-explicit-any - any; + any + ); } } diff --git a/src/renderer/src/isDev.ts b/src/renderer/src/isDev.ts new file mode 100644 index 0000000..56aafd9 --- /dev/null +++ b/src/renderer/src/isDev.ts @@ -0,0 +1,3 @@ +const { isDev } = window.require('@electron/remote').require('./index.js'); + +export default isDev; diff --git a/src/main.css b/src/renderer/src/main.css similarity index 100% rename from src/main.css rename to src/renderer/src/main.css diff --git a/src/mifi.js b/src/renderer/src/mifi.js similarity index 100% rename from src/mifi.js rename to src/renderer/src/mifi.js diff --git a/src/outFormats.js b/src/renderer/src/outFormats.js similarity index 100% rename from src/outFormats.js rename to src/renderer/src/outFormats.js diff --git a/src/reporting.jsx b/src/renderer/src/reporting.tsx similarity index 76% rename from src/reporting.jsx rename to src/renderer/src/reporting.tsx index 63bf65e..33f1054 100644 --- a/src/reporting.jsx +++ b/src/renderer/src/reporting.tsx @@ -1,24 +1,28 @@ import withReactContent from 'sweetalert2-react-content'; import i18n from 'i18next'; import { Trans } from 'react-i18next'; +import { CSSProperties } from 'react'; import CopyClipboardButton from './components/CopyClipboardButton'; import { isStoreBuild, isMasBuild, isWindowsStoreBuild } from './util'; import Swal from './swal'; const electron = window.require('electron'); -const os = window.require('os'); -const { app } = window.require('@electron/remote'); +const remote = window.require('@electron/remote'); + +const { app } = remote; + +const { platform } = remote.require('./index.js'); const ReactSwal = withReactContent(Swal); -const linkStyle = { fontWeight: 'bold', cursor: 'pointer' }; +const linkStyle: CSSProperties = { fontWeight: 'bold', cursor: 'pointer' }; // eslint-disable-next-line import/prefer-default-export -export function openSendReportDialog(err, state) { +export function openSendReportDialog(err: unknown | undefined, state: unknown) { const reportInstructions = isStoreBuild ? (

Please send an email to electron.shell.openExternal('mailto:losslesscut@mifi.no')}>losslesscut@mifi.no where you describe what you were doing.

@@ -33,19 +37,18 @@ export function openSendReportDialog(err, state) { ); - const platform = os.platform(); const version = app.getVersion(); - const text = `${err ? err.stack : 'No error occurred.'}\n\n${JSON.stringify({ - err: err && { - code: err.code, - killed: err.killed, - failed: err.failed, - timedOut: err.timedOut, - isCanceled: err.isCanceled, - exitCode: err.exitCode, - signal: err.signal, - signalDescription: err.signalDescription, + const text = `${err instanceof Error ? err.stack : 'No error occurred.'}\n\n${JSON.stringify({ + err: err instanceof Error && { + code: err['code'], + killed: err['killed'], + failed: err['failed'], + timedOut: err['timedOut'], + isCanceled: err['isCanceled'], + exitCode: err['exitCode'], + signal: err['signal'], + signalDescription: err['signalDescription'], }, state, diff --git a/src/segments.test.ts b/src/renderer/src/segments.test.ts similarity index 100% rename from src/segments.test.ts rename to src/renderer/src/segments.test.ts diff --git a/src/segments.ts b/src/renderer/src/segments.ts similarity index 100% rename from src/segments.ts rename to src/renderer/src/segments.ts diff --git a/src/smartcut.ts b/src/renderer/src/smartcut.ts similarity index 98% rename from src/smartcut.ts rename to src/renderer/src/smartcut.ts index 0507bf4..b478f62 100644 --- a/src/smartcut.ts +++ b/src/renderer/src/smartcut.ts @@ -1,7 +1,7 @@ import { getRealVideoStreams, getVideoTimebase } from './util/streams'; import { readKeyframesAroundTime, findNextKeyframe, findKeyframeAtExactTime } from './ffmpeg'; -import { FFprobeStream } from '../ffprobe'; +import { FFprobeStream } from '../../../ffprobe'; const { stat } = window.require('fs-extra'); diff --git a/src/swal.ts b/src/renderer/src/swal.ts similarity index 100% rename from src/swal.ts rename to src/renderer/src/swal.ts diff --git a/src/theme.ts b/src/renderer/src/theme.ts similarity index 100% rename from src/theme.ts rename to src/renderer/src/theme.ts diff --git a/src/types.ts b/src/renderer/src/types.ts similarity index 95% rename from src/types.ts rename to src/renderer/src/types.ts index be2b6b1..45e16d7 100644 --- a/src/types.ts +++ b/src/renderer/src/types.ts @@ -61,8 +61,6 @@ export interface InverseCutSegment { export type PlaybackMode = 'loop-segment-start-end' | 'loop-segment' | 'play-segment-once' | 'loop-selected-segments'; -export type Html5ifyMode = 'fastest' | 'fast-audio-remux' | 'fast-audio' | 'fast' | 'slow' | 'slow-audio' | 'slowest'; - export type EdlFileType = 'csv' | 'csv-frames' | 'xmeml' | 'fcpxml' | 'dv-analyzer-summary-txt' | 'cue' | 'pbf' | 'mplayer' | 'srt' | 'llc'; export type EdlImportType = 'youtube' | EdlFileType; diff --git a/src/util.ts b/src/renderer/src/util.ts similarity index 98% rename from src/util.ts rename to src/renderer/src/util.ts index b916623..81568f1 100644 --- a/src/util.ts +++ b/src/renderer/src/util.ts @@ -6,7 +6,6 @@ import sortBy from 'lodash/sortBy'; import pRetry, { Options } from 'p-retry'; import { ExecaError } from 'execa'; import type * as FsPromises from 'fs/promises'; -import type * as Os from 'os'; import type * as FsExtra from 'fs-extra'; import type { PlatformPath } from 'path'; @@ -17,9 +16,11 @@ import { ffmpegExtractWindow } from './util/constants'; const { dirname, parse: parsePath, join, extname, isAbsolute, resolve, basename }: PlatformPath = window.require('path'); const fsExtra: typeof FsExtra = window.require('fs-extra'); const { stat, lstat, readdir, utimes, unlink }: typeof FsPromises = window.require('fs/promises'); -const os: typeof Os = window.require('os'); const { ipcRenderer } = window.require('electron'); const remote = window.require('@electron/remote'); +const { isWindows, isMac } = remote.require('./index.js'); + +export { isWindows, isMac }; const trashFile = async (path: string) => ipcRenderer.invoke('tryTrashItem', path); @@ -195,12 +196,6 @@ export const isMasBuild = window.process.mas; export const isWindowsStoreBuild = window.process.windowsStore; export const isStoreBuild = isMasBuild || isWindowsStoreBuild; -export const platform = os.platform(); -export const arch = os.arch(); - -export const isWindows = platform === 'win32'; -export const isMac = platform === 'darwin'; - export function getExtensionForFormat(format: string) { const ext = { matroska: 'mkv', @@ -270,7 +265,7 @@ export async function findExistingHtml5FriendlyFile(fp, cod) { }; } -export function getHtml5ifiedPath(cod, fp, type) { +export function getHtml5ifiedPath(cod: string | undefined, fp, type) { // See also inside ffmpegHtml5ify const ext = (isMac && ['slowest', 'slow', 'slow-audio'].includes(type)) ? 'mp4' : 'mkv'; return getSuffixedOutPath({ customOutDir: cod, filePath: fp, nameSuffix: `${html5ifiedPrefix}${type}.${ext}` }); @@ -311,6 +306,10 @@ export const deleteDispositionValue = 'llc_disposition_remove'; export const mirrorTransform = 'matrix(-1, 0, 0, 1, 0, 0)'; +export function isExecaError(err: unknown): err is Pick { + return err instanceof Error && 'stdout' in err && 'stderr' in err; +} + // I *think* Windows will throw error with code ENOENT if ffprobe/ffmpeg fails (execa), but other OS'es will return this error code if a file is not found, so it would be wrong to attribute it to exec failure. // see https://github.com/mifi/lossless-cut/issues/451 export const isExecaFailure = (err): err is ExecaError => err.exitCode === 1 || (isWindows && err.code === 'ENOENT'); diff --git a/src/util/colors.ts b/src/renderer/src/util/colors.ts similarity index 100% rename from src/util/colors.ts rename to src/renderer/src/util/colors.ts diff --git a/src/util/constants.ts b/src/renderer/src/util/constants.ts similarity index 100% rename from src/util/constants.ts rename to src/renderer/src/util/constants.ts diff --git a/src/util/duration.test.ts b/src/renderer/src/util/duration.test.ts similarity index 100% rename from src/util/duration.test.ts rename to src/renderer/src/util/duration.test.ts diff --git a/src/util/duration.ts b/src/renderer/src/util/duration.ts similarity index 100% rename from src/util/duration.ts rename to src/renderer/src/util/duration.ts diff --git a/src/util/outputNameTemplate.ts b/src/renderer/src/util/outputNameTemplate.ts similarity index 100% rename from src/util/outputNameTemplate.ts rename to src/renderer/src/util/outputNameTemplate.ts diff --git a/src/util/rate-calculator.js b/src/renderer/src/util/rate-calculator.js similarity index 100% rename from src/util/rate-calculator.js rename to src/renderer/src/util/rate-calculator.js diff --git a/src/util/rate-calculator.test.ts b/src/renderer/src/util/rate-calculator.test.ts similarity index 100% rename from src/util/rate-calculator.test.ts rename to src/renderer/src/util/rate-calculator.test.ts diff --git a/src/util/streams.test.ts b/src/renderer/src/util/streams.test.ts similarity index 98% rename from src/util/streams.test.ts rename to src/renderer/src/util/streams.test.ts index 347f8f8..2ba7c59 100644 --- a/src/util/streams.test.ts +++ b/src/renderer/src/util/streams.test.ts @@ -1,7 +1,7 @@ import { test, expect } from 'vitest'; import { LiteFFprobeStream, getMapStreamsArgs, getStreamIdsToCopy } from './streams'; -import { FFprobeStreamDisposition } from '../../ffprobe'; +import { FFprobeStreamDisposition } from '../../../../ffprobe'; const makeDisposition = (override?: Partial): FFprobeStreamDisposition => ({ diff --git a/src/util/streams.ts b/src/renderer/src/util/streams.ts similarity index 99% rename from src/util/streams.ts rename to src/renderer/src/util/streams.ts index 8f39283..74cfd61 100644 --- a/src/util/streams.ts +++ b/src/renderer/src/util/streams.ts @@ -1,4 +1,4 @@ -import { FFprobeStream, FFprobeStreamDisposition } from '../../ffprobe'; +import { FFprobeStream, FFprobeStreamDisposition } from '../../../../ffprobe'; import { ChromiumHTMLAudioElement, ChromiumHTMLVideoElement } from '../types'; // https://www.ffmpeg.org/doxygen/3.2/libavutil_2utils_8c_source.html#l00079 diff --git a/translation.md b/translation.md index 858a8c0..6d99ec7 100644 --- a/translation.md +++ b/translation.md @@ -41,11 +41,11 @@ Master language is English. To test new weblate translations you made in the app itself, you need to: 1. Download the translation for your language from Weblate: **Files -> Download translation** 2. Rename the downloaded `.json` file to: `translation.json` -3. Create a [folder structure](https://github.com/mifi/lossless-cut/tree/master/public/locales) somewhere on your computer that looks like this: +3. Create a [folder structure](https://github.com/mifi/lossless-cut/tree/master/src/main/locales) somewhere on your computer that looks like this: ``` translations/locales/localeCode ``` -You can find a list of the available [`localeCode`s here](https://github.com/mifi/lossless-cut/tree/master/public/locales). In our example we will use `nb_NO` (Norwegian) with this path: +You can find a list of the available [`localeCode`s here](https://github.com/mifi/lossless-cut/tree/master/src/main/locales). In our example we will use `nb_NO` (Norwegian) with this path: ``` /Users/mifi/Desktop/translations/locales/nb_NO ``` diff --git a/tsconfig.json b/tsconfig.json index 768fb6b..0cdc39f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "references": [ { "path": "./tsconfig.web.json" }, { "path": "./tsconfig.main.json" }, + { "path": "./tsconfig.node.json" }, ], "files": [], } \ No newline at end of file diff --git a/tsconfig.main.json b/tsconfig.main.json index f9df496..ad7911f 100644 --- a/tsconfig.main.json +++ b/tsconfig.main.json @@ -10,12 +10,9 @@ "target": "ESNext", "module": "ESNext", "moduleResolution": "Bundler", - - "noImplicitAny": false, // todo - "checkJs": true, // todo - "allowJs": true, // todo }, "include": [ - "public/**/*", "types.ts", + "src/main/**/*", + "types.ts", ], } \ No newline at end of file diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..2ad1fad --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "extends": ["@tsconfig/strictest", "@tsconfig/node18/tsconfig.json"], + "compilerOptions": { + "noEmit": true, + }, + "include": [ + "script/**/*", + ], +} \ No newline at end of file diff --git a/tsconfig.web.json b/tsconfig.web.json index a0fd7ac..6e8ae21 100644 --- a/tsconfig.web.json +++ b/tsconfig.web.json @@ -12,6 +12,6 @@ { "path": "./tsconfig.main.json" }, ], "include": [ - "src/**/*", + "src/renderer/**/*", ], } \ No newline at end of file diff --git a/types.ts b/types.ts index 2e8d15f..698027f 100644 --- a/types.ts +++ b/types.ts @@ -99,10 +99,13 @@ export interface Config { invertTimelineScroll: boolean | undefined, } -export type StoreGetConfig = (key: T) => Config[T]; -export type StoreSetConfig = (key: T, value: Config[T]) => void; -export type StoreResetConfig = (key: T) => void; - export interface Waveform { buffer: Buffer, } + +export interface ApiKeyboardActionRequest { + id: number + action: string +} + +export type Html5ifyMode = 'fastest' | 'fast-audio-remux' | 'fast-audio' | 'fast' | 'slow' | 'slow-audio' | 'slowest'; diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index d0da754..0000000 --- a/vite.config.js +++ /dev/null @@ -1,13 +0,0 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], - base: '', - build: { - chunkSizeWarningLimit: 3e6, - sourcemap: true, - }, -}); diff --git a/yarn.lock b/yarn.lock index 8c14cb9..257ac8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,6 +29,16 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.0": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: f3451525379c68a73eb0a1e65247fbf28c0cccd126d93af21c75fceff77773d43c0d4a2d51978fb131aff25b5f2cb41a9fe48cc296e61ae65e679c4f6918b0ab + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" @@ -58,6 +68,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.24.1, @babel/code-frame@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/code-frame@npm:7.24.2" + dependencies: + "@babel/highlight": "npm:^7.24.2" + picocolors: "npm:^1.0.0" + checksum: 7db8f5b36ffa3f47a37f58f61e3d130b9ecad21961f3eede7e2a4ac2c7e4a5efb6e9d03a810c669bc986096831b6c0dfc2c3082673d93351b82359c1b03e0590 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.20.5": version: 7.20.14 resolution: "@babel/compat-data@npm:7.20.14" @@ -65,6 +85,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.23.5": + version: 7.24.1 + resolution: "@babel/compat-data@npm:7.24.1" + checksum: d5460b99c07ff8487467c52f742a219c7e3bcdcaa2882456a13c0d0c8116405f0c85a651fb60511284dc64ed627a5e989f24c3cd6e71d07a9947e7c8954b433c + languageName: node + linkType: hard + "@babel/core@npm:^7.20.12": version: 7.20.12 resolution: "@babel/core@npm:7.20.12" @@ -88,6 +115,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.23.5": + version: 7.24.3 + resolution: "@babel/core@npm:7.24.3" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.24.2" + "@babel/generator": "npm:^7.24.1" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.24.1" + "@babel/parser": "npm:^7.24.1" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 3a7b9931fe0d93c500dcdb6b36f038b0f9d5090c048818e62aa8321c8f6e8ccc3d47373f0b40591c1fe3b13e5096bacabb1ade83f9f4d86f57878c39a9d1ade1 + languageName: node + linkType: hard + "@babel/generator@npm:^7.20.7": version: 7.20.14 resolution: "@babel/generator@npm:7.20.14" @@ -111,6 +161,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/generator@npm:7.24.1" + dependencies: + "@babel/types": "npm:^7.24.0" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: c6160e9cd63d7ed7168dee27d827f9c46fab820c45861a5df56cd5c78047f7c3fc97c341e9ccfa1a6f97c87ec2563d9903380b5f92794e3540a6c5f99eb8f075 + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.20.7": version: 7.20.7 resolution: "@babel/helper-compilation-targets@npm:7.20.7" @@ -126,6 +188,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" + dependencies: + "@babel/compat-data": "npm:^7.23.5" + "@babel/helper-validator-option": "npm:^7.23.5" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 05595cd73087ddcd81b82d2f3297aac0c0422858dfdded43d304786cf680ec33e846e2317e6992d2c964ee61d93945cbf1fa8ec80b55aee5bfb159227fb02cb9 + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-environment-visitor@npm:7.18.9" @@ -168,6 +243,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.24.3 + resolution: "@babel/helper-module-imports@npm:7.24.3" + dependencies: + "@babel/types": "npm:^7.24.0" + checksum: 42fe124130b78eeb4bb6af8c094aa749712be0f4606f46716ce74bc18a5ea91c918c547c8bb2307a2e4b33f163e4ad2cb6a7b45f80448e624eae45b597ea3499 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.20.11": version: 7.20.11 resolution: "@babel/helper-module-transforms@npm:7.20.11" @@ -184,6 +268,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/helper-module-transforms@npm:7.23.3" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/helper-simple-access": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/helper-validator-identifier": "npm:^7.22.20" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 583fa580f8e50e6f45c4f46aa76a8e49c2528deb84e25f634d66461b9a0e2420e13979b0a607b67aef67eaf8db8668eb9edc038b4514b16e3879fe09e8fd294b + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.19.0": version: 7.20.2 resolution: "@babel/helper-plugin-utils@npm:7.20.2" @@ -191,6 +290,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: dc8c7af321baf7653d93315beffee1790eb2c464b4f529273a24c8743a3f3095bf3f2d11828cb2c52d56282ef43a4bdc67a79c9ab8dd845e35d01871f3f28a0e + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.20.2": version: 7.20.2 resolution: "@babel/helper-simple-access@npm:7.20.2" @@ -200,6 +306,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-simple-access@npm:7.22.5" + dependencies: + "@babel/types": "npm:^7.22.5" + checksum: 7d5430eecf880937c27d1aed14245003bd1c7383ae07d652b3932f450f60bfcf8f2c1270c593ab063add185108d26198c69d1aca0e6fb7c6fdada4bcf72ab5b7 + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-split-export-declaration@npm:7.18.6" @@ -232,6 +347,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.24.1 + resolution: "@babel/helper-string-parser@npm:7.24.1" + checksum: 04c0ede77b908b43e6124753b48bc485528112a9335f0a21a226bff1ace75bb6e64fab24c85cb4b1610ef3494dacd1cb807caeb6b79a7b36c43d48c289b35949 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-validator-identifier@npm:7.19.1" @@ -253,6 +375,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e + languageName: node + linkType: hard + "@babel/helpers@npm:^7.20.7": version: 7.20.13 resolution: "@babel/helpers@npm:7.20.13" @@ -264,6 +393,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/helpers@npm:7.24.1" + dependencies: + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + checksum: 82d3cdd3beafc4583f237515ef220bc205ced8b0540c6c6e191fc367a9589bd7304b8f9800d3d7574d4db9f079bd555979816b1874c86e53b3e7dd2032ad6c7c + languageName: node + linkType: hard + "@babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" @@ -297,6 +437,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.2": + version: 7.24.2 + resolution: "@babel/highlight@npm:7.24.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 4555124235f34403bb28f55b1de58edf598491cc181c75f8afc8fe529903cb598cd52fe3bf2faab9bc1f45c299681ef0e44eea7a848bb85c500c5a4fe13f54f6 + languageName: node + linkType: hard + "@babel/parser@npm:^7.20.7": version: 7.20.15 resolution: "@babel/parser@npm:7.20.15" @@ -315,6 +467,26 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/parser@npm:7.24.1" + bin: + parser: ./bin/babel-parser.js + checksum: 561d9454091e07ecfec3828ce79204c0fc9d24e17763f36181c6984392be4ca6b79c8225f2224fdb7b1b3b70940e243368c8f83ac77ec2dc20f46d3d06bd6795 + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.23.3": + version: 7.24.1 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 58f9aa9b0de8382f8cfa3f1f1d40b69d98cd2f52340e2391733d0af745fdddda650ba392e509bc056157c880a2f52834a38ab2c5aa5569af8c61bb6ecbf45f34 + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx-self@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-react-jsx-self@npm:7.18.6" @@ -395,6 +567,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/template@npm:7.24.0" + dependencies: + "@babel/code-frame": "npm:^7.23.5" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 8c538338c7de8fac8ada691a5a812bdcbd60bd4a4eb5adae2cc9ee19773e8fb1a724312a00af9e1ce49056ffd3c3475e7287b5668cf6360bfb3f8ac827a06ffe + languageName: node + linkType: hard + "@babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.13": version: 7.23.2 resolution: "@babel/traverse@npm:7.23.2" @@ -413,6 +596,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.24.1": + version: 7.24.1 + resolution: "@babel/traverse@npm:7.24.1" + dependencies: + "@babel/code-frame": "npm:^7.24.1" + "@babel/generator": "npm:^7.24.1" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/parser": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: b9b0173c286ef549e179f3725df3c4958069ad79fe5b9840adeb99692eb4a5a08db4e735c0f086aab52e7e08ec711cee9e7c06cb908d8035641d1382172308d3 + languageName: node + linkType: hard + "@babel/types@npm:^7.18.6, @babel/types@npm:^7.20.2, @babel/types@npm:^7.8.3": version: 7.20.2 resolution: "@babel/types@npm:7.20.2" @@ -446,6 +647,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: a0b4875ce2e132f9daff0d5b27c7f4c4fcc97f2b084bdc5834e92c9d32592778489029e65d99d00c406da612d87b72d7a236c0afccaa1435c028d0c94c9b6da4 + languageName: node + linkType: hard + "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -1107,22 +1319,6 @@ __metadata: languageName: node linkType: hard -"@hapi/hoek@npm:^9.0.0": - version: 9.2.1 - resolution: "@hapi/hoek@npm:9.2.1" - checksum: dd1268451a5072b005233da5b1d13d9e2d232b22ca44526275dc8d21992a5669221ec6c0706adc4341f85e24ca0fd6988b727e356b9c436128ab4e336593c35d - languageName: node - linkType: hard - -"@hapi/topo@npm:^5.0.0": - version: 5.1.0 - resolution: "@hapi/topo@npm:5.1.0" - dependencies: - "@hapi/hoek": "npm:^9.0.0" - checksum: 084bfa647015f4fd3fdd51fadb2747d09ef2f5e1443d6cbada2988b0c88494f85edf257ec606c790db146ac4e34ff57f3fcb22e3299b8e06ed5c87ba7583495c - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.11.13": version: 0.11.14 resolution: "@humanwhocodes/config-array@npm:0.11.14" @@ -1148,6 +1344,20 @@ __metadata: languageName: node linkType: hard +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 + languageName: node + linkType: hard + "@jest/schemas@npm:^29.6.3": version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" @@ -1178,6 +1388,17 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 81587b3c4dd8e6c60252122937cea0c637486311f4ed208b52b62aae2e7a87598f63ec330e6cd0984af494bfb16d3f0d60d3b21d7e5b4aedd2602ff3fe9d32e2 + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.0.3": version: 3.1.0 resolution: "@jridgewell/resolve-uri@npm:3.1.0" @@ -1199,6 +1420,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 + languageName: node + linkType: hard + "@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": version: 1.4.14 resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" @@ -1223,6 +1451,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: dced32160a44b49d531b80a4a2159dceab6b3ddf0c8e95a0deae4b0e894b172defa63d5ac52a19c2068e1fe7d31ea4ba931fbeec103233ecb4208953967120fc + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.14 resolution: "@jridgewell/trace-mapping@npm:0.3.14" @@ -1366,6 +1604,95 @@ __metadata: languageName: node linkType: hard +"@octokit/auth-token@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/auth-token@npm:4.0.0" + checksum: 60e42701e341d700f73c518c7a35675d36d79fa9d5e838cc3ade96d147e49f5ba74db2e07b2337c2b95aaa540aa42088116df2122daa25633f9e70a2c8785c44 + languageName: node + linkType: hard + +"@octokit/core@npm:5": + version: 5.1.0 + resolution: "@octokit/core@npm:5.1.0" + dependencies: + "@octokit/auth-token": "npm:^4.0.0" + "@octokit/graphql": "npm:^7.0.0" + "@octokit/request": "npm:^8.0.2" + "@octokit/request-error": "npm:^5.0.0" + "@octokit/types": "npm:^12.0.0" + before-after-hook: "npm:^2.2.0" + universal-user-agent: "npm:^6.0.0" + checksum: 8062e86a3088f24a691b36d2c3e9f33e864cefcb5f544b0633650358bce280708b111551cbe855ecf6a5190d6fc4fec1220117c329a2c27525940dd97b868614 + languageName: node + linkType: hard + +"@octokit/endpoint@npm:^9.0.0": + version: 9.0.4 + resolution: "@octokit/endpoint@npm:9.0.4" + dependencies: + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: 7df35c96f2b5628fe5b3f44a72614be9b439779c06b4dd1bb72283b3cb2ea53e59e1f9a108798efe5404b6856f4380a4c5be12d93255d854f0683cd6e22f3a27 + languageName: node + linkType: hard + +"@octokit/graphql@npm:^7.0.0": + version: 7.0.2 + resolution: "@octokit/graphql@npm:7.0.2" + dependencies: + "@octokit/request": "npm:^8.0.1" + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: f5dcc51fed5304f65dab83fcea4c2a569107d3b71e8d084199dc44f0d0cfc852c9e1f341b06ae66601f9da4af3aad416b0c62dcd0567ac7568f072d8d90d502e + languageName: node + linkType: hard + +"@octokit/openapi-types@npm:^20.0.0": + version: 20.0.0 + resolution: "@octokit/openapi-types@npm:20.0.0" + checksum: 9f60572af1201dd92626c412253d83d986b8ab1956250b95f417013ee8e7baf25870eeb801d16672cabc2c420544bc9c2f0a979e07603ff5997eff038c71a8c3 + languageName: node + linkType: hard + +"@octokit/request-error@npm:^5.0.0": + version: 5.0.1 + resolution: "@octokit/request-error@npm:5.0.1" + dependencies: + "@octokit/types": "npm:^12.0.0" + deprecation: "npm:^2.0.0" + once: "npm:^1.4.0" + checksum: a21a4614c46cb173e4ba73fa048576204f1ddc541dee3e7c938ef36088566e3b25e04ca1f96f375ec2e3cc29b7ba970b3b078a89a20bc50cdcdbed879db94573 + languageName: node + linkType: hard + +"@octokit/request@npm:^8.0.1, @octokit/request@npm:^8.0.2": + version: 8.2.0 + resolution: "@octokit/request@npm:8.2.0" + dependencies: + "@octokit/endpoint": "npm:^9.0.0" + "@octokit/request-error": "npm:^5.0.0" + "@octokit/types": "npm:^12.0.0" + universal-user-agent: "npm:^6.0.0" + checksum: 553ba8b99ea6fe2d3b66b2be6df06f7fe62a0b81e441d334ef25388cf0fcdab4a888fcfe2c1fb1ada262c233bcf7169da3ad5e03f024060ea5723f7753b0de3e + languageName: node + linkType: hard + +"@octokit/types@npm:^12.0.0": + version: 12.6.0 + resolution: "@octokit/types@npm:12.6.0" + dependencies: + "@octokit/openapi-types": "npm:^20.0.0" + checksum: 19b77a8d25af2a5df4561f8750f807edfc9fca5b07cfa9fb21dce4665e1b188c966688f5ed5e08089404428100dfe44ad353f8d8532f1d30fe47e61c5faa1440 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff + languageName: node + linkType: hard + "@radix-ui/colors@npm:^0.1.8": version: 0.1.8 resolution: "@radix-ui/colors@npm:0.1.8" @@ -1607,29 +1934,6 @@ __metadata: languageName: node linkType: hard -"@sideway/address@npm:^4.1.3": - version: 4.1.3 - resolution: "@sideway/address@npm:4.1.3" - dependencies: - "@hapi/hoek": "npm:^9.0.0" - checksum: 7224cd7127abb315573bd697836a1277edaaf4a93043e0ea76d5584191937e350dab85191176e19e3dbaa0ece888267bfcaa6e2c41541e151bdb0f7209a814f3 - languageName: node - linkType: hard - -"@sideway/formula@npm:^3.0.1": - version: 3.0.1 - resolution: "@sideway/formula@npm:3.0.1" - checksum: 8d3ee7f80df4e5204b2cbe92a2a711ca89684965a5c9eb3b316b7051212d3522e332a65a0bb2a07cc708fcd1d0b27fcb30f43ff0bcd5089d7006c7160a89eefe - languageName: node - linkType: hard - -"@sideway/pinpoint@npm:^2.0.0": - version: 2.0.0 - resolution: "@sideway/pinpoint@npm:2.0.0" - checksum: 1ed21800128b2b23280ba4c9db26c8ff6142b97a8683f17639fd7f2128aa09046461574800b30fb407afc5b663c2331795ccf3b654d4b38fa096e41a5c786bf8 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -1667,6 +1971,13 @@ __metadata: languageName: node linkType: hard +"@tsconfig/node18@npm:^18.2.2": + version: 18.2.2 + resolution: "@tsconfig/node18@npm:18.2.2" + checksum: 1c4b04b570e33de14bf518492e077079db2dcfba738c8d40c6ff916d94c9410246f4cb56f0802d9771423862140bf714c35d4a5f6cec2446d851cf61d3f8f9df + languageName: node + linkType: hard + "@tsconfig/strictest@npm:^2.0.2": version: 2.0.2 resolution: "@tsconfig/strictest@npm:2.0.2" @@ -1681,6 +1992,16 @@ __metadata: languageName: node linkType: hard +"@types/body-parser@npm:*": + version: 1.19.5 + resolution: "@types/body-parser@npm:1.19.5" + dependencies: + "@types/connect": "npm:*" + "@types/node": "npm:*" + checksum: 1e251118c4b2f61029cc43b0dc028495f2d1957fe8ee49a707fb940f86a9bd2f9754230805598278fe99958b49e9b7e66eec8ef6a50ab5c1f6b93e1ba2aaba82 + languageName: node + linkType: hard + "@types/cacheable-request@npm:^6.0.1": version: 6.0.3 resolution: "@types/cacheable-request@npm:6.0.3" @@ -1718,6 +2039,15 @@ __metadata: languageName: node linkType: hard +"@types/connect@npm:*": + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" + dependencies: + "@types/node": "npm:*" + checksum: 7eb1bc5342a9604facd57598a6c62621e244822442976c443efb84ff745246b10d06e8b309b6e80130026a396f19bf6793b7cecd7380169f369dac3bfc46fb99 + languageName: node + linkType: hard + "@types/css-modules@npm:^1.0.5": version: 1.0.5 resolution: "@types/css-modules@npm:1.0.5" @@ -1751,6 +2081,30 @@ __metadata: languageName: node linkType: hard +"@types/express-serve-static-core@npm:^4.17.33": + version: 4.17.43 + resolution: "@types/express-serve-static-core@npm:4.17.43" + dependencies: + "@types/node": "npm:*" + "@types/qs": "npm:*" + "@types/range-parser": "npm:*" + "@types/send": "npm:*" + checksum: 9079e137470e0456bb8e77ae66df9505ee12591e94860bde574cfe52c5c60bbc5bf7dd44f5689c3cbb1baf0aa84442d9a21f53dcd921d18745727293cd5a5fd6 + languageName: node + linkType: hard + +"@types/express@npm:^4.17.21": + version: 4.17.21 + resolution: "@types/express@npm:4.17.21" + dependencies: + "@types/body-parser": "npm:*" + "@types/express-serve-static-core": "npm:^4.17.33" + "@types/qs": "npm:*" + "@types/serve-static": "npm:*" + checksum: 7a6d26cf6f43d3151caf4fec66ea11c9d23166e4f3102edfe45a94170654a54ea08cf3103d26b3928d7ebcc24162c90488e33986b7e3a5f8941225edd5eb18c7 + languageName: node + linkType: hard + "@types/fs-extra@npm:9.0.13, @types/fs-extra@npm:^9.0.11": version: 9.0.13 resolution: "@types/fs-extra@npm:9.0.13" @@ -1776,6 +2130,13 @@ __metadata: languageName: node linkType: hard +"@types/http-errors@npm:*": + version: 2.0.4 + resolution: "@types/http-errors@npm:2.0.4" + checksum: 1f3d7c3b32c7524811a45690881736b3ef741bf9849ae03d32ad1ab7062608454b150a4e7f1351f83d26a418b2d65af9bdc06198f1c079d75578282884c4e8e3 + languageName: node + linkType: hard + "@types/js-cookie@npm:^2.2.6": version: 2.2.7 resolution: "@types/js-cookie@npm:2.2.7" @@ -1813,6 +2174,27 @@ __metadata: languageName: node linkType: hard +"@types/luxon@npm:^3.4.2": + version: 3.4.2 + resolution: "@types/luxon@npm:3.4.2" + checksum: fd89566e3026559f2bc4ddcc1e70a2c16161905ed50be9473ec0cfbbbe919165041408c4f6e06c4bcf095445535052e2c099087c76b1b38e368127e618fc968d + languageName: node + linkType: hard + +"@types/mime@npm:*": + version: 3.0.4 + resolution: "@types/mime@npm:3.0.4" + checksum: a6139c8e1f705ef2b064d072f6edc01f3c099023ad7c4fce2afc6c2bf0231888202adadbdb48643e8e20da0ce409481a49922e737eca52871b3dc08017455843 + languageName: node + linkType: hard + +"@types/mime@npm:^1": + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: e29a5f9c4776f5229d84e525b7cd7dd960b51c30a0fb9a028c0821790b82fca9f672dab56561e2acd9e8eed51d431bde52eafdfef30f643586c4162f1aecfc78 + languageName: node + linkType: hard + "@types/minimatch@npm:^3.0.3": version: 3.0.5 resolution: "@types/minimatch@npm:3.0.5" @@ -1820,6 +2202,15 @@ __metadata: languageName: node linkType: hard +"@types/morgan@npm:^1.9.9": + version: 1.9.9 + resolution: "@types/morgan@npm:1.9.9" + dependencies: + "@types/node": "npm:*" + checksum: a6969b4494de964d6b682fce93decd51988ec15a69be0d2766adacd5e942e06d9b4a5cad1708d6698b242edc5dee76ec6f909b81d68e148eb0634a0b6a4efb66 + languageName: node + linkType: hard + "@types/ms@npm:*": version: 0.7.31 resolution: "@types/ms@npm:0.7.31" @@ -1874,6 +2265,20 @@ __metadata: languageName: node linkType: hard +"@types/qs@npm:*": + version: 6.9.14 + resolution: "@types/qs@npm:6.9.14" + checksum: d3b76021d36b86c0063ec4b7373e9fa470754914e486fbfe54b3a8866dad037800a2c2068ecbcaa9399ae3ed15772a26b07e67793ed2519cf2de199104014716 + languageName: node + linkType: hard + +"@types/range-parser@npm:*": + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 95640233b689dfbd85b8c6ee268812a732cf36d5affead89e806fe30da9a430767af8ef2cd661024fd97e19d61f3dec75af2df5e80ec3bea000019ab7028629a + languageName: node + linkType: hard + "@types/react-dom@npm:^18.2.22": version: 18.2.22 resolution: "@types/react-dom@npm:18.2.22" @@ -1955,6 +2360,27 @@ __metadata: languageName: node linkType: hard +"@types/send@npm:*": + version: 0.17.4 + resolution: "@types/send@npm:0.17.4" + dependencies: + "@types/mime": "npm:^1" + "@types/node": "npm:*" + checksum: 28320a2aa1eb704f7d96a65272a07c0bf3ae7ed5509c2c96ea5e33238980f71deeed51d3631927a77d5250e4091b3e66bce53b42d770873282c6a20bb8b0280d + languageName: node + linkType: hard + +"@types/serve-static@npm:*": + version: 1.15.5 + resolution: "@types/serve-static@npm:1.15.5" + dependencies: + "@types/http-errors": "npm:*" + "@types/mime": "npm:*" + "@types/node": "npm:*" + checksum: 49aa21c367fffe4588fc8c57ea48af0ea7cbadde7418bc53cde85d8bd57fd2a09a293970d9ea86e79f17a87f8adeb3e20da76aab38e1c4d1567931fa15c8af38 + languageName: node + linkType: hard + "@types/sortablejs@npm:^1.15.0": version: 1.15.0 resolution: "@types/sortablejs@npm:1.15.0" @@ -1983,6 +2409,13 @@ __metadata: languageName: node linkType: hard +"@types/yargs-parser@npm:^21.0.3": + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b + languageName: node + linkType: hard + "@types/yauzl@npm:^2.9.1": version: 2.10.0 resolution: "@types/yauzl@npm:2.10.0" @@ -2318,13 +2751,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^2.0.0": - version: 2.1.1 - resolution: "ansi-regex@npm:2.1.1" - checksum: 190abd03e4ff86794f338a31795d262c1dfe8c91f7e01d04f13f646f1dcb16c5800818f886047876f1272f065570ab86b24b99089f8b68a0e11ff19aed4ca8f1 - languageName: node - linkType: hard - "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -2332,6 +2758,13 @@ __metadata: languageName: node linkType: hard +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 + languageName: node + linkType: hard + "ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" @@ -2357,6 +2790,13 @@ __metadata: languageName: node linkType: hard +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: 70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 + languageName: node + linkType: hard + "app-builder-bin@npm:4.0.0": version: 4.0.0 resolution: "app-builder-bin@npm:4.0.0" @@ -2445,13 +2885,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3": - version: 1.2.0 - resolution: "aproba@npm:1.2.0" - checksum: 48def777330afca699880126b555273cd9912525500edc5866b527da6fd6c54badd3ae6cc6039081e5bc22e9b349d8e65fd70f8499beb090f86aa6261e4242dd - languageName: node - linkType: hard - "aproba@npm:^1.0.3 || ^2.0.0": version: 2.0.0 resolution: "aproba@npm:2.0.0" @@ -2469,16 +2902,6 @@ __metadata: languageName: node linkType: hard -"are-we-there-yet@npm:~1.1.2": - version: 1.1.7 - resolution: "are-we-there-yet@npm:1.1.7" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^2.0.6" - checksum: 5fc14ea29ed1ae480117c177b31c6e6da6f02c0fd6d5071b7e4a1373adf42539f5d81f178358dab58b10fc929bf7650c5ed0153ae9cc98eff97285189cb6b836 - languageName: node - linkType: hard - "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" @@ -2706,25 +3129,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.21.1": - version: 0.21.4 - resolution: "axios@npm:0.21.4" - dependencies: - follow-redirects: "npm:^1.14.0" - checksum: da644592cb6f8f9f8c64fdabd7e1396d6769d7a4c1ea5f8ae8beb5c2eb90a823e3a574352b0b934ac62edc762c0f52647753dc54f7d07279127a7e5c4cd20272 - languageName: node - linkType: hard - -"axios@npm:^0.27.2": - version: 0.27.2 - resolution: "axios@npm:0.27.2" - dependencies: - follow-redirects: "npm:^1.14.9" - form-data: "npm:^4.0.0" - checksum: 2efaf18dd0805f7bc772882bc86f004abd92d51007b54c5081f74db0d08ce3593e2c010261896d25a14318eeaa2e966fd825e34f810e8a3339dc64b9d177cf70 - languageName: node - linkType: hard - "axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" @@ -2764,6 +3168,13 @@ __metadata: languageName: node linkType: hard +"before-after-hook@npm:^2.2.0": + version: 2.2.3 + resolution: "before-after-hook@npm:2.2.3" + checksum: e676f769dbc4abcf4b3317db2fd2badb4a92c0710e0a7da12cf14b59c3482d4febf835ad7de7874499060fd4e13adf0191628e504728b3c5bb4ec7a878c09940 + languageName: node + linkType: hard + "bl@npm:^4.0.3": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -2914,7 +3325,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.22.3": +"browserslist@npm:^4.22.2, browserslist@npm:^4.22.3": version: 4.23.0 resolution: "browserslist@npm:4.23.0" dependencies: @@ -3355,13 +3766,6 @@ __metadata: languageName: node linkType: hard -"code-point-at@npm:^1.0.0": - version: 1.1.0 - resolution: "code-point-at@npm:1.1.0" - checksum: 17d5666611f9b16d64fdf48176d9b7fb1c7d1c1607a189f7e600040a11a6616982876af148230336adb7d8fe728a559f743a4e29db3747e3b1a32fa7f4529681 - languageName: node - linkType: hard - "color-convert@npm:^1.9.0, color-convert@npm:^1.9.3": version: 1.9.3 resolution: "color-convert@npm:1.9.3" @@ -3423,7 +3827,7 @@ __metadata: languageName: node linkType: hard -"color@npm:^4.0.1, color@npm:^4.2.3": +"color@npm:^4.2.3": version: 4.2.3 resolution: "color@npm:4.2.3" dependencies: @@ -3573,7 +3977,7 @@ __metadata: languageName: node linkType: hard -"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0, console-control-strings@npm:~1.1.0": +"console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" checksum: 27b5fa302bc8e9ae9e98c03c66d76ca289ad0c61ce2fe20ab288d288bee875d217512d2edb2363fc83165e88f1c405180cf3f5413a46e51b4fe1a004840c6cdb @@ -3605,6 +4009,13 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: c987be3ec061348cdb3c2bfb924bec86dea1eacad10550a85ca23edb0fe3556c3a61c7399114f3331ccb3499d7fd0285ab24566e5745929412983494c3926e15 + languageName: node + linkType: hard + "cookie-signature@npm:1.0.6": version: 1.0.6 resolution: "cookie-signature@npm:1.0.6" @@ -3667,19 +4078,7 @@ __metadata: languageName: node linkType: hard -"cross-env@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-env@npm:7.0.3" - dependencies: - cross-spawn: "npm:^7.0.1" - bin: - cross-env: src/bin/cross-env.js - cross-env-shell: src/bin/cross-env-shell.js - checksum: e99911f0d31c20e990fd92d6fd001f4b01668a303221227cc5cb42ed155f086351b1b3bd2699b200e527ab13011b032801f8ce638e6f09f854bdf744095e604c - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" dependencies: @@ -3909,22 +4308,6 @@ __metadata: languageName: node linkType: hard -"del@npm:^6.0.0": - version: 6.0.0 - resolution: "del@npm:6.0.0" - dependencies: - globby: "npm:^11.0.1" - graceful-fs: "npm:^4.2.4" - is-glob: "npm:^4.0.1" - is-path-cwd: "npm:^2.2.0" - is-path-inside: "npm:^3.0.2" - p-map: "npm:^4.0.0" - rimraf: "npm:^3.0.2" - slash: "npm:^3.0.0" - checksum: 5742891627e91aaf62385714025233f4664da28bc55b6ab825649dcdea4691fed3cf329a2b1913fd2d2612e693e99e08a03c84cac7f36ef54bacac9390520192 - languageName: node - linkType: hard - "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -3953,6 +4336,13 @@ __metadata: languageName: node linkType: hard +"deprecation@npm:^2.0.0": + version: 2.3.1 + resolution: "deprecation@npm:2.3.1" + checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132 + languageName: node + linkType: hard + "dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" @@ -3967,15 +4357,6 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^1.0.3": - version: 1.0.3 - resolution: "detect-libc@npm:1.0.3" - bin: - detect-libc: ./bin/detect-libc.js - checksum: 3849fe7720feb153e4ac9407086956e073f1ce1704488290ef0ca8aab9430a8d48c8a9f8351889e7cdc64e5b1128589501e4fef48f3a4a49ba92cd6d112d0757 - languageName: node - linkType: hard - "detect-libc@npm:^2.0.0": version: 2.0.1 resolution: "detect-libc@npm:2.0.1" @@ -4174,6 +4555,13 @@ __metadata: languageName: node linkType: hard +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -4285,6 +4673,28 @@ __metadata: languageName: node linkType: hard +"electron-vite@npm:^2.1.0": + version: 2.1.0 + resolution: "electron-vite@npm:2.1.0" + dependencies: + "@babel/core": "npm:^7.23.5" + "@babel/plugin-transform-arrow-functions": "npm:^7.23.3" + cac: "npm:^6.7.14" + esbuild: "npm:^0.19.8" + magic-string: "npm:^0.30.5" + picocolors: "npm:^1.0.0" + peerDependencies: + "@swc/core": ^1.0.0 + vite: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + "@swc/core": + optional: true + bin: + electron-vite: bin/electron-vite.js + checksum: 29f1d1d80e88db27952ba0ba7039dccfe161acd20186e0d6d2a7af5e38a303821e3ab09d058041d9d929e6c2fabdae95d182c1f38872946872100e837ff9e9b5 + languageName: node + linkType: hard + "electron@npm:^27.0.0": version: 27.0.0 resolution: "electron@npm:27.0.0" @@ -4691,7 +5101,7 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.19.3": +"esbuild@npm:^0.19.3, esbuild@npm:^0.19.8, esbuild@npm:~0.19.10": version: 0.19.12 resolution: "esbuild@npm:0.19.12" dependencies: @@ -5151,23 +5561,6 @@ __metadata: languageName: node linkType: hard -"execa@npm:5": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^6.0.0" - human-signals: "npm:^2.1.0" - is-stream: "npm:^2.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^4.0.1" - onetime: "npm:^5.1.2" - signal-exit: "npm:^3.0.3" - strip-final-newline: "npm:^2.0.0" - checksum: 8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 - languageName: node - linkType: hard - "execa@npm:^8.0.1": version: 8.0.1 resolution: "execa@npm:8.0.1" @@ -5515,16 +5908,6 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" - peerDependenciesMeta: - debug: - optional: true - checksum: 70c7612c4cab18e546e36b991bbf8009a1a41cf85354afe04b113d1117569abf760269409cb3eb842d9f7b03d62826687086b081c566ea7b1e6613cf29030bf7 - languageName: node - linkType: hard - "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -5534,6 +5917,16 @@ __metadata: languageName: node linkType: hard +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 087edd44857d258c4f73ad84cb8df980826569656f2550c341b27adf5335354393eec24ea2fabd43a253233fb27cee177ebe46bd0b7ea129c77e87cb1e9936fb + languageName: node + linkType: hard + "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -5793,22 +6186,6 @@ __metadata: languageName: node linkType: hard -"gauge@npm:~2.7.3": - version: 2.7.4 - resolution: "gauge@npm:2.7.4" - dependencies: - aproba: "npm:^1.0.3" - console-control-strings: "npm:^1.0.0" - has-unicode: "npm:^2.0.0" - object-assign: "npm:^4.1.0" - signal-exit: "npm:^3.0.0" - string-width: "npm:^1.0.1" - strip-ansi: "npm:^3.0.1" - wide-align: "npm:^1.1.0" - checksum: 0db20a7def238f0e8eab50226247e1f94f1446ab24700eab0a56e5ccf23ce85ccf8f0c0c462112b89beb964431b1edabd3f7b31f1f6d5f62294c453594523993 - languageName: node - linkType: hard - "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -5863,13 +6240,6 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: 781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 - languageName: node - linkType: hard - "get-stream@npm:^8.0.1": version: 8.0.1 resolution: "get-stream@npm:8.0.1" @@ -5888,15 +6258,12 @@ __metadata: languageName: node linkType: hard -"github-api@npm:^3.2.2": - version: 3.4.0 - resolution: "github-api@npm:3.4.0" +"get-tsconfig@npm:^4.7.2": + version: 4.7.3 + resolution: "get-tsconfig@npm:4.7.3" dependencies: - axios: "npm:^0.21.1" - debug: "npm:^2.2.0" - js-base64: "npm:^2.1.9" - utf8: "npm:^2.1.1" - checksum: fdf48af33b1ec8eeeb37cceca102d21f82a9de6da6e31aa355bbcddf92af24d17938b7eebbc3e9c3a327944ccc5d9b5526e3d7cbc0b5371091969432dcd07d62 + resolve-pkg-maps: "npm:^1.0.0" + checksum: 7397bb4f8aef936df4d9016555b662dcf5279f3c46428b7c7c1ff5e94ab2b87d018b3dda0f4bc1a28b154d5affd0eac5d014511172c085fd8a9cdff9ea7fe043 languageName: node linkType: hard @@ -5966,6 +6333,21 @@ __metadata: languageName: node linkType: hard +"glob@npm:^10.3.7": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.3.5" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/esm/bin.mjs + checksum: 38bdb2c9ce75eb5ed168f309d4ed05b0798f640b637034800a6bf306f39d35409bf278b0eaaffaec07591085d3acb7184a201eae791468f0f617771c2486a6a8 + languageName: node + linkType: hard + "glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.0 resolution: "glob@npm:7.2.0" @@ -6041,7 +6423,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.1, globby@npm:^11.1.0": +"globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -6083,7 +6465,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.0.0, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.0.0, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": version: 4.2.9 resolution: "graceful-fs@npm:4.2.9" checksum: 4bcf2de4f1108a928dd64d5e894b833cba634b2e82729c0e57f327d384bf15098e4706639f3045e587e845afed06bae52e70916f74a42db5a56e9ca44f6c2fd1 @@ -6166,7 +6548,7 @@ __metadata: languageName: node linkType: hard -"has-unicode@npm:^2.0.0, has-unicode@npm:^2.0.1": +"has-unicode@npm:^2.0.1": version: 2.0.1 resolution: "has-unicode@npm:2.0.1" checksum: 041b4293ad6bf391e21c5d85ed03f412506d6623786b801c4ab39e4e6ca54993f13201bceb544d92963f9e0024e6e7fbf0cb1d84c9d6b31cb9c79c8c990d13d8 @@ -6351,13 +6733,6 @@ __metadata: languageName: node linkType: hard -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 - languageName: node - linkType: hard - "human-signals@npm:^5.0.0": version: 5.0.0 resolution: "human-signals@npm:5.0.0" @@ -6434,19 +6809,16 @@ __metadata: languageName: node linkType: hard -"icon-gen@npm:^3.0.0": - version: 3.0.0 - resolution: "icon-gen@npm:3.0.0" +"icon-gen@npm:^4.0.0": + version: 4.0.0 + resolution: "icon-gen@npm:4.0.0" dependencies: commander: "npm:^8.3.0" - del: "npm:^6.0.0" - mkdirp: "npm:^1.0.4" - pngjs: "npm:^6.0.0" - sharp: "npm:^0.29.3" - uuid: "npm:^8.3.2" + pngjs: "npm:^7.0.0" + sharp: "npm:^0.32.4" bin: icon-gen: dist/bin/index.js - checksum: e695d5abcc3375f158e90f19d60af4b3fef95e571d6934287ce952f63f39d2ce8a9dc4411a0c974a732deb67cbd8a70430b16cde78027f24c5cc2c2dcbd964cc + checksum: d4c829659dfe2cde2379ea5bfae4fba2efed04af3f60aa12eecca8f4b92b2c0f82a266b044ac70db5d9869f787264bb22aab17336a5e73580c018408d8235a88 languageName: node linkType: hard @@ -6782,15 +7154,6 @@ __metadata: languageName: node linkType: hard -"is-fullwidth-code-point@npm:^1.0.0": - version: 1.0.0 - resolution: "is-fullwidth-code-point@npm:1.0.0" - dependencies: - number-is-nan: "npm:^1.0.0" - checksum: 4d46a7465a66a8aebcc5340d3b63a56602133874af576a9ca42c6f0f4bd787a743605771c5f246db77da96605fefeffb65fc1dbe862dcc7328f4b4d03edf5a57 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -6890,14 +7253,7 @@ __metadata: languageName: node linkType: hard -"is-path-cwd@npm:^2.2.0": - version: 2.2.0 - resolution: "is-path-cwd@npm:2.2.0" - checksum: 46a840921bb8cc0dc7b5b423a14220e7db338072a4495743a8230533ce78812dc152548c86f4b828411fe98c5451959f07cf841c6a19f611e46600bd699e8048 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": +"is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 @@ -7122,6 +7478,19 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 6e6490d676af8c94a7b5b29b8fd5629f21346911ebe2e32931c2a54210134408171c24cee1a109df2ec19894ad04a429402a8438cbf5cc2794585d35428ace76 + languageName: node + linkType: hard + "jake@npm:^10.8.5": version: 10.8.5 resolution: "jake@npm:10.8.5" @@ -7136,26 +7505,6 @@ __metadata: languageName: node linkType: hard -"joi@npm:^17.7.0": - version: 17.7.1 - resolution: "joi@npm:17.7.1" - dependencies: - "@hapi/hoek": "npm:^9.0.0" - "@hapi/topo": "npm:^5.0.0" - "@sideway/address": "npm:^4.1.3" - "@sideway/formula": "npm:^3.0.1" - "@sideway/pinpoint": "npm:^2.0.0" - checksum: 2df890d5a7de74207a089d77416bcba8004fdf42c696f0960f93d16494ae757c3216a4e0df533c746af2071287032f29c1c50d02c0efab06dfb870c944577e8c - languageName: node - linkType: hard - -"js-base64@npm:^2.1.9": - version: 2.6.4 - resolution: "js-base64@npm:2.6.4" - checksum: c1a740a34fbb0ad0a528c2ab8749d7f873b1856a0638826306fcd98502e3c8c833334dff233085407e3201be543e5e71bf9692da7891ca680d9b03d027247a6a - languageName: node - linkType: hard - "js-cookie@npm:^2.2.1": version: 2.2.1 resolution: "js-cookie@npm:2.2.1" @@ -7272,7 +7621,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.2.2": +"json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -7560,25 +7909,30 @@ __metadata: dependencies: "@electron/remote": "npm:^2.0.10" "@fontsource/open-sans": "npm:^4.5.14" + "@octokit/core": "npm:5" "@radix-ui/colors": "npm:^0.1.8" "@radix-ui/react-switch": "npm:^1.0.1" + "@tsconfig/node18": "npm:^18.2.2" "@tsconfig/strictest": "npm:^2.0.2" "@tsconfig/vite-react": "npm:^3.0.0" "@types/color": "npm:^3.0.6" "@types/css-modules": "npm:^1.0.5" "@types/eslint": "npm:^8" + "@types/express": "npm:^4.17.21" "@types/lodash": "npm:^4.14.202" + "@types/luxon": "npm:^3.4.2" + "@types/morgan": "npm:^1.9.9" "@types/node": "npm:18" "@types/react": "npm:^18.2.66" "@types/react-dom": "npm:^18.2.22" "@types/sortablejs": "npm:^1.15.0" + "@types/yargs-parser": "npm:^21.0.3" "@typescript-eslint/eslint-plugin": "npm:^6.12.0" "@typescript-eslint/parser": "npm:^6.12.0" "@uidotdev/usehooks": "npm:^2.4.1" "@vitejs/plugin-react": "npm:^3.1.0" color: "npm:^3.1.0" concurrently: "npm:^6.0.0" - cross-env: "npm:^7.0.3" csv-parse: "npm:^4.15.3" csv-stringify: "npm:^5.6.2" cue-parser: "npm:^0.3.0" @@ -7586,9 +7940,9 @@ __metadata: electron: "npm:^27.0.0" electron-builder: "npm:^24.6.4" electron-devtools-installer: "npm:^3.2.0" - electron-is-dev: "npm:^2.0.0" electron-store: "npm:5.1.1" electron-unhandled: "npm:^4.0.1" + electron-vite: "npm:^2.1.0" eslint: "npm:^8.2.0" eslint-config-mifi: "npm:^0.0.3" eslint-plugin-import: "npm:^2.25.3" @@ -7597,7 +7951,7 @@ __metadata: eslint-plugin-react-hooks: "npm:^4.3.0" eslint-plugin-unicorn: "npm:^51.0.1" evergreen-ui: "npm:^6.13.1" - execa: "npm:5" + execa: "npm:^8.0.1" express: "npm:^4.18.2" express-async-handler: "npm:^1.2.0" fast-xml-parser: "npm:^4.2.5" @@ -7605,11 +7959,10 @@ __metadata: file-url: "npm:^3.0.0" framer-motion: "npm:^9.0.3" fs-extra: "npm:^8.1.0" - github-api: "npm:^3.2.2" i18next: "npm:^22.4.10" i18next-fs-backend: "npm:^2.1.1" i18next-parser: "npm:^7.6.0" - icon-gen: "npm:^3.0.0" + icon-gen: "npm:^4.0.0" immer: "npm:^10.0.2" json5: "npm:^2.2.2" ky: "npm:^0.33.1" @@ -7632,24 +7985,25 @@ __metadata: react-sortablejs: "npm:^6.1.4" react-syntax-highlighter: "npm:^15.4.3" react-use: "npm:^17.4.0" + rimraf: "npm:^5.0.5" screenfull: "npm:^6.0.2" scroll-into-view-if-needed: "npm:^2.2.28" semver: "npm:^7.5.2" sharp: "npm:^0.32.6" smpte-timecode: "npm:^1.2.3" sortablejs: "npm:^1.13.0" - string-to-stream: "npm:^1.1.1" + string-to-stream: "npm:^3.0.1" sweetalert2: "npm:^11.0.0" sweetalert2-react-content: "npm:^5.0.7" tiny-invariant: "npm:^1.3.3" + tsx: "npm:^4.7.1" typescript: "npm:~5.2.0" use-debounce: "npm:^5.1.0" use-trace-update: "npm:^1.3.0" vite: "npm:^4.5.2" vitest: "npm:^1.2.2" - wait-on: "npm:^7.0.1" winston: "npm:^3.8.1" - yargs-parser: "npm:^21.0.0" + yargs-parser: "npm:^21.1.1" languageName: unknown linkType: soft @@ -7720,6 +8074,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.2.0 + resolution: "lru-cache@npm:10.2.0" + checksum: 502ec42c3309c0eae1ce41afca471f831c278566d45a5273a0c51102dee31e0e250a62fa9029c3370988df33a14188a38e682c16143b794de78668de3643e302 + languageName: node + linkType: hard + "luxon@npm:^3.3.0": version: 3.3.0 resolution: "luxon@npm:3.3.0" @@ -7934,7 +8295,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:9.0.3": +"minimatch@npm:9.0.3, minimatch@npm:^9.0.1": version: 9.0.3 resolution: "minimatch@npm:9.0.3" dependencies: @@ -7984,7 +8345,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.6, minimist@npm:^1.2.7": +"minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f @@ -8067,6 +8428,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": + version: 7.0.4 + resolution: "minipass@npm:7.0.4" + checksum: e864bd02ceb5e0707696d58f7ce3a0b89233f0d686ef0d447a66db705c0846a8dc6f34865cd85256c1472ff623665f616b90b8ff58058b2ad996c5de747d2d18 + languageName: node + linkType: hard + "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -8240,15 +8608,6 @@ __metadata: languageName: node linkType: hard -"node-addon-api@npm:^4.2.0": - version: 4.2.0 - resolution: "node-addon-api@npm:4.2.0" - dependencies: - node-gyp: "npm:latest" - checksum: 27a51793848b9159c134378a0e19394ba02bfb1e23b856ba9feb2560f6c5f182cca77a42f011d08c2dd38725c7cad1294241b8db1ab605aa0b404046b73b297a - languageName: node - linkType: hard - "node-addon-api@npm:^6.1.0": version: 6.1.0 resolution: "node-addon-api@npm:6.1.0" @@ -8350,15 +8709,6 @@ __metadata: languageName: node linkType: hard -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: "npm:^3.0.0" - checksum: 5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - "npm-run-path@npm:^5.1.0": version: 5.2.0 resolution: "npm-run-path@npm:5.2.0" @@ -8368,18 +8718,6 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^4.0.1": - version: 4.1.2 - resolution: "npmlog@npm:4.1.2" - dependencies: - are-we-there-yet: "npm:~1.1.2" - console-control-strings: "npm:~1.1.0" - gauge: "npm:~2.7.3" - set-blocking: "npm:~2.0.0" - checksum: b6b85c9f33da8f600f72564b6ec71136b1641b8b235fca7cc543d1041acb74c2d989d97fe443a0e65754f438d9a974a2fe1b4ff8723c78ef3f9b7a6d74b02079 - languageName: node - linkType: hard - "npmlog@npm:^6.0.0": version: 6.0.2 resolution: "npmlog@npm:6.0.2" @@ -8401,13 +8739,6 @@ __metadata: languageName: node linkType: hard -"number-is-nan@npm:^1.0.0": - version: 1.0.1 - resolution: "number-is-nan@npm:1.0.1" - checksum: 13656bc9aa771b96cef209ffca31c31a03b507ca6862ba7c3f638a283560620d723d52e626d57892c7fff475f4c36ac07f0600f14544692ff595abff214b9ffb - languageName: node - linkType: hard - "object-assign@npm:^4.1.0, object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -8559,7 +8890,7 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^5.1.0, onetime@npm:^5.1.2": +"onetime@npm:^5.1.0": version: 5.1.2 resolution: "onetime@npm:5.1.2" dependencies: @@ -8793,7 +9124,7 @@ __metadata: languageName: node linkType: hard -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": +"path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 @@ -8821,6 +9152,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" + dependencies: + lru-cache: "npm:^9.1.1 || ^10.0.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: eebfb8304fef1d4f7e1486df987e4fd77413de4fce16508dea69fcf8eb318c09a6b15a7a2f4c22877cec1cb7ecbd3071d18ca9de79eeece0df874a00f1f0bdc8 + languageName: node + linkType: hard + "path-to-regexp@npm:0.1.7": version: 0.1.7 resolution: "path-to-regexp@npm:0.1.7" @@ -8939,10 +9280,10 @@ __metadata: languageName: node linkType: hard -"pngjs@npm:^6.0.0": - version: 6.0.0 - resolution: "pngjs@npm:6.0.0" - checksum: 692751ccd5e762623103900922caac982caa90258d9c6c04a6e2bc3397b1dedbaf9db826fc0fa068a29d607cad3df1d1eded0dec2ee35a0015c65cb5ef33ad18 +"pngjs@npm:^7.0.0": + version: 7.0.0 + resolution: "pngjs@npm:7.0.0" + checksum: e843ebbb0df092ee0f3a3e7dbd91ff87a239a4e4c4198fff202916bfb33b67622f4b83b3c29f3ccae94fcb97180c289df06068624554f61686fe6b9a4811f7db languageName: node linkType: hard @@ -8975,29 +9316,6 @@ __metadata: languageName: node linkType: hard -"prebuild-install@npm:^7.0.0": - version: 7.1.0 - resolution: "prebuild-install@npm:7.1.0" - dependencies: - detect-libc: "npm:^2.0.0" - expand-template: "npm:^2.0.3" - github-from-package: "npm:0.0.0" - minimist: "npm:^1.2.3" - mkdirp-classic: "npm:^0.5.3" - napi-build-utils: "npm:^1.0.1" - node-abi: "npm:^3.3.0" - npmlog: "npm:^4.0.1" - pump: "npm:^3.0.0" - rc: "npm:^1.2.7" - simple-get: "npm:^4.0.0" - tar-fs: "npm:^2.0.0" - tunnel-agent: "npm:^0.6.0" - bin: - prebuild-install: bin.js - checksum: 7c05e13b6778e7854a9fed7516f74d8b04d6bbe869466859506bded274980bfe28051501f57e8d57982c45d7fc74ff0937fd8db56b38c76e04d0a18ece50b463 - languageName: node - linkType: hard - "prebuild-install@npm:^7.1.1": version: 7.1.1 resolution: "prebuild-install@npm:7.1.1" @@ -9465,7 +9783,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.5, readable-stream@npm:^2.0.6, readable-stream@npm:^2.1.0, readable-stream@npm:^2.1.5, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.5, readable-stream@npm:^2.1.5, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": version: 2.3.7 resolution: "readable-stream@npm:2.3.7" dependencies: @@ -9647,6 +9965,13 @@ __metadata: languageName: node linkType: hard +"resolve-pkg-maps@npm:^1.0.0": + version: 1.0.0 + resolution: "resolve-pkg-maps@npm:1.0.0" + checksum: 0763150adf303040c304009231314d1e84c6e5ebfa2d82b7d94e96a6e82bacd1dcc0b58ae257315f3c8adb89a91d8d0f12928241cba2df1680fbe6f60bf99b0e + languageName: node + linkType: hard + "resolve@npm:^1.10.0, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" @@ -9758,6 +10083,17 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^5.0.5": + version: 5.0.5 + resolution: "rimraf@npm:5.0.5" + dependencies: + glob: "npm:^10.3.7" + bin: + rimraf: dist/esm/bin.mjs + checksum: a612c7184f96258b7d1328c486b12ca7b60aa30e04229a08bbfa7e964486deb1e9a1b52d917809311bdc39a808a4055c0f950c0280fba194ba0a09e6f0d404f6 + languageName: node + linkType: hard + "roarr@npm:^2.15.3": version: 2.15.4 resolution: "roarr@npm:2.15.4" @@ -9881,15 +10217,6 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.8.0": - version: 7.8.0 - resolution: "rxjs@npm:7.8.0" - dependencies: - tslib: "npm:^2.1.0" - checksum: ff9359cc7875edecc8fc487481366b876b488901178cca8f2bdad03e00d2b5a19b01d2b02d3b4ebd47e574264db8460c6c2386076c3189b359b5e8c70a6e51e3 - languageName: node - linkType: hard - "safe-array-concat@npm:^1.1.0": version: 1.1.0 resolution: "safe-array-concat@npm:1.1.0" @@ -10107,7 +10434,7 @@ __metadata: languageName: node linkType: hard -"set-blocking@npm:^2.0.0, set-blocking@npm:~2.0.0": +"set-blocking@npm:^2.0.0": version: 2.0.0 resolution: "set-blocking@npm:2.0.0" checksum: 8980ebf7ae9eb945bb036b6e283c547ee783a1ad557a82babf758a065e2fb6ea337fd82cac30dd565c1e606e423f30024a19fff7afbf4977d784720c4026a8ef @@ -10161,24 +10488,7 @@ __metadata: languageName: node linkType: hard -"sharp@npm:^0.29.3": - version: 0.29.3 - resolution: "sharp@npm:0.29.3" - dependencies: - color: "npm:^4.0.1" - detect-libc: "npm:^1.0.3" - node-addon-api: "npm:^4.2.0" - node-gyp: "npm:latest" - prebuild-install: "npm:^7.0.0" - semver: "npm:^7.3.5" - simple-get: "npm:^4.0.0" - tar-fs: "npm:^2.1.1" - tunnel-agent: "npm:^0.6.0" - checksum: 6c427b687ce4e01ec0328c5bb943a2001deaa4ad0df710dc9ebe23d800fc92a608b0dd6987b68a2666f07180c80d70258616766157385e2ba3dda8bc6d73c11b - languageName: node - linkType: hard - -"sharp@npm:^0.32.6": +"sharp@npm:^0.32.4, sharp@npm:^0.32.6": version: 0.32.6 resolution: "sharp@npm:0.32.6" dependencies: @@ -10229,21 +10539,21 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2": +"signal-exit@npm:^3.0.2": version: 3.0.6 resolution: "signal-exit@npm:3.0.6" checksum: b819ac81ba757af559dad0804233ae31bf6f054591cd8a671e9cbcf09f21c72ec3076fe87d1e04861f5b33b47d63f0694b568de99c99cd733ee2060515beb6d5 languageName: node linkType: hard -"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 languageName: node linkType: hard -"signal-exit@npm:^4.1.0": +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f @@ -10556,28 +10866,16 @@ __metadata: languageName: node linkType: hard -"string-to-stream@npm:^1.1.1": - version: 1.1.1 - resolution: "string-to-stream@npm:1.1.1" +"string-to-stream@npm:^3.0.1": + version: 3.0.1 + resolution: "string-to-stream@npm:3.0.1" dependencies: - inherits: "npm:^2.0.1" - readable-stream: "npm:^2.1.0" - checksum: f4ad5f2a845faa59adc4b12c1141ab2303ccdfa4e768d0f8c63af7b2a136f19bfe80e3f7eb8abf577803fd6d13895767d2b2e9560705f1aa0747329cbaea708c + readable-stream: "npm:^3.4.0" + checksum: 422d68a8bbb018b63bf2c028cafb8b507f272b4c045cc6493adedb26ad7ceb81cc0e2399804cd5fd9e0207de5753bb5b0ff087181c5ebf0a5620f9c3d4a3a183 languageName: node linkType: hard -"string-width@npm:^1.0.1": - version: 1.0.2 - resolution: "string-width@npm:1.0.2" - dependencies: - code-point-at: "npm:^1.0.0" - is-fullwidth-code-point: "npm:^1.0.0" - strip-ansi: "npm:^3.0.0" - checksum: 5c79439e95bc3bd7233a332c5f5926ab2ee90b23816ed4faa380ce3b2576d7800b0a5bb15ae88ed28737acc7ea06a518c2eef39142dd727adad0e45c776cd37e - languageName: node - linkType: hard - -"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -10588,6 +10886,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + languageName: node + linkType: hard + "string.prototype.matchall@npm:^4.0.8": version: 4.0.10 resolution: "string.prototype.matchall@npm:4.0.10" @@ -10656,16 +10965,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^3.0.0, strip-ansi@npm:^3.0.1": - version: 3.0.1 - resolution: "strip-ansi@npm:3.0.1" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 9b974de611ce5075c70629c00fa98c46144043db92ae17748fb780f706f7a789e9989fd10597b7c2053ae8d1513fd707816a91f1879b2f71e6ac0b6a863db465 - languageName: node - linkType: hard - -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: @@ -10674,6 +10974,15 @@ __metadata: languageName: node linkType: hard +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 + languageName: node + linkType: hard + "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -10681,13 +10990,6 @@ __metadata: languageName: node linkType: hard -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - "strip-final-newline@npm:^3.0.0": version: 3.0.0 resolution: "strip-final-newline@npm:3.0.0" @@ -10819,7 +11121,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.1": +"tar-fs@npm:^2.0.0": version: 2.1.1 resolution: "tar-fs@npm:2.1.1" dependencies: @@ -11177,6 +11479,22 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^4.7.1": + version: 4.7.1 + resolution: "tsx@npm:4.7.1" + dependencies: + esbuild: "npm:~0.19.10" + fsevents: "npm:~2.3.3" + get-tsconfig: "npm:^4.7.2" + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: 3a462b595f31ae58b31f9c6e8c450577dc87660b1225012bd972b6b58d7d2f6c4034728763ebc53bb731acff68de8b0fa50586e4c1ec4c086226f1788ccf9b7d + languageName: node + linkType: hard + "tunnel-agent@npm:^0.6.0": version: 0.6.0 resolution: "tunnel-agent@npm:0.6.0" @@ -11442,6 +11760,13 @@ __metadata: languageName: node linkType: hard +"universal-user-agent@npm:^6.0.0": + version: 6.0.1 + resolution: "universal-user-agent@npm:6.0.1" + checksum: fdc8e1ae48a05decfc7ded09b62071f571c7fe0bd793d700704c80cea316101d4eac15cc27ed2bb64f4ce166d2684777c3198b9ab16034f547abea0d3aa1c93c + languageName: node + linkType: hard + "universalify@npm:^0.1.0": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -11534,13 +11859,6 @@ __metadata: languageName: node linkType: hard -"utf8@npm:^2.1.1": - version: 2.1.2 - resolution: "utf8@npm:2.1.2" - checksum: 7b35ff1203d2e0209db7a28f6852cb64ff292a3bdc3b6a9c52ff2d69abcfeff992647e8d4dc787c4f1c9374613ad11f7e9c682df66985dfa516b8f8c69855860 - languageName: node - linkType: hard - "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -11555,15 +11873,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 9a5f7aa1d6f56dd1e8d5f2478f855f25c645e64e26e347a98e98d95781d5ed20062d6cca2eecb58ba7c84bc3910be95c0451ef4161906abaab44f9cb68ffbdd1 - languageName: node - linkType: hard - "validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4" @@ -11829,21 +12138,6 @@ __metadata: languageName: node linkType: hard -"wait-on@npm:^7.0.1": - version: 7.0.1 - resolution: "wait-on@npm:7.0.1" - dependencies: - axios: "npm:^0.27.2" - joi: "npm:^17.7.0" - lodash: "npm:^4.17.21" - minimist: "npm:^1.2.7" - rxjs: "npm:^7.8.0" - bin: - wait-on: bin/wait-on - checksum: 9f76c0eb89785745fd0c20332d447e5f3505a84997aca4ab19e1a961c2ccd39cf60cb805ff4223184593a133cd84d6170f9eb1cdc105d0d31eb55a0703d6d432 - languageName: node - linkType: hard - "walk-sync@npm:^2.2.0": version: 2.2.0 resolution: "walk-sync@npm:2.2.0" @@ -11944,7 +12238,7 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.0, wide-align@npm:^1.1.5": +"wide-align@npm:^1.1.5": version: 1.1.5 resolution: "wide-align@npm:1.1.5" dependencies: @@ -11982,7 +12276,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -11993,6 +12287,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -12068,13 +12373,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^21.0.0": - version: 21.0.0 - resolution: "yargs-parser@npm:21.0.0" - checksum: bbfa0daa49d46d07954fc9c9088037628d603a4862b08fb97183d5cf905791a9b0beb95866637c63453b73475a4187d76cfba7503ccfc79fd66bbd11a8afb032 - languageName: node - linkType: hard - "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1"