Bye Bye Desktop App
This commit is contained in:
parent
69d71b99d1
commit
8ed52d8843
23 changed files with 1670 additions and 5031 deletions
|
|
@ -1,11 +1,10 @@
|
|||
# Node Alpine -- multi-arch (amd64 + arm64)
|
||||
FROM oven/bun:1.3.10-alpine AS builder
|
||||
FROM oven/bun:1.3.11-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies required for Bun and Neutralino
|
||||
# Install system dependencies required for Bun
|
||||
RUN apk add --no-cache wget curl bash
|
||||
RUN apk add --no-cache python3 make g++ && ln -sf python3 /usr/bin/python
|
||||
|
||||
# Accept build arguments for environment variables
|
||||
ARG AUTH_ENABLED
|
||||
|
|
@ -24,7 +23,7 @@ RUN bun install
|
|||
# Copy the rest of the project
|
||||
COPY . .
|
||||
|
||||
# Build the project (Bun is now available for "bun x neu build")
|
||||
# Build the project
|
||||
RUN bun run build
|
||||
|
||||
# Serve with nginx
|
||||
|
|
|
|||
125
bun.lock
125
bun.lock
|
|
@ -15,7 +15,6 @@
|
|||
"@ffmpeg/ffmpeg": "^0.12.15",
|
||||
"@ffmpeg/util": "^0.12.2",
|
||||
"@kawarp/core": "^1.1.1",
|
||||
"@neutralinojs/lib": "^6.5.0",
|
||||
"@svta/common-media-library": "^0.18.1",
|
||||
"@uimaxbai/am-lyrics": "^1.1.4",
|
||||
"appwrite": "^23.0.0",
|
||||
|
|
@ -41,7 +40,6 @@
|
|||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
"@capacitor/cli": "^8.2.0",
|
||||
"@neutralinojs/neu": "^11.7.0",
|
||||
"@types/node": "^25.3.5",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
|
@ -55,7 +53,6 @@
|
|||
"stylelint-config-standard-scss": "^16.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-neutralino": "^1.0.3",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
},
|
||||
},
|
||||
|
|
@ -292,8 +289,6 @@
|
|||
|
||||
"@dual-bundle/import-meta-resolve": ["@dual-bundle/import-meta-resolve@4.2.1", "", {}, "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg=="],
|
||||
|
||||
"@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q=="],
|
||||
|
|
@ -476,10 +471,6 @@
|
|||
|
||||
"@lit/reactive-element": ["@lit/reactive-element@2.1.2", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0" } }, "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A=="],
|
||||
|
||||
"@neutralinojs/lib": ["@neutralinojs/lib@6.5.0", "", { "optionalDependencies": { "@rollup/rollup-darwin-x64": "*", "@rollup/rollup-linux-x64-gnu": "*" } }, "sha512-ECgYh+CXAfMR1JVTvDw/kHhjL6LzNNcjk8Va1DZUSBkUwROqFTQ7zseFeuFtwGvutqvlWiwpGmU3s11rg/bdvA=="],
|
||||
|
||||
"@neutralinojs/neu": ["@neutralinojs/neu@11.7.0", "", { "dependencies": { "@electron/asar": "^3.0.3", "chalk": "^4.1.0", "chokidar": "^4.0.3", "commander": "^7.2.0", "configstore": "^5.0.1", "edit-json-file": "^1.6.2", "follow-redirects": "^1.13.1", "fs-extra": "^9.0.1", "pe-library": "^1.0.1", "png2icons": "^2.0.1", "postject": "1.0.0-alpha.6", "recursive-readdir": "^2.2.2", "resedit": "^2.0.2", "spawn-command": "^1.0.0", "tcp-port-used": "^1.0.2", "uuid": "^8.3.2", "websocket": "^1.0.35", "zip-lib": "^1.0.4" }, "bin": { "neu": "bin/neu.js" } }, "sha512-fUqvR70a+BpKI9mrD92ldZkVC24Rs8XL/9m7zmOCLgCRys3yuWy7vEsxpHzKMzqTiQJkTYIsLmcR8VMzNIjuSw=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
|
@ -728,8 +719,6 @@
|
|||
|
||||
"chevrotain": ["chevrotain@7.1.1", "", { "dependencies": { "regexp-to-ast": "0.5.0" } }, "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw=="],
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||
|
||||
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
|
||||
|
|
@ -756,8 +745,6 @@
|
|||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"configstore": ["configstore@5.0.1", "", { "dependencies": { "dot-prop": "^5.2.0", "graceful-fs": "^4.1.2", "make-dir": "^3.0.0", "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" } }, "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA=="],
|
||||
|
||||
"conventional-changelog": ["conventional-changelog@3.1.25", "", { "dependencies": { "conventional-changelog-angular": "^5.0.12", "conventional-changelog-atom": "^2.0.8", "conventional-changelog-codemirror": "^2.0.8", "conventional-changelog-conventionalcommits": "^4.5.0", "conventional-changelog-core": "^4.2.1", "conventional-changelog-ember": "^2.0.9", "conventional-changelog-eslint": "^3.0.9", "conventional-changelog-express": "^2.0.6", "conventional-changelog-jquery": "^3.0.11", "conventional-changelog-jshint": "^2.0.9", "conventional-changelog-preset-loader": "^2.3.4" } }, "sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ=="],
|
||||
|
||||
"conventional-changelog-angular": ["conventional-changelog-angular@5.0.13", "", { "dependencies": { "compare-func": "^2.0.0", "q": "^1.5.1" } }, "sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA=="],
|
||||
|
|
@ -822,8 +809,6 @@
|
|||
|
||||
"csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="],
|
||||
|
||||
"d": ["d@1.0.2", "", { "dependencies": { "es5-ext": "^0.10.64", "type": "^2.7.2" } }, "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw=="],
|
||||
|
||||
"dargs": ["dargs@7.0.0", "", {}, "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg=="],
|
||||
|
||||
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
|
||||
|
|
@ -880,8 +865,6 @@
|
|||
|
||||
"ecma-proposal-math-extensions": ["ecma-proposal-math-extensions@0.0.2", "", {}, "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q=="],
|
||||
|
||||
"edit-json-file": ["edit-json-file@1.8.1", "", { "dependencies": { "find-value": "^1.0.12", "iterate-object": "^1.3.4", "r-json": "^1.2.10", "set-value": "^4.1.0", "w-json": "^1.3.10" } }, "sha512-x8L381+GwqxQejPipwrUZIyAg5gDQ9tLVwiETOspgXiaQztLsrOm7luBW5+Pe31aNezuzDY79YyzF+7viCRPXA=="],
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.328", "", {}, "sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w=="],
|
||||
|
|
@ -912,12 +895,6 @@
|
|||
|
||||
"es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
|
||||
|
||||
"es5-ext": ["es5-ext@0.10.64", "", { "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", "esniff": "^2.0.1", "next-tick": "^1.1.0" } }, "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg=="],
|
||||
|
||||
"es6-iterator": ["es6-iterator@2.0.3", "", { "dependencies": { "d": "1", "es5-ext": "^0.10.35", "es6-symbol": "^3.1.1" } }, "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g=="],
|
||||
|
||||
"es6-symbol": ["es6-symbol@3.1.4", "", { "dependencies": { "d": "^1.0.2", "ext": "^1.7.0" } }, "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.27.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.4", "@esbuild/android-arm": "0.27.4", "@esbuild/android-arm64": "0.27.4", "@esbuild/android-x64": "0.27.4", "@esbuild/darwin-arm64": "0.27.4", "@esbuild/darwin-x64": "0.27.4", "@esbuild/freebsd-arm64": "0.27.4", "@esbuild/freebsd-x64": "0.27.4", "@esbuild/linux-arm": "0.27.4", "@esbuild/linux-arm64": "0.27.4", "@esbuild/linux-ia32": "0.27.4", "@esbuild/linux-loong64": "0.27.4", "@esbuild/linux-mips64el": "0.27.4", "@esbuild/linux-ppc64": "0.27.4", "@esbuild/linux-riscv64": "0.27.4", "@esbuild/linux-s390x": "0.27.4", "@esbuild/linux-x64": "0.27.4", "@esbuild/netbsd-arm64": "0.27.4", "@esbuild/netbsd-x64": "0.27.4", "@esbuild/openbsd-arm64": "0.27.4", "@esbuild/openbsd-x64": "0.27.4", "@esbuild/openharmony-arm64": "0.27.4", "@esbuild/sunos-x64": "0.27.4", "@esbuild/win32-arm64": "0.27.4", "@esbuild/win32-ia32": "0.27.4", "@esbuild/win32-x64": "0.27.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
|
@ -932,8 +909,6 @@
|
|||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
|
||||
|
||||
"esniff": ["esniff@2.0.1", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.62", "event-emitter": "^0.3.5", "type": "^2.7.2" } }, "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg=="],
|
||||
|
||||
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
|
||||
|
||||
"esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
|
||||
|
|
@ -946,8 +921,6 @@
|
|||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"event-emitter": ["event-emitter@0.3.5", "", { "dependencies": { "d": "1", "es5-ext": "~0.10.14" } }, "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
|
||||
|
||||
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||
|
|
@ -956,8 +929,6 @@
|
|||
|
||||
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||
|
||||
"ext": ["ext@1.7.0", "", { "dependencies": { "type": "^2.7.2" } }, "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="],
|
||||
|
|
@ -986,14 +957,10 @@
|
|||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"find-value": ["find-value@1.0.13", "", {}, "sha512-epNL4mnl3HUYrwVQtZ8s0nxkE4ogAoSqO1V1fa670Ww1fXp8Yr74zNS9Aib/vLNf0rq0AF/4mboo7ev5XkikXQ=="],
|
||||
|
||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||
|
||||
"flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="],
|
||||
|
||||
"follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="],
|
||||
|
||||
"for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
|
@ -1118,8 +1085,6 @@
|
|||
|
||||
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
||||
|
||||
"ip-regex": ["ip-regex@4.3.0", "", {}, "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q=="],
|
||||
|
||||
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="],
|
||||
|
|
@ -1160,7 +1125,7 @@
|
|||
|
||||
"is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="],
|
||||
|
||||
"is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
|
||||
"is-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="],
|
||||
|
||||
"is-path-cwd": ["is-path-cwd@2.2.0", "", {}, "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ=="],
|
||||
|
||||
|
|
@ -1170,8 +1135,6 @@
|
|||
|
||||
"is-plain-object": ["is-plain-object@5.0.0", "", {}, "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="],
|
||||
|
||||
"is-primitive": ["is-primitive@3.0.1", "", {}, "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w=="],
|
||||
|
||||
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
|
||||
|
||||
"is-regexp": ["is-regexp@1.0.0", "", {}, "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA=="],
|
||||
|
|
@ -1190,10 +1153,6 @@
|
|||
|
||||
"is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="],
|
||||
|
||||
"is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="],
|
||||
|
||||
"is-url": ["is-url@1.2.4", "", {}, "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="],
|
||||
|
||||
"is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="],
|
||||
|
||||
"is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="],
|
||||
|
|
@ -1202,16 +1161,10 @@
|
|||
|
||||
"is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="],
|
||||
|
||||
"is2": ["is2@2.0.9", "", { "dependencies": { "deep-is": "^0.1.3", "ip-regex": "^4.1.0", "is-url": "^1.2.4" } }, "sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g=="],
|
||||
|
||||
"isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="],
|
||||
|
||||
"iterate-object": ["iterate-object@1.3.5", "", {}, "sha512-eL23u8oFooYTq6TtJKjp2RYjZnCkUYQvC0T/6fJfWykXJ3quvdDdzKZ3CEjy8b3JGOvLTjDYMEMIp5243R906A=="],
|
||||
|
||||
"jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="],
|
||||
|
||||
"jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="],
|
||||
|
|
@ -1290,8 +1243,6 @@
|
|||
|
||||
"magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "^1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="],
|
||||
|
||||
"make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="],
|
||||
|
||||
"make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="],
|
||||
|
||||
"map-obj": ["map-obj@4.3.0", "", {}, "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="],
|
||||
|
|
@ -1346,8 +1297,6 @@
|
|||
|
||||
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
||||
|
||||
"next-tick": ["next-tick@1.1.0", "", {}, "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="],
|
||||
|
||||
"node-abi": ["node-abi@3.89.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA=="],
|
||||
|
||||
"node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="],
|
||||
|
|
@ -1412,8 +1361,6 @@
|
|||
|
||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||
|
||||
"pe-library": ["pe-library@1.0.1", "", {}, "sha512-nh39Mo1eGWmZS7y+mK/dQIqg7S1lp38DpRxkyoHf0ZcUs/HDc+yyTjuOtTvSMZHmfSLuSQaX945u05Y2Q6UWZg=="],
|
||||
|
||||
"pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
|
@ -1424,8 +1371,6 @@
|
|||
|
||||
"plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="],
|
||||
|
||||
"png2icons": ["png2icons@2.0.1", "", { "bin": { "png2icons": "./png2icons-cli.js" } }, "sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA=="],
|
||||
|
||||
"pocketbase": ["pocketbase@0.26.8", "", {}, "sha512-aQ/ewvS7ncvAE8wxoW10iAZu6ElgbeFpBhKPnCfvRovNzm2gW8u/sQNPGN6vNgVEagz44kK//C61oKjfa+7Low=="],
|
||||
|
||||
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
|
||||
|
|
@ -1444,8 +1389,6 @@
|
|||
|
||||
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
|
||||
|
||||
"postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "^9.4.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="],
|
||||
|
||||
"prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
|
@ -1470,8 +1413,6 @@
|
|||
|
||||
"quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="],
|
||||
|
||||
"r-json": ["r-json@1.3.1", "", { "dependencies": { "w-json": "1.3.10" } }, "sha512-5nhRFfjVMQdrwKUfUlRpDUCocdKtjSnYZ1R/86mpZDV3MfsZ3dYYNjSGuMX+mPBvFvQBhdzxSqxkuLPLv4uFGg=="],
|
||||
|
||||
"rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
|
||||
|
||||
"read-pkg": ["read-pkg@3.0.0", "", { "dependencies": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", "path-type": "^3.0.0" } }, "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA=="],
|
||||
|
|
@ -1480,10 +1421,6 @@
|
|||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"recursive-readdir": ["recursive-readdir@2.2.3", "", { "dependencies": { "minimatch": "^3.0.5" } }, "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA=="],
|
||||
|
||||
"redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="],
|
||||
|
||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||
|
|
@ -1512,8 +1449,6 @@
|
|||
|
||||
"require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="],
|
||||
|
||||
"resedit": ["resedit@2.0.3", "", { "dependencies": { "pe-library": "^1.0.1" } }, "sha512-oTeemxwoMuxxTYxXUwjkrOPfngTQehlv0/HoYFNkB4uzsP1Un1A9nI8JQKGOFkxpqkC7qkMs0lUsGrvUlbLNUA=="],
|
||||
|
||||
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
|
||||
|
||||
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||
|
|
@ -1548,8 +1483,6 @@
|
|||
|
||||
"set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="],
|
||||
|
||||
"set-value": ["set-value@4.1.0", "", { "dependencies": { "is-plain-object": "^2.0.4", "is-primitive": "^3.0.1" } }, "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw=="],
|
||||
|
||||
"shaka-player": ["shaka-player@5.0.8", "", {}, "sha512-f886rKRvQ0IKhWGk+rINS++YTjTJyc4DT5YypTsHW6wiNV9fiHi2n35+lg5R+hj9RfhqkmJHMjJb3gprUTNa8w=="],
|
||||
|
||||
"sharp": ["sharp@0.32.6", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.1", "semver": "^7.5.4", "simple-get": "^4.0.1", "tar-fs": "^3.0.4", "tunnel-agent": "^0.6.0" } }, "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w=="],
|
||||
|
|
@ -1594,8 +1527,6 @@
|
|||
|
||||
"sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"spawn-command": ["spawn-command@1.0.0", "", {}, "sha512-zsboEQnjeF6tSJ8SRnojMr22HyFEaRaohgTt0Kgx3BgzkXYiboh09vpmZVIq1HOLzkFZDgFJJfwGUqSbb5fQQQ=="],
|
||||
|
||||
"spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="],
|
||||
|
||||
"spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
|
||||
|
|
@ -1668,8 +1599,6 @@
|
|||
|
||||
"tar-stream": ["tar-stream@3.1.8", "", { "dependencies": { "b4a": "^1.6.4", "bare-fs": "^4.5.5", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ=="],
|
||||
|
||||
"tcp-port-used": ["tcp-port-used@1.0.2", "", { "dependencies": { "debug": "4.3.1", "is2": "^2.0.6" } }, "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA=="],
|
||||
|
||||
"teex": ["teex@1.0.1", "", { "dependencies": { "streamx": "^2.12.5" } }, "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg=="],
|
||||
|
||||
"temp-dir": ["temp-dir@2.0.0", "", {}, "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg=="],
|
||||
|
|
@ -1706,8 +1635,6 @@
|
|||
|
||||
"tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
|
||||
|
||||
"type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"type-fest": ["type-fest@0.16.0", "", {}, "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg=="],
|
||||
|
|
@ -1720,8 +1647,6 @@
|
|||
|
||||
"typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="],
|
||||
|
||||
"typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
|
||||
|
|
@ -1766,16 +1691,10 @@
|
|||
|
||||
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
|
||||
|
||||
"vite-plugin-neutralino": ["vite-plugin-neutralino@1.0.3", "", {}, "sha512-E/PSTCp7m7efk7fa4eE12WQ+5XGNP72gkhOv61X4i0n+NcnrwKtJgEgeCDGUXeLp4ngTfU/CP+EF55jmZs/0Jw=="],
|
||||
|
||||
"vite-plugin-pwa": ["vite-plugin-pwa@1.2.0", "", { "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", "workbox-build": "^7.4.0", "workbox-window": "^7.4.0" }, "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" }, "optionalPeers": ["@vite-pwa/assets-generator"] }, "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw=="],
|
||||
|
||||
"w-json": ["w-json@1.3.11", "", {}, "sha512-Xa8vTinB5XBIYZlcN8YyHpE625pBU6k+lvCetTQM+FKxRtLJxAY9zUVZbRqCqkMeEGbQpKvGUzwh4wZKGem+ag=="],
|
||||
|
||||
"webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||
|
||||
"websocket": ["websocket@1.0.35", "", { "dependencies": { "bufferutil": "^4.0.1", "debug": "^2.2.0", "es5-ext": "^0.10.63", "typedarray-to-buffer": "^3.1.5", "utf-8-validate": "^5.0.2", "yaeti": "^0.0.6" } }, "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q=="],
|
||||
|
||||
"whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
|
@ -1838,8 +1757,6 @@
|
|||
|
||||
"xcode": ["xcode@3.0.1", "", { "dependencies": { "simple-plist": "^1.1.0", "uuid": "^7.0.3" } }, "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA=="],
|
||||
|
||||
"xdg-basedir": ["xdg-basedir@4.0.0", "", {}, "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="],
|
||||
|
||||
"xml": ["xml@1.0.1", "", {}, "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw=="],
|
||||
|
||||
"xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": { "xml-js": "./bin/cli.js" } }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="],
|
||||
|
|
@ -1854,8 +1771,6 @@
|
|||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yaeti": ["yaeti@0.0.6", "", {}, "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
|
@ -1864,8 +1779,6 @@
|
|||
|
||||
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
||||
|
||||
"yazl": ["yazl@3.3.1", "", { "dependencies": { "buffer-crc32": "^1.0.0" } }, "sha512-BbETDVWG+VcMUle37k5Fqp//7SDOK2/1+T7X8TD96M3D9G8jK5VLUdQVdVjGi8im7FGkazX7kk5hkU8X4L5Bng=="],
|
||||
|
||||
"yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
|
@ -1874,8 +1787,6 @@
|
|||
|
||||
"youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="],
|
||||
|
||||
"zip-lib": ["zip-lib@1.3.1", "", { "dependencies": { "yauzl": "^3.2.1", "yazl": "^3.3.1" } }, "sha512-fgtJsv4yuqbgo7MC2F2n2pVlAGO9VjHOzmK2p9yPw8LKNRfAbm7Mmvw0Ji6AZRDAqJqT3XGe6AzwwI6LggobVA=="],
|
||||
|
||||
"@apideck/better-ajv-errors/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||
|
||||
"@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
|
@ -1912,10 +1823,6 @@
|
|||
|
||||
"@capacitor/cli/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="],
|
||||
|
||||
"@electron/asar/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
|
||||
|
||||
"@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
|
@ -1968,12 +1875,6 @@
|
|||
|
||||
"@keyv/bigmap/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
|
||||
|
||||
"@neutralinojs/neu/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
|
||||
|
||||
"@neutralinojs/neu/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
|
||||
|
||||
"@neutralinojs/neu/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
|
||||
|
||||
"@poppinss/dumper/supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
|
||||
|
||||
"@rollup/plugin-babel/rollup": ["rollup@2.80.0", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ=="],
|
||||
|
|
@ -2000,8 +1901,6 @@
|
|||
|
||||
"cacheable/keyv": ["keyv@5.6.0", "", { "dependencies": { "@keyv/serialize": "^1.1.1" } }, "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw=="],
|
||||
|
||||
"configstore/write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="],
|
||||
|
||||
"conventional-changelog-writer/meow": ["meow@8.1.2", "", { "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", "type-fest": "^0.18.0", "yargs-parser": "^20.2.3" } }, "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q=="],
|
||||
|
||||
"conventional-changelog-writer/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
|
@ -2018,6 +1917,8 @@
|
|||
|
||||
"del/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
|
||||
|
||||
"dot-prop/is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="],
|
||||
|
||||
"elementtree/sax": ["sax@1.1.4", "", {}, "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg=="],
|
||||
|
||||
"eslint/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
|
@ -2060,8 +1961,6 @@
|
|||
|
||||
"load-json-file/pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="],
|
||||
|
||||
"make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"mergexml/xpath": ["xpath@0.0.27", "", {}, "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="],
|
||||
|
|
@ -2360,16 +2259,12 @@
|
|||
|
||||
"plist/@xmldom/xmldom": ["@xmldom/xmldom@0.8.11", "", {}, "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw=="],
|
||||
|
||||
"postject/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="],
|
||||
|
||||
"prebuild-install/tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="],
|
||||
|
||||
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"qified/hookified": ["hookified@2.1.0", "", {}, "sha512-ootKng4eaxNxa7rx6FJv2YKef3DuhqbEj3l70oGXwddPQEEnISm50TEZQclqiLTAtilT2nu7TErtCO523hHkyg=="],
|
||||
|
||||
"r-json/w-json": ["w-json@1.3.10", "", {}, "sha512-XadVyw0xE+oZ5FGApXsdswv96rOhStzKqL53uSe5UaTadABGkWIg1+DTx8kiZ/VqTZTBneoL0l65RcPe4W3ecw=="],
|
||||
|
||||
"rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
|
||||
|
||||
"rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
|
||||
|
|
@ -2386,14 +2281,10 @@
|
|||
|
||||
"replace/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
|
||||
|
||||
"set-value/is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="],
|
||||
|
||||
"simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="],
|
||||
|
||||
"simple-swizzle/is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="],
|
||||
|
||||
"stringify-object/is-obj": ["is-obj@1.0.1", "", {}, "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg=="],
|
||||
|
||||
"stylelint/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"stylelint/file-entry-cache": ["file-entry-cache@11.1.2", "", { "dependencies": { "flat-cache": "^6.1.20" } }, "sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log=="],
|
||||
|
|
@ -2404,16 +2295,12 @@
|
|||
|
||||
"table/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||
|
||||
"tcp-port-used/debug": ["debug@4.3.1", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ=="],
|
||||
|
||||
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
|
||||
|
||||
"ts-node/diff": ["diff@4.0.4", "", {}, "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ=="],
|
||||
|
||||
"vite-plugin-pwa/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
|
||||
|
||||
"workbox-build/ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
|
||||
|
||||
"workbox-build/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
|
||||
|
|
@ -2432,10 +2319,6 @@
|
|||
|
||||
"xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
|
||||
|
||||
"yazl/buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="],
|
||||
|
||||
"zip-lib/yauzl": ["yauzl@3.2.1", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-k1isifdbpNSFEHFJ1ZY4YDewv0IH9FR61lDetaRMD3j2ae3bIXGV+7c+LHCqtQGofSd8PIyV4X6+dHMAnSr60A=="],
|
||||
|
||||
"@apideck/better-ajv-errors/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"@babel/core/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
|
@ -2584,8 +2467,6 @@
|
|||
|
||||
"vite-plugin-pwa/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"websocket/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"workbox-build/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"workbox-build/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ export default [
|
|||
'**/bin/**',
|
||||
'**/www/**',
|
||||
'**/public/lib/**',
|
||||
'**/public/neutralino.js',
|
||||
],
|
||||
},
|
||||
js.configs.recommended,
|
||||
|
|
@ -23,7 +22,6 @@ export default [
|
|||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
Neutralino: 'readonly',
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
|
|
|
|||
|
|
@ -1,102 +0,0 @@
|
|||
# bridge.ps1 - Diagnostic Version
|
||||
$Log = Join-Path $PSScriptRoot "bridge.log"
|
||||
function Log($m) { Add-Content $Log "$(Get-Date -f 'HH:mm:ss') - $m" }
|
||||
|
||||
Log "--- START (DIAGNOSTIC) ---"
|
||||
|
||||
# 1. PID
|
||||
$p = Get-Process Monochrome -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $p) { $p = Get-Process neutralino-win_x64 -ErrorAction SilentlyContinue | Select-Object -First 1 }
|
||||
$pid_to_send = if ($p) { $p.Id } else { [System.Diagnostics.Process]::GetCurrentProcess().Id }
|
||||
|
||||
# 2. Discord Connection
|
||||
function Get-Pipe {
|
||||
for ($i = 0; $i -le 9; $i++) {
|
||||
try {
|
||||
$pn = "discord-ipc-$i"
|
||||
$p = New-Object System.IO.Pipes.NamedPipeClientStream(".", $pn, [System.IO.Pipes.PipeDirection]::InOut)
|
||||
$p.Connect(100)
|
||||
return $p
|
||||
} catch { }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
$pipe = Get-Pipe; if (-not $pipe) { Log "Discord Fail"; exit }
|
||||
|
||||
function Send-Packet($op, $json) {
|
||||
if ($op -eq 1) { Log "Sending Activity: $json" }
|
||||
$j = [System.Text.Encoding]::UTF8.GetBytes($json)
|
||||
[byte[]]$pkt = [BitConverter]::GetBytes([int]$op) + [BitConverter]::GetBytes([int]$j.Length) + $j
|
||||
$pipe.Write($pkt, 0, $pkt.Length); $pipe.Flush()
|
||||
}
|
||||
|
||||
# 3. Handshake
|
||||
Send-Packet 0 (@{ v = 1; client_id = "1462186088184549661" } | ConvertTo-Json -Compress)
|
||||
$h = New-Object byte[] 8; if ($pipe.Read($h, 0, 8) -eq 8) {
|
||||
$l = [BitConverter]::ToInt32($h, 4); $b = New-Object byte[] $l; $pipe.Read($b, 0, $l) | Out-Null
|
||||
Log "Handshake OK"
|
||||
}
|
||||
|
||||
function Set-Activity($d, $s, $img, $start, $end, $large_text, $small_img, $small_txt) {
|
||||
$activity = @{
|
||||
details = [string]$d
|
||||
state = [string]$s
|
||||
type = 2
|
||||
assets = @{
|
||||
large_image = if ($img -and $img.StartsWith("http")) { [string]$img } else { "monochrome" }
|
||||
large_text = if ($large_text) { [string]$large_text } else { "Monochrome" }
|
||||
}
|
||||
}
|
||||
|
||||
if ($small_img) {
|
||||
$activity.assets.small_image = [string]$small_img
|
||||
$activity.assets.small_text = [string]$small_txt
|
||||
}
|
||||
|
||||
if ($start -or $end) {
|
||||
$activity.timestamps = @{}
|
||||
if ($start) { $activity.timestamps.start = [long]$start }
|
||||
if ($end) { $activity.timestamps.end = [long]$end }
|
||||
}
|
||||
|
||||
# CRITICAL: -Depth 10 ensures 'assets' is not stringified as a class name
|
||||
$payload = @{
|
||||
cmd = "SET_ACTIVITY"
|
||||
args = @{ pid = [int]$pid_to_send; activity = $activity }
|
||||
nonce = [Guid]::NewGuid().ToString()
|
||||
} | ConvertTo-Json -Compress -Depth 10
|
||||
|
||||
Send-Packet 1 $payload
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 1
|
||||
Set-Activity "Idling" "Monochrome" $null $null $null $null $null $null
|
||||
|
||||
# 4. Config & WS
|
||||
$line = [Console]::In.ReadLine()
|
||||
if (-not $line) { exit }
|
||||
$config = $line | ConvertFrom-Json
|
||||
|
||||
$ws = New-Object System.Net.WebSockets.ClientWebSocket
|
||||
try {
|
||||
$uri = [Uri]"ws://127.0.0.1:$($config.nlPort)?extensionId=$($config.nlExtensionId)&connectToken=$($config.nlConnectToken)"
|
||||
$ws.ConnectAsync($uri, [System.Threading.CancellationToken]::None).Wait()
|
||||
Log "WS Connected"
|
||||
} catch { exit }
|
||||
|
||||
# 5. Loop
|
||||
$buf = New-Object byte[] 65536
|
||||
while ($ws.State -eq "Open") {
|
||||
$task = $ws.ReceiveAsync((New-Object ArraySegment[byte] -ArgumentList @(,$buf)), [System.Threading.CancellationToken]::None)
|
||||
while (-not $task.Wait(1000)) { if (-not (Get-Process -Id $pid_to_send -ErrorAction SilentlyContinue)) { exit } }
|
||||
if ($task.Result.Count -gt 0) {
|
||||
try {
|
||||
$raw = [System.Text.Encoding]::UTF8.GetString($buf, 0, $task.Result.Count)
|
||||
$msg = $raw | ConvertFrom-Json
|
||||
if ($msg.event -eq "discord:update") {
|
||||
Set-Activity $msg.data.details $msg.data.state $msg.data.largeImageKey $msg.data.startTimestamp $msg.data.endTimestamp $msg.data.largeImageText $msg.data.smallImageKey $msg.data.smallImageText
|
||||
}
|
||||
elseif ($msg.event -eq "discord:clear") { Set-Activity "Idling" "Monochrome" $null $null $null $null $null $null }
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,165 +0,0 @@
|
|||
# bridge.py - Production Discord RPC Bridge (Linux/macOS)
|
||||
import sys, json, socket, struct, os, uuid, base64, time
|
||||
|
||||
CLIENT_ID = "1462186088184549661"
|
||||
LAST_STATUS = ""
|
||||
|
||||
def get_discord_path():
|
||||
for i in range(10):
|
||||
path = os.path.join(os.environ.get('XDG_RUNTIME_DIR', '/tmp'), f'discord-ipc-{i}')
|
||||
if os.path.exists(path): return path
|
||||
return None
|
||||
|
||||
def send_packet(s, op, data):
|
||||
payload = json.dumps(data).encode('utf-8')
|
||||
header = struct.pack('<II', op, len(payload))
|
||||
s.sendall(header + payload)
|
||||
|
||||
def recv_packet(s):
|
||||
try:
|
||||
header = s.recv(8)
|
||||
if len(header) < 8: return None
|
||||
op, length = struct.unpack('<II', header)
|
||||
payload = s.recv(length)
|
||||
return json.loads(payload.decode('utf-8'))
|
||||
except Exception:
|
||||
# Ignore errors and return None
|
||||
return None
|
||||
|
||||
def set_activity(ds, pid, details, state, img=None, start=None, end=None, large_text=None, small_img=None, small_txt=None):
|
||||
global LAST_STATUS
|
||||
current = f"{details}-{state}-{img}-{start}-{end}-{large_text}-{small_img}-{small_txt}"
|
||||
if current == LAST_STATUS: return
|
||||
LAST_STATUS = current
|
||||
|
||||
activity = {
|
||||
"details": str(details or "Idling"),
|
||||
"state": str(state or "Monochrome"),
|
||||
"type": 2, # Listening
|
||||
"assets": {
|
||||
"large_image": img if img and img.startswith('http') else "monochrome",
|
||||
"large_text": str(large_text or "Monochrome")
|
||||
}
|
||||
}
|
||||
|
||||
if small_img:
|
||||
activity["assets"]["small_image"] = str(small_img)
|
||||
activity["assets"]["small_text"] = str(small_txt or "")
|
||||
|
||||
if start or end:
|
||||
activity["timestamps"] = {}
|
||||
if start: activity["timestamps"]["start"] = int(start)
|
||||
if end: activity["timestamps"]["end"] = int(end)
|
||||
|
||||
send_packet(ds, 1, {
|
||||
"cmd": "SET_ACTIVITY",
|
||||
"args": {"pid": pid, "activity": activity},
|
||||
"nonce": str(uuid.uuid4())
|
||||
})
|
||||
|
||||
def main():
|
||||
# 1. Read config
|
||||
try:
|
||||
line = sys.stdin.readline()
|
||||
if not line: return
|
||||
config = json.loads(line)
|
||||
except Exception:
|
||||
# Ignore errors and exit
|
||||
return
|
||||
|
||||
ppid = os.getppid()
|
||||
|
||||
# 2. Connect to Discord
|
||||
ipc_path = get_discord_path()
|
||||
if not ipc_path: return
|
||||
try:
|
||||
ds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
ds.connect(ipc_path)
|
||||
except Exception:
|
||||
# Ignore connection errors and exit
|
||||
return
|
||||
|
||||
# 3. Handshake
|
||||
send_packet(ds, 0, {"v": 1, "client_id": CLIENT_ID})
|
||||
recv_packet(ds) # Mandatory read
|
||||
|
||||
time.sleep(0.5)
|
||||
set_activity(ds, ppid, "Idling", "Monochrome")
|
||||
|
||||
# 4. Minimal WebSocket Client
|
||||
ws = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
ws.settimeout(1.0)
|
||||
try:
|
||||
ws.connect(('127.0.0.1', int(config['nlPort'])))
|
||||
except Exception:
|
||||
# Ignore connection errors and exit
|
||||
return
|
||||
|
||||
key = base64.b64encode(os.urandom(16)).decode()
|
||||
handshake = (
|
||||
f"GET /?extensionId={config['nlExtensionId']}&connectToken={config['nlConnectToken']} HTTP/1.1\r\n"
|
||||
f"Host: 127.0.0.1:{config['nlPort']}\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
f"Sec-WebSocket-Key: {key}\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n\r\n"
|
||||
)
|
||||
ws.sendall(handshake.encode())
|
||||
|
||||
# Skip HTTP response header
|
||||
resp = b""
|
||||
while b"\r\n\r\n" not in resp:
|
||||
try:
|
||||
chunk = ws.recv(1024)
|
||||
if not chunk: break
|
||||
resp += chunk
|
||||
except socket.timeout: continue
|
||||
|
||||
# 5. Loop
|
||||
while True:
|
||||
# Watchdog
|
||||
try:
|
||||
os.kill(ppid, 0)
|
||||
except OSError: break
|
||||
|
||||
try:
|
||||
head = ws.recv(2)
|
||||
if not head: break
|
||||
length = head[1] & 127
|
||||
if length == 126: length = struct.unpack(">H", ws.recv(2))[0]
|
||||
elif length == 127: length = struct.unpack(">Q", ws.recv(8))[0]
|
||||
|
||||
data = b""
|
||||
while len(data) < length:
|
||||
data += ws.recv(length - len(data))
|
||||
|
||||
msg = json.loads(data.decode('utf-8'))
|
||||
if msg['event'] == 'discord:update':
|
||||
d = msg['data']
|
||||
set_activity(ds, ppid, d.get('details'), d.get('state'), d.get('largeImageKey'), d.get('startTimestamp'), d.get('endTimestamp'), d.get('largeImageText'), d.get('smallImageKey'), d.get('smallImageText'))
|
||||
elif msg['event'] == 'discord:clear':
|
||||
set_activity(ds, ppid, "Idling", "Monochrome")
|
||||
elif msg['event'] == 'windowClose':
|
||||
break
|
||||
except socket.timeout:
|
||||
# Timeout is expected, continue polling
|
||||
continue
|
||||
except Exception:
|
||||
# Ignore other errors and continue
|
||||
continue
|
||||
|
||||
# Cleanup
|
||||
try:
|
||||
send_packet(ds, 1, {
|
||||
"cmd": "SET_ACTIVITY",
|
||||
"args": {"pid": ppid, "activity": None},
|
||||
"nonce": str(uuid.uuid4())
|
||||
})
|
||||
time.sleep(0.1)
|
||||
ds.close()
|
||||
except Exception:
|
||||
# Ignore cleanup errors
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
13
index.html
13
index.html
|
|
@ -1432,7 +1432,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="desktop-update-modal" class="modal">
|
||||
<div id="desktop-update-modal" class="modal">
|
||||
<div class="modal-overlay"></div>
|
||||
<div class="modal-content">
|
||||
<h3>Update Available</h3>
|
||||
|
|
@ -1455,7 +1455,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="command-palette-overlay" style="display: none">
|
||||
<div class="command-palette">
|
||||
<div class="command-palette-header">
|
||||
|
|
@ -4394,15 +4394,6 @@
|
|||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="setting-item" id="desktop-update-container" style="display: none">
|
||||
<div class="info">
|
||||
<span class="label">Desktop Update</span>
|
||||
<span class="description">Check for updates to the desktop application</span>
|
||||
</div>
|
||||
<button id="check-desktop-updates-btn" class="btn-secondary">
|
||||
Check for Updates
|
||||
</button>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="info">
|
||||
<span class="label">Analytics</span>
|
||||
|
|
|
|||
201
js/app.js
201
js/app.js
|
|
@ -470,77 +470,6 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
// Initialize tracker
|
||||
initTracker();
|
||||
|
||||
// Linux Media Keys Fix
|
||||
if (window.NL_MODE) {
|
||||
import('./desktop/neutralino-bridge.js').then(({ events }) => {
|
||||
events.on('mediaNext', () => Player.instance.playNext());
|
||||
events.on('mediaPrevious', () => Player.instance.playPrev());
|
||||
events.on('mediaPlayPause', () => Player.instance.handlePlayPause());
|
||||
events.on('mediaStop', () => {
|
||||
const el = Player.instance.activeElement;
|
||||
el.pause();
|
||||
el.currentTime = 0;
|
||||
});
|
||||
console.log('Media keys initialized via bridge');
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize desktop features if in Neutralino mode
|
||||
if (
|
||||
typeof window !== 'undefined' &&
|
||||
(window.NL_MODE ||
|
||||
window.location.search.includes('mode=neutralino') ||
|
||||
window.location.search.includes('nl_port='))
|
||||
) {
|
||||
window.NL_MODE = true;
|
||||
try {
|
||||
const desktopModule = await import('./desktop/desktop.js');
|
||||
await desktopModule.initDesktop(Player.instance);
|
||||
|
||||
import('./desktop/neutralino-bridge.js').then(({ updater }) => {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
// my worker should detect a users OS and serve the right ver
|
||||
const update = await updater.checkForUpdates('https://update.samidy.xyz/update.json');
|
||||
|
||||
if (update && update.available) {
|
||||
const modal = document.getElementById('desktop-update-modal');
|
||||
const notes = document.getElementById('desktop-update-notes');
|
||||
const confirmBtn = document.getElementById('desktop-update-confirm');
|
||||
const cancelBtn = document.getElementById('desktop-update-cancel');
|
||||
|
||||
if (modal) {
|
||||
notes.innerHTML = update.notes || 'Bug fixes and improvements.';
|
||||
modal.classList.add('active');
|
||||
|
||||
confirmBtn.onclick = async () => {
|
||||
confirmBtn.disabled = true;
|
||||
confirmBtn.textContent = 'Updating...';
|
||||
try {
|
||||
await updater.install();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
confirmBtn.textContent = 'Failed';
|
||||
setTimeout(() => {
|
||||
confirmBtn.disabled = false;
|
||||
confirmBtn.textContent = 'Update Now';
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
cancelBtn.onclick = () => modal.classList.remove('active');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to check for desktop updates:', e);
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Failed to load desktop module:', err);
|
||||
}
|
||||
}
|
||||
|
||||
const castBtn = document.getElementById('cast-btn');
|
||||
initializeCasting(audioPlayer, castBtn);
|
||||
|
||||
|
|
@ -568,83 +497,42 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
const handle = await db.getSetting('local_folder_handle');
|
||||
if (!handle) return;
|
||||
|
||||
const isNeutralino =
|
||||
window.Neutralino && (window.NL_MODE || window.location.search.includes('mode=neutralino'));
|
||||
const tracks = (window.localFilesCache = []);
|
||||
let idCounter = 0;
|
||||
const { readTrackMetadata } = await loadMetadataModule();
|
||||
|
||||
if (isNeutralino) {
|
||||
async function scanNeu(dirPath) {
|
||||
const entries = await window.Neutralino.filesystem.readDirectory(dirPath);
|
||||
for (const entry of entries) {
|
||||
if (entry.entry === '.' || entry.entry === '..') continue;
|
||||
const fullPath = `${dirPath}/${entry.entry}`;
|
||||
if (entry.type === 'FILE') {
|
||||
const name = entry.entry.toLowerCase();
|
||||
if (
|
||||
name.endsWith('.flac') ||
|
||||
name.endsWith('.mp3') ||
|
||||
name.endsWith('.m4a') ||
|
||||
name.endsWith('.wav') ||
|
||||
name.endsWith('.ogg')
|
||||
) {
|
||||
try {
|
||||
const buffer = await window.Neutralino.filesystem.readBinaryFile(fullPath);
|
||||
const stats = await window.Neutralino.filesystem.getStats(fullPath);
|
||||
const file = new File([buffer], entry.entry, { lastModified: stats.mtime });
|
||||
const metadata = await readTrackMetadata(file);
|
||||
metadata.id = `local-${idCounter++}-${entry.entry}`;
|
||||
tracks.push(metadata);
|
||||
UIRenderer.instance.renderLocalFiles(
|
||||
document.getElementById('library-local-container')
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Failed to read file:', fullPath, e);
|
||||
}
|
||||
}
|
||||
} else if (entry.type === 'DIRECTORY') {
|
||||
await scanNeu(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
await scanNeu(handle.path);
|
||||
} else {
|
||||
// Request read permission before iterating. When the browser has
|
||||
// already granted it (e.g. within the same session or via a
|
||||
// persistent grant) this succeeds without a user gesture.
|
||||
if (typeof handle.requestPermission === 'function') {
|
||||
const permission = await handle.requestPermission({ mode: 'read' });
|
||||
if (permission !== 'granted') return;
|
||||
}
|
||||
|
||||
async function scanBrowser(dirHandle) {
|
||||
for await (const entry of dirHandle.values()) {
|
||||
if (entry.kind === 'file') {
|
||||
const name = entry.name.toLowerCase();
|
||||
if (
|
||||
name.endsWith('.flac') ||
|
||||
name.endsWith('.mp3') ||
|
||||
name.endsWith('.m4a') ||
|
||||
name.endsWith('.wav') ||
|
||||
name.endsWith('.ogg')
|
||||
) {
|
||||
const file = await entry.getFile();
|
||||
const metadata = await readTrackMetadata(file);
|
||||
metadata.id = `local-${idCounter++}-${file.name}`;
|
||||
tracks.push(metadata);
|
||||
UIRenderer.instance.renderLocalFiles(
|
||||
document.getElementById('library-local-container')
|
||||
);
|
||||
}
|
||||
} else if (entry.kind === 'directory') {
|
||||
await scanBrowser(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
await scanBrowser(handle);
|
||||
// Request read permission before iterating. When the browser has
|
||||
// already granted it (e.g. within the same session or via a
|
||||
// persistent grant) this succeeds without a user gesture.
|
||||
if (typeof handle.requestPermission === 'function') {
|
||||
const permission = await handle.requestPermission({ mode: 'read' });
|
||||
if (permission !== 'granted') return;
|
||||
}
|
||||
|
||||
async function scanBrowser(dirHandle) {
|
||||
for await (const entry of dirHandle.values()) {
|
||||
if (entry.kind === 'file') {
|
||||
const name = entry.name.toLowerCase();
|
||||
if (
|
||||
name.endsWith('.flac') ||
|
||||
name.endsWith('.mp3') ||
|
||||
name.endsWith('.m4a') ||
|
||||
name.endsWith('.wav') ||
|
||||
name.endsWith('.ogg')
|
||||
) {
|
||||
const file = await entry.getFile();
|
||||
const metadata = await readTrackMetadata(file);
|
||||
metadata.id = `local-${idCounter++}-${file.name}`;
|
||||
tracks.push(metadata);
|
||||
UIRenderer.instance.renderLocalFiles(document.getElementById('library-local-container'));
|
||||
}
|
||||
} else if (entry.kind === 'directory') {
|
||||
await scanBrowser(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
await scanBrowser(handle);
|
||||
|
||||
tracks.sort((a, b) => (a.artist.name || '').localeCompare(b.artist.name || ''));
|
||||
// Update only the local-files section without navigating to the library page.
|
||||
UIRenderer.instance.renderLocalFiles(document.getElementById('library-local-container'));
|
||||
|
|
@ -712,17 +600,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
const ua = navigator.userAgent;
|
||||
const isChromeOrEdge = (ua.indexOf('Chrome') > -1 || ua.indexOf('Edg') > -1) && !/Mobile|Android/.test(ua);
|
||||
const hasFileSystemApi = 'showDirectoryPicker' in window;
|
||||
const isNeutralino =
|
||||
window.NL_MODE ||
|
||||
window.location.search.includes('mode=neutralino') ||
|
||||
window.location.search.includes('nl_port=');
|
||||
|
||||
if (!isNeutralino && (!isChromeOrEdge || !hasFileSystemApi)) {
|
||||
if (!isChromeOrEdge || !hasFileSystemApi) {
|
||||
selectLocalBtn.style.display = 'none';
|
||||
browserWarning.style.display = 'block';
|
||||
} else if (isNeutralino) {
|
||||
selectLocalBtn.style.display = 'flex';
|
||||
browserWarning.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2563,22 +2444,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
if (e.target.closest('#select-local-folder-btn') || e.target.closest('#change-local-folder-btn')) {
|
||||
const isChange = e.target.closest('#change-local-folder-btn') !== null;
|
||||
try {
|
||||
const isNeutralino =
|
||||
window.Neutralino && (window.NL_MODE || window.location.search.includes('mode=neutralino'));
|
||||
let handle;
|
||||
let path;
|
||||
|
||||
if (isNeutralino) {
|
||||
path = await window.Neutralino.os.showFolderDialog('Select Music Folder');
|
||||
if (!path) return;
|
||||
// Mock a handle object for UI compatibility
|
||||
handle = { name: path.split(/[/\\]/).pop() || path, isNeutralino: true, path };
|
||||
} else {
|
||||
handle = await window.showDirectoryPicker({
|
||||
id: 'music-folder',
|
||||
mode: 'read',
|
||||
});
|
||||
}
|
||||
const handle = await window.showDirectoryPicker({
|
||||
id: 'music-folder',
|
||||
mode: 'read',
|
||||
});
|
||||
|
||||
await db.saveSetting('local_folder_handle', handle);
|
||||
if (isChange) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { triggerDownload } from './download-utils';
|
||||
import { readableStreamIterator } from './readableStreamIterator';
|
||||
|
||||
/**
|
||||
* A single entry to be included in a ZIP archive or written directly to a folder.
|
||||
|
|
@ -10,22 +9,6 @@ export interface WriterEntry {
|
|||
input: Blob | File | string | ArrayBuffer | Uint8Array;
|
||||
}
|
||||
|
||||
/** Minimal interface for the Neutralino bridge used by ZipNeutralinoWriter */
|
||||
interface NeutralinoBridge {
|
||||
os: {
|
||||
showSaveDialog(
|
||||
title: string,
|
||||
options: { defaultPath: string; filters: Array<{ name: string; extensions: string[] }> }
|
||||
): Promise<string | null>;
|
||||
showFolderDialog(title: string, options?: Record<string, unknown>): Promise<string | null>;
|
||||
};
|
||||
filesystem: {
|
||||
writeBinaryFile(path: string, buffer: ArrayBuffer): Promise<void>;
|
||||
appendBinaryFile(path: string, buffer: ArrayBuffer): Promise<void>;
|
||||
createDirectory(path: string): Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
async function loadClientZip() {
|
||||
try {
|
||||
return await import('client-zip');
|
||||
|
|
@ -115,44 +98,6 @@ export class ZipBlobWriter implements IBulkDownloadWriter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a ZIP archive to the filesystem via the Neutralino desktop bridge,
|
||||
* showing a native save dialog first.
|
||||
*/
|
||||
export class ZipNeutralinoWriter implements IBulkDownloadWriter {
|
||||
constructor(private readonly folderName: string) {}
|
||||
|
||||
async write(files: AsyncIterable<WriterEntry>): Promise<void> {
|
||||
const bridge = (await import('./desktop/neutralino-bridge.js')) as unknown as NeutralinoBridge;
|
||||
|
||||
const savePath = await bridge.os.showSaveDialog(`Select save location for ${this.folderName}.zip`, {
|
||||
defaultPath: `${this.folderName}.zip`,
|
||||
filters: [{ name: 'ZIP Archive', extensions: ['zip'] }],
|
||||
});
|
||||
|
||||
if (!savePath) {
|
||||
throw new DOMException('User cancelled save dialog', 'AbortError');
|
||||
}
|
||||
|
||||
const { downloadZip } = await loadClientZip();
|
||||
const response = downloadZip(files);
|
||||
if (!response.body) throw new Error('ZIP response body is null');
|
||||
|
||||
await bridge.filesystem.writeBinaryFile(savePath, new ArrayBuffer(0));
|
||||
|
||||
const reader = response.body.getReader();
|
||||
let receivedLength = 0;
|
||||
|
||||
for await (const value of readableStreamIterator(response.body)) {
|
||||
const chunk = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
||||
await bridge.filesystem.appendBinaryFile(savePath, chunk);
|
||||
receivedLength += value.length;
|
||||
}
|
||||
|
||||
console.log(`[ZIP] Download complete. Total size: ${receivedLength} bytes.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes files directly into a user-chosen folder using the standard browser
|
||||
* File System Access API (showDirectoryPicker). Subdirectories embedded in
|
||||
|
|
@ -250,54 +195,3 @@ export class FolderPickerWriter implements IBulkDownloadWriter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes files directly into a folder on the local filesystem via the
|
||||
* Neutralino desktop bridge. Subdirectories are created automatically.
|
||||
*/
|
||||
export class NeutralinoFolderWriter implements IBulkDownloadWriter {
|
||||
constructor(private readonly basePath: string) {}
|
||||
|
||||
async write(files: AsyncIterable<WriterEntry>): Promise<void> {
|
||||
// Import once per write() call; the module system caches the result.
|
||||
const bridge = (await import('./desktop/neutralino-bridge.js')) as unknown as NeutralinoBridge;
|
||||
const createdDirs = new Set<string>();
|
||||
|
||||
for await (const file of files) {
|
||||
const parts = file.name.split('/').filter(Boolean);
|
||||
if (parts.length === 0) continue;
|
||||
|
||||
// Ensure all parent directories exist
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
const dirPath = this.basePath + '/' + parts.slice(0, i).join('/');
|
||||
if (!createdDirs.has(dirPath)) {
|
||||
try {
|
||||
await bridge.filesystem.createDirectory(dirPath);
|
||||
} catch {
|
||||
// Directory may already exist; ignore
|
||||
}
|
||||
createdDirs.add(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
const filePath = this.basePath + '/' + file.name;
|
||||
let buffer: ArrayBuffer;
|
||||
const { input } = file;
|
||||
if (input instanceof Blob) {
|
||||
buffer = await input.arrayBuffer();
|
||||
} else if (typeof input === 'string') {
|
||||
const encoded = new TextEncoder().encode(input);
|
||||
buffer = encoded.buffer.slice(
|
||||
encoded.byteOffset,
|
||||
encoded.byteOffset + encoded.byteLength
|
||||
) as ArrayBuffer;
|
||||
} else if (input instanceof Uint8Array) {
|
||||
buffer = input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength) as ArrayBuffer;
|
||||
} else {
|
||||
buffer = input;
|
||||
}
|
||||
|
||||
await bridge.filesystem.writeBinaryFile(filePath, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
// js/desktop/desktop.js
|
||||
import Neutralino from './neutralino-bridge.js';
|
||||
import { initializeDiscordRPC } from './discord-rpc.js';
|
||||
|
||||
export async function initDesktop(player) {
|
||||
console.log('[Desktop] Initializing desktop features...');
|
||||
|
||||
// Assign to window for modules that use global Neutralino (like Player.js)
|
||||
window.Neutralino = Neutralino;
|
||||
|
||||
try {
|
||||
await Neutralino.init();
|
||||
console.log('[Desktop] Neutralino initialized.');
|
||||
|
||||
if (player) {
|
||||
console.log('[Desktop] Starting Discord RPC...');
|
||||
initializeDiscordRPC(player);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Desktop] Failed to initialize desktop environment:', error);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// js/desktop/discord-rpc.js
|
||||
import { getTrackTitle, getTrackArtists } from '../utils.js';
|
||||
|
||||
export function initializeDiscordRPC(player) {
|
||||
const EXTENSION_ID = 'js.neutralino.discordrpc';
|
||||
|
||||
function sendUpdate(track, isPaused = false) {
|
||||
if (!track) return;
|
||||
|
||||
let coverUrl = 'monochrome';
|
||||
if (track.album?.cover) {
|
||||
const coverId = String(track.album.cover).replace(/-/g, '/');
|
||||
coverUrl = `https://resources.tidal.com/images/${coverId}/320x320.jpg`;
|
||||
}
|
||||
|
||||
const data = {
|
||||
details: getTrackTitle(track),
|
||||
state: getTrackArtists(track),
|
||||
largeImageKey: coverUrl,
|
||||
largeImageText: track.album?.title || 'Monochrome',
|
||||
smallImageKey: isPaused ? 'pause' : 'play',
|
||||
smallImageText: isPaused ? 'Paused' : 'Playing',
|
||||
instance: false,
|
||||
};
|
||||
|
||||
if (!isPaused && track.duration) {
|
||||
const now = Date.now();
|
||||
const elapsed = player.audio.currentTime * 1000;
|
||||
const remaining = (track.duration - player.audio.currentTime) * 1000;
|
||||
|
||||
data.startTimestamp = Math.floor((now - elapsed) / 1000);
|
||||
data.endTimestamp = Math.floor((now + remaining) / 1000);
|
||||
}
|
||||
|
||||
Neutralino.events.broadcast('discord:update', data).catch((e) => console.error('Broadcast failed', e));
|
||||
Neutralino.extensions
|
||||
.dispatch(EXTENSION_ID, 'discord:update', data)
|
||||
.catch((e) => console.error('Dispatch failed', e));
|
||||
}
|
||||
|
||||
player.audio.addEventListener('play', () => {
|
||||
sendUpdate(player.currentTrack);
|
||||
});
|
||||
|
||||
player.audio.addEventListener('pause', () => {
|
||||
sendUpdate(player.currentTrack, true);
|
||||
});
|
||||
|
||||
player.audio.addEventListener('loadedmetadata', () => {
|
||||
if (!player.audio.paused) {
|
||||
sendUpdate(player.currentTrack);
|
||||
}
|
||||
});
|
||||
|
||||
// Send initial status
|
||||
if (player.currentTrack) {
|
||||
sendUpdate(player.currentTrack, player.audio.paused);
|
||||
} else {
|
||||
Neutralino.events
|
||||
.broadcast('discord:update', {
|
||||
details: 'Idling',
|
||||
state: 'Monochrome',
|
||||
largeImageKey: 'monochrome',
|
||||
largeImageText: 'Monochrome',
|
||||
smallImageKey: 'pause',
|
||||
smallImageText: 'Paused',
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
// js/desktop/neutralino-bridge.js
|
||||
|
||||
const isNeutralino =
|
||||
typeof window !== 'undefined' &&
|
||||
(window.NL_MODE || window.location.search.includes('mode=neutralino') || window.parent !== window);
|
||||
|
||||
const listeners = new Map();
|
||||
|
||||
// Listen for events from the Shell (Parent)
|
||||
if (isNeutralino) {
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data?.type === 'NL_EVENT') {
|
||||
const { eventName, detail } = event.data;
|
||||
if (listeners.has(eventName)) {
|
||||
listeners.get(eventName).forEach((handler) => {
|
||||
try {
|
||||
handler(detail);
|
||||
} catch (e) {
|
||||
console.error('[Bridge] Error in event handler:', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const init = async () => {
|
||||
if (!isNeutralino) return;
|
||||
// Notify Shell we are ready
|
||||
window.parent.postMessage({ type: 'NL_INIT' }, '*');
|
||||
};
|
||||
|
||||
export const events = {
|
||||
on: (eventName, handler) => {
|
||||
if (!isNeutralino) return;
|
||||
if (!listeners.has(eventName)) {
|
||||
listeners.set(eventName, []);
|
||||
}
|
||||
listeners.get(eventName).push(handler);
|
||||
},
|
||||
off: (eventName, handler) => {
|
||||
if (!isNeutralino) return;
|
||||
if (!listeners.has(eventName)) return;
|
||||
const handlers = listeners.get(eventName);
|
||||
const index = handlers.indexOf(handler);
|
||||
if (index > -1) handlers.splice(index, 1);
|
||||
},
|
||||
broadcast: async (eventName, data) => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_BROADCAST', eventName, data }, '*');
|
||||
},
|
||||
};
|
||||
|
||||
export const extensions = {
|
||||
dispatch: async (extensionId, eventName, data) => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_EXTENSION', extensionId, eventName, data }, '*');
|
||||
},
|
||||
};
|
||||
|
||||
export const app = {
|
||||
exit: async () => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_APP_EXIT' }, '*');
|
||||
},
|
||||
};
|
||||
|
||||
export const os = {
|
||||
open: async (url) => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_OS_OPEN', url }, '*');
|
||||
},
|
||||
showSaveDialog: async (title, options) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_OS_SHOW_SAVE_DIALOG', id, title, options }, '*');
|
||||
});
|
||||
},
|
||||
showFolderDialog: async (title, options) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_OS_SHOW_FOLDER_DIALOG', id, title, options }, '*');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const filesystem = {
|
||||
readBinaryFile: async (path) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_FS_READ_BINARY', id, path }, '*');
|
||||
});
|
||||
},
|
||||
readDirectory: async (path) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_FS_READ_DIR', id, path }, '*');
|
||||
});
|
||||
},
|
||||
getStats: async (path) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_FS_STATS', id, path }, '*');
|
||||
});
|
||||
},
|
||||
writeBinaryFile: async (path, buffer) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_FS_WRITE_BINARY', id, path, buffer }, '*', [buffer]);
|
||||
});
|
||||
},
|
||||
appendBinaryFile: async (path, buffer) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
// Transfer buffer if possible to save memory
|
||||
window.parent.postMessage({ type: 'NL_FS_APPEND_BINARY', id, path, buffer }, '*', [buffer]);
|
||||
});
|
||||
},
|
||||
createDirectory: async (path) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_FS_CREATE_DIR', id, path }, '*');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const updater = {
|
||||
checkForUpdates: async (url) => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_UPDATER_CHECK', id, url }, '*');
|
||||
});
|
||||
},
|
||||
install: async () => {
|
||||
if (!isNeutralino) return;
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
const handler = (event) => {
|
||||
if (event.data?.type === 'NL_RESPONSE' && event.data.id === id) {
|
||||
window.removeEventListener('message', handler);
|
||||
if (event.data.error) reject(event.data.error);
|
||||
else resolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
window.parent.postMessage({ type: 'NL_UPDATER_INSTALL', id }, '*');
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const _window = {
|
||||
minimize: async () => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_WINDOW_MIN' }, '*');
|
||||
},
|
||||
maximize: async () => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_WINDOW_MAX' }, '*');
|
||||
},
|
||||
show: async () => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_WINDOW_SHOW' }, '*');
|
||||
},
|
||||
hide: async () => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_WINDOW_HIDE' }, '*');
|
||||
},
|
||||
isVisible: async () => {
|
||||
return true; // Mock response
|
||||
},
|
||||
setTitle: async (title) => {
|
||||
if (!isNeutralino) return;
|
||||
window.parent.postMessage({ type: 'NL_WINDOW_SET_TITLE', title }, '*');
|
||||
},
|
||||
};
|
||||
|
||||
// Expose generically for other modules
|
||||
export { _window as window };
|
||||
export default {
|
||||
init,
|
||||
events,
|
||||
extensions,
|
||||
app,
|
||||
os,
|
||||
filesystem,
|
||||
updater,
|
||||
window: _window,
|
||||
};
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
//js/downloads.js
|
||||
//@ts-check
|
||||
import {
|
||||
buildTrackFilename,
|
||||
sanitizeForFilename,
|
||||
|
|
@ -9,19 +8,15 @@ import {
|
|||
formatPathTemplate,
|
||||
getCoverBlob,
|
||||
getExtensionFromBlob,
|
||||
formatTemplate,
|
||||
escapeHtml,
|
||||
getTrackDiscNumber,
|
||||
} from './utils.js';
|
||||
import { AbortError } from './errorTypes.ts';
|
||||
import { lyricsSettings, playlistSettings } from './storage.js';
|
||||
import { generateM3U, generateM3U8, generateCUE, generateNFO, generateJSON } from './playlist-generator.js';
|
||||
import {
|
||||
ZipStreamWriter,
|
||||
ZipBlobWriter,
|
||||
ZipNeutralinoWriter,
|
||||
FolderPickerWriter,
|
||||
NeutralinoFolderWriter,
|
||||
SequentialFileWriter,
|
||||
} from './bulk-download-writer.ts';
|
||||
import { FfmpegProgress } from './ffmpeg.types.js';
|
||||
|
|
@ -29,7 +24,6 @@ import { DownloadProgress, ProgressMessage, SegmentedDownloadProgress } from './
|
|||
import { db } from './db.js';
|
||||
import { modernSettings } from './ModernSettings.js';
|
||||
import { SVG_CLOSE } from './icons.ts';
|
||||
import { MusicAPI } from './music-api.js';
|
||||
import { LyricsManager } from './lyrics.js';
|
||||
|
||||
const downloadTasks = new Map();
|
||||
|
|
@ -438,13 +432,13 @@ async function bulkDownload({
|
|||
|
||||
// For albums, generate CUE file (one per disc if multi-disc)
|
||||
if (type === 'album' && playlistSettings.shouldGenerateCUE()) {
|
||||
const tracksByVolume = Object.groupBy(
|
||||
tracks.map((track, index) => ({
|
||||
...track,
|
||||
trackPath: trackPaths[index],
|
||||
})),
|
||||
(track) => String(getTrackDiscNumber(track) || 1)
|
||||
);
|
||||
const tracksByVolume = tracks.reduce((acc, track, index) => {
|
||||
const discNumber = String(getTrackDiscNumber(track) || 1);
|
||||
if (!acc[discNumber]) acc[discNumber] = [];
|
||||
acc[discNumber].push({ ...track, trackPath: trackPaths[index] });
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const multiDisc = Object.keys(tracksByVolume).length > 1;
|
||||
|
||||
for (const [volumeNumber, volumeTracks] of Object.entries(tracksByVolume)) {
|
||||
|
|
@ -511,17 +505,12 @@ async function bulkDownload({
|
|||
async function createSingleTrackFolderWriter() {
|
||||
if (!modernSettings.downloadSinglesToFolder) return null;
|
||||
|
||||
const isNeutralino =
|
||||
typeof window !== 'undefined' &&
|
||||
(window.NL_MODE || window.location.search.includes('mode=neutralino') || window.parent !== window);
|
||||
const method = modernSettings.bulkDownloadMethod;
|
||||
const hasFolderPicker = 'showDirectoryPicker' in window;
|
||||
|
||||
if (method === 'local') {
|
||||
const localHandle = await db.getSetting('local_folder_handle');
|
||||
if (isNeutralino) {
|
||||
if (localHandle?.path) return new NeutralinoFolderWriter(localHandle.path);
|
||||
} else if (hasFolderPicker && localHandle && typeof localHandle.requestPermission === 'function') {
|
||||
if (hasFolderPicker && localHandle && typeof localHandle.requestPermission === 'function') {
|
||||
try {
|
||||
const permission = await localHandle.requestPermission({ mode: 'readwrite' });
|
||||
if (permission === 'granted') return FolderPickerWriter.fromHandle(localHandle);
|
||||
|
|
@ -534,7 +523,7 @@ async function createSingleTrackFolderWriter() {
|
|||
|
||||
if (method === 'folder' && hasFolderPicker) {
|
||||
const rememberFolder = modernSettings.rememberBulkDownloadFolder;
|
||||
const savedHandle = rememberFolder ? modernSettings.bulkDownloadFolder : null;
|
||||
const savedHandle = rememberFolder ? await db.getSetting('bulk_download_folder_handle') : null;
|
||||
// Try to reuse the saved handle silently first.
|
||||
if (savedHandle && typeof savedHandle.requestPermission === 'function') {
|
||||
try {
|
||||
|
|
@ -548,8 +537,7 @@ async function createSingleTrackFolderWriter() {
|
|||
try {
|
||||
const writer = await FolderPickerWriter.create();
|
||||
if (rememberFolder) {
|
||||
modernSettings.bulkDownloadFolder = writer.getDirHandle();
|
||||
await modernSettings.waitPending();
|
||||
await db.saveSetting('bulk_download_folder_handle', writer.getDirHandle());
|
||||
}
|
||||
return writer;
|
||||
} catch (error) {
|
||||
|
|
@ -570,9 +558,6 @@ async function createSingleTrackFolderWriter() {
|
|||
* or null when individual sequential downloads should be used.
|
||||
*/
|
||||
async function createBulkWriter(folderName) {
|
||||
const isNeutralino =
|
||||
typeof window !== 'undefined' &&
|
||||
(window.NL_MODE || window.location.search.includes('mode=neutralino') || window.parent !== window);
|
||||
const method = modernSettings.bulkDownloadMethod;
|
||||
const forceZipBlob = modernSettings.forceZipBlob;
|
||||
const hasFileSystemAccess = 'showSaveFilePicker' in window && 'createWritable' in FileSystemFileHandle.prototype;
|
||||
|
|
@ -581,23 +566,7 @@ async function createBulkWriter(folderName) {
|
|||
// ── Local Media Folder method ────────────────────────────────────────────
|
||||
if (method === 'local') {
|
||||
const localHandle = await db.getSetting('local_folder_handle');
|
||||
if (isNeutralino) {
|
||||
if (localHandle?.path) {
|
||||
return new NeutralinoFolderWriter(localHandle.path);
|
||||
}
|
||||
// No folder configured – prompt now
|
||||
const bridge = await import('./desktop/neutralino-bridge.js');
|
||||
const pickedPath = await bridge.os.showFolderDialog('Select Download Folder');
|
||||
if (!pickedPath) return null; // user cancelled – fall back to default
|
||||
// Persist as the local media folder so future downloads reuse it
|
||||
const handle = {
|
||||
name: pickedPath.split(/[/\\]/).pop() || pickedPath,
|
||||
isNeutralino: true,
|
||||
path: pickedPath,
|
||||
};
|
||||
await db.saveSetting('local_folder_handle', handle);
|
||||
return new NeutralinoFolderWriter(pickedPath);
|
||||
} else if (hasFolderPicker) {
|
||||
if (hasFolderPicker) {
|
||||
// Browser mode: try to reuse the stored handle with write permission
|
||||
if (localHandle && typeof localHandle.requestPermission === 'function') {
|
||||
try {
|
||||
|
|
@ -624,11 +593,6 @@ async function createBulkWriter(folderName) {
|
|||
// Browser without File System Access API – fall through to ZIP
|
||||
}
|
||||
|
||||
// ── Neutralino default (ZIP) ─────────────────────────────────────────────
|
||||
if (isNeutralino) {
|
||||
return new ZipNeutralinoWriter(folderName);
|
||||
}
|
||||
|
||||
// ── Folder Picker method ─────────────────────────────────────────────────
|
||||
if (method === 'folder' && hasFolderPicker) {
|
||||
const rememberFolder = modernSettings.rememberBulkDownloadFolder;
|
||||
|
|
|
|||
13
js/player.js
13
js/player.js
|
|
@ -801,7 +801,6 @@ export class Player {
|
|||
this.updatePlayingTrackIndicator();
|
||||
this.updateMediaSession(track);
|
||||
this.updateMediaSessionPlaybackState();
|
||||
this.updateNativeWindow(track);
|
||||
|
||||
try {
|
||||
let streamUrl;
|
||||
|
|
@ -2070,16 +2069,4 @@ export class Player {
|
|||
updateBtn(timerBtn);
|
||||
updateBtn(timerBtnDesktop);
|
||||
}
|
||||
|
||||
async updateNativeWindow(track) {
|
||||
if (!window.Neutralino) return;
|
||||
|
||||
const trackTitle = getTrackTitle(track);
|
||||
const artist = getTrackArtists(track);
|
||||
try {
|
||||
await Neutralino.window.setTitle(`${trackTitle} • ${artist}`);
|
||||
} catch (e) {
|
||||
console.error('Failed to set window title:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,10 +220,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
return;
|
||||
}
|
||||
|
||||
let authWindow = null;
|
||||
if (!window.Neutralino) {
|
||||
authWindow = window.open('', '_blank');
|
||||
}
|
||||
let authWindow = window.open('', '_blank');
|
||||
|
||||
lastfmConnectBtn.disabled = true;
|
||||
lastfmConnectBtn.textContent = 'Opening Last.fm...';
|
||||
|
|
@ -231,16 +228,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
try {
|
||||
const { token, url } = await scrobbler.lastfm.getAuthUrl();
|
||||
|
||||
if (window.Neutralino) {
|
||||
try {
|
||||
await Neutralino.os.open(url);
|
||||
} catch (e) {
|
||||
// Fallback if os.open fails
|
||||
console.error('Neutralino open failed, falling back to window.open', e);
|
||||
if (!authWindow) authWindow = window.open(url, '_blank');
|
||||
else authWindow.location.href = url;
|
||||
}
|
||||
} else if (authWindow) {
|
||||
if (authWindow) {
|
||||
authWindow.location.href = url;
|
||||
} else {
|
||||
alert('Popup blocked! Please allow popups.');
|
||||
|
|
@ -587,10 +575,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
return;
|
||||
}
|
||||
|
||||
let authWindow = null;
|
||||
if (!window.Neutralino) {
|
||||
authWindow = window.open('', '_blank');
|
||||
}
|
||||
let authWindow = window.open('', '_blank');
|
||||
|
||||
librefmConnectBtn.disabled = true;
|
||||
librefmConnectBtn.textContent = 'Opening Libre.fm...';
|
||||
|
|
@ -598,9 +583,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
try {
|
||||
const { token, url } = await scrobbler.librefm.getAuthUrl();
|
||||
|
||||
if (window.Neutralino) {
|
||||
await Neutralino.os.open(url);
|
||||
} else if (authWindow) {
|
||||
if (authWindow) {
|
||||
authWindow.location.href = url;
|
||||
} else {
|
||||
alert('Popup blocked! Please allow popups.');
|
||||
|
|
@ -1037,20 +1020,7 @@ export async function initializeSettings(scrobbler, player, api, ui) {
|
|||
if (!existingHandle) {
|
||||
let picked = false;
|
||||
try {
|
||||
const isNeutralino =
|
||||
window.Neutralino && (window.NL_MODE || window.location.search.includes('mode=neutralino'));
|
||||
if (isNeutralino) {
|
||||
const path = await window.Neutralino.os.showFolderDialog('Select Local Media Folder');
|
||||
if (path) {
|
||||
picked = true;
|
||||
const handle = {
|
||||
name: path.split(/[/\\]/).pop() || path,
|
||||
isNeutralino: true,
|
||||
path,
|
||||
};
|
||||
await db.saveSetting('local_folder_handle', handle);
|
||||
}
|
||||
} else if (hasFolderPicker) {
|
||||
if (hasFolderPicker) {
|
||||
const handle = await window.showDirectoryPicker({ mode: 'readwrite' });
|
||||
if (handle) {
|
||||
picked = true;
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"applicationId": "com.monochrome.app",
|
||||
"applicationName": "Monochrome",
|
||||
"applicationIcon": "public/assets/appicon.png",
|
||||
"author": "Monochrome",
|
||||
"description": "Monochrome - Lossless music streaming",
|
||||
"version": "1.0.0",
|
||||
"defaultMode": "window",
|
||||
"documentRoot": "/",
|
||||
"url": "/public/neutralino_loader.html",
|
||||
"enableServer": true,
|
||||
"enableNativeAPI": true,
|
||||
"enableExtensions": true,
|
||||
"tokenSecurity": "none",
|
||||
"modes": {
|
||||
"window": {
|
||||
"title": "Monochrome (DEV)",
|
||||
"icon": "public/assets/appicon.png",
|
||||
"width": 1280,
|
||||
"height": 800,
|
||||
"minWidth": 800,
|
||||
"minHeight": 600,
|
||||
"center": true,
|
||||
"resizable": true,
|
||||
"hidden": false,
|
||||
"borderless": false,
|
||||
"enableInspector": true,
|
||||
"openInspectorOnStartup": true,
|
||||
"exitProcessOnClose": true
|
||||
}
|
||||
},
|
||||
"port": 5050,
|
||||
"cli": {
|
||||
"binaryName": "Monochrome",
|
||||
"resourcesPath": "/",
|
||||
"binaryVersion": "6.5.0",
|
||||
"clientVersion": "6.5.0"
|
||||
},
|
||||
"extensions": [
|
||||
{
|
||||
"id": "js.neutralino.discordrpc",
|
||||
"commandLinux": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"",
|
||||
"commandMac": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"",
|
||||
"commandWindows": "powershell.exe -ExecutionPolicy Bypass -File \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.ps1\""
|
||||
}
|
||||
],
|
||||
"nativeAllowList": [
|
||||
"app.*",
|
||||
"window.*",
|
||||
"extensions.*",
|
||||
"events.*",
|
||||
"os.*",
|
||||
"filesystem.*",
|
||||
"debug.*",
|
||||
"storage.*",
|
||||
"computer.*",
|
||||
"clipboard.*",
|
||||
"updater.*"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"applicationId": "com.monochrome.app",
|
||||
"applicationName": "Monochrome",
|
||||
"applicationIcon": "public/assets/appicon.png",
|
||||
"author": "Monochrome",
|
||||
"description": "Monochrome - Lossless music streaming",
|
||||
"version": "1.0.0",
|
||||
"defaultMode": "window",
|
||||
"documentRoot": "dist/",
|
||||
"url": "/neutralino_loader.html",
|
||||
"enableServer": true,
|
||||
"enableNativeAPI": true,
|
||||
"enableExtensions": true,
|
||||
"tokenSecurity": "none",
|
||||
"modes": {
|
||||
"window": {
|
||||
"title": "Monochrome",
|
||||
"icon": "public/assets/appicon.png",
|
||||
"width": 1280,
|
||||
"height": 800,
|
||||
"minWidth": 800,
|
||||
"minHeight": 600,
|
||||
"center": true,
|
||||
"resizable": true,
|
||||
"hidden": false,
|
||||
"borderless": false,
|
||||
"enableInspector": true,
|
||||
"openInspectorOnStartup": false,
|
||||
"exitProcessOnClose": true
|
||||
}
|
||||
},
|
||||
"port": 5050,
|
||||
"cli": {
|
||||
"binaryName": "Monochrome",
|
||||
"resourcesPath": "dist/",
|
||||
"binaryVersion": "6.5.0",
|
||||
"clientVersion": "6.5.0"
|
||||
},
|
||||
"extensions": [
|
||||
{
|
||||
"id": "js.neutralino.discordrpc",
|
||||
"commandLinux": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"",
|
||||
"commandMac": "python3 \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.py\"",
|
||||
"commandWindows": "powershell.exe -ExecutionPolicy Bypass -File \"${NL_PATH}/extensions/js.neutralino.discordrpc/bridge.ps1\""
|
||||
}
|
||||
],
|
||||
"nativeAllowList": [
|
||||
"app.*",
|
||||
"window.*",
|
||||
"extensions.*",
|
||||
"events.*",
|
||||
"os.*",
|
||||
"filesystem.*",
|
||||
"debug.*",
|
||||
"storage.*",
|
||||
"computer.*",
|
||||
"clipboard.*",
|
||||
"updater.*"
|
||||
]
|
||||
}
|
||||
4129
package-lock.json
generated
4129
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,9 +5,7 @@
|
|||
"description": "[<img src=\"https://github.com/monochrome-music/monochrome/blob/main/assets/512.png?raw=true\" alt=\"Monochrome Logo\">](https://monochrome.tf)",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev:desktop": "start bun run dev & node scripts/dev-runner.js",
|
||||
"build": "vite build",
|
||||
"build:desktop": "bun x neu build",
|
||||
"postbuild": "node -e \"const fs = require('fs'); const path = require('path'); const src = 'extensions'; const dest = path.join('dist', 'Monochrome', 'extensions'); if (fs.existsSync(src)) { fs.mkdirSync(dest, { recursive: true }); fs.cpSync(src, dest, { recursive: true }); console.log('Extensions manually copied to ' + dest); }\"",
|
||||
"preview": "vite preview",
|
||||
"lint:js": "eslint .",
|
||||
|
|
@ -30,7 +28,6 @@
|
|||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
"@capacitor/cli": "^8.2.0",
|
||||
"@neutralinojs/neu": "^11.7.0",
|
||||
"@types/node": "^25.3.5",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
|
@ -44,7 +41,6 @@
|
|||
"stylelint-config-standard-scss": "^16.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-neutralino": "^1.0.3",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
},
|
||||
"overrides": {
|
||||
|
|
@ -63,7 +59,6 @@
|
|||
"@ffmpeg/ffmpeg": "^0.12.15",
|
||||
"@ffmpeg/util": "^0.12.2",
|
||||
"@kawarp/core": "^1.1.1",
|
||||
"@neutralinojs/lib": "^6.5.0",
|
||||
"@svta/common-media-library": "^0.18.1",
|
||||
"@uimaxbai/am-lyrics": "^1.1.4",
|
||||
"appwrite": "^23.0.0",
|
||||
|
|
|
|||
|
|
@ -1,815 +0,0 @@
|
|||
var Neutralino = (function (e) {
|
||||
'use strict';
|
||||
function t(e, t) {
|
||||
return (window.addEventListener(e, t), Promise.resolve({ success: !0, message: 'Event listener added' }));
|
||||
}
|
||||
function n(e, t) {
|
||||
const n = new CustomEvent(e, { detail: t });
|
||||
return (window.dispatchEvent(n), Promise.resolve({ success: !0, message: 'Message dispatched' }));
|
||||
}
|
||||
function r(e) {
|
||||
const t = window.atob(e),
|
||||
n = t.length,
|
||||
r = new Uint8Array(n);
|
||||
for (let e = 0; e < n; e++) r[e] = t.charCodeAt(e);
|
||||
return r.buffer;
|
||||
}
|
||||
function o(e) {
|
||||
let t = new Uint8Array(e),
|
||||
n = '';
|
||||
for (let e of t) n += String.fromCharCode(e);
|
||||
return window.btoa(n);
|
||||
}
|
||||
function i(e) {
|
||||
const t = [];
|
||||
for (const n of e) {
|
||||
const e = Array.isArray(n) ? n : [n];
|
||||
for (const n of e) {
|
||||
const e = n instanceof HTMLElement ? n : document.getElementById(n);
|
||||
e && t.push(e);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
let a;
|
||||
const s = {},
|
||||
c = [],
|
||||
u = {};
|
||||
function d() {
|
||||
window.NL_TOKEN && sessionStorage.setItem('NL_TOKEN', window.NL_TOKEN);
|
||||
const e = g().split('.')[1],
|
||||
o = window.NL_GINJECTED || window.NL_CINJECTED ? '127.0.0.1' : window.location.hostname;
|
||||
((a = new WebSocket(`ws://${o}:${window.NL_PORT}?connectToken=${e}`)),
|
||||
(function () {
|
||||
if (
|
||||
(t('ready', async () => {
|
||||
if ((await f(c), !window.NL_EXTENABLED)) return;
|
||||
let e = await l('extensions.getStats');
|
||||
for (let t of e.connected) n('extensionReady', t);
|
||||
}),
|
||||
t('extClientConnect', (e) => {
|
||||
n('extensionReady', e.detail);
|
||||
}),
|
||||
!window.NL_EXTENABLED)
|
||||
)
|
||||
return;
|
||||
t('extensionReady', async (e) => {
|
||||
e.detail in u && (await f(u[e.detail]), delete u[e.detail]);
|
||||
});
|
||||
})(),
|
||||
a.addEventListener('message', (e) => {
|
||||
const t = JSON.parse(e.data);
|
||||
t.id && t.id in s
|
||||
? (t.data?.error
|
||||
? (s[t.id].reject(t.data.error),
|
||||
'NE_RT_INVTOKN' == t.data.error.code &&
|
||||
(a.close(),
|
||||
(document.body.innerText = ''),
|
||||
document.write(
|
||||
'<code>NE_RT_INVTOKN</code>: Neutralinojs application cannot execute native methods since <code>NL_TOKEN</code> is invalid.'
|
||||
)))
|
||||
: t.data?.success &&
|
||||
s[t.id].resolve(t.data.hasOwnProperty('returnValue') ? t.data.returnValue : t.data),
|
||||
delete s[t.id])
|
||||
: t.event &&
|
||||
('openedFile' == t.event && 'dataBinary' == t?.data?.action && (t.data.data = r(t.data.data)),
|
||||
n(t.event, t.data));
|
||||
}),
|
||||
a.addEventListener('open', async (e) => {
|
||||
n('ready');
|
||||
}),
|
||||
a.addEventListener('close', async (e) => {
|
||||
n('serverOffline', {
|
||||
code: 'NE_CL_NSEROFF',
|
||||
message: 'Neutralino server is offline. Try restarting the application',
|
||||
});
|
||||
}),
|
||||
a.addEventListener('error', async (e) => {
|
||||
((document.body.innerText = ''),
|
||||
document.write(
|
||||
'<code>NE_CL_IVCTOKN</code>: Neutralinojs application cannot connect with the framework core using <code>NL_TOKEN</code>.'
|
||||
));
|
||||
}));
|
||||
}
|
||||
function l(e, t) {
|
||||
return new Promise((n, r) => {
|
||||
if (a?.readyState != WebSocket.OPEN)
|
||||
return ((o = { method: e, data: t, resolve: n, reject: r }), void c.push(o));
|
||||
var o;
|
||||
const i = '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (e) =>
|
||||
(e ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (e / 4)))).toString(16)
|
||||
),
|
||||
u = g();
|
||||
((s[i] = { resolve: n, reject: r }), a.send(JSON.stringify({ id: i, method: e, data: t, accessToken: u })));
|
||||
});
|
||||
}
|
||||
async function f(e) {
|
||||
for (; e.length > 0; ) {
|
||||
const t = e.shift();
|
||||
try {
|
||||
const e = await l(t.method, t.data);
|
||||
t.resolve(e);
|
||||
} catch (e) {
|
||||
t.reject(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function g() {
|
||||
return window.NL_TOKEN || sessionStorage.getItem('NL_TOKEN') || '';
|
||||
}
|
||||
function w(e, t) {
|
||||
return l('filesystem.writeBinaryFile', { path: e, data: o(t) });
|
||||
}
|
||||
var m = {
|
||||
__proto__: null,
|
||||
appendBinaryFile: function (e, t) {
|
||||
return l('filesystem.appendBinaryFile', { path: e, data: o(t) });
|
||||
},
|
||||
appendFile: function (e, t) {
|
||||
return l('filesystem.appendFile', { path: e, data: t });
|
||||
},
|
||||
copy: function (e, t, n) {
|
||||
return l('filesystem.copy', { source: e, destination: t, ...n });
|
||||
},
|
||||
createDirectory: function (e) {
|
||||
return l('filesystem.createDirectory', { path: e });
|
||||
},
|
||||
createWatcher: function (e) {
|
||||
return l('filesystem.createWatcher', { path: e });
|
||||
},
|
||||
getAbsolutePath: function (e) {
|
||||
return l('filesystem.getAbsolutePath', { path: e });
|
||||
},
|
||||
getJoinedPath: function (...e) {
|
||||
return l('filesystem.getJoinedPath', { paths: e });
|
||||
},
|
||||
getNormalizedPath: function (e) {
|
||||
return l('filesystem.getNormalizedPath', { path: e });
|
||||
},
|
||||
getOpenedFileInfo: function (e) {
|
||||
return l('filesystem.getOpenedFileInfo', { id: e });
|
||||
},
|
||||
getPathParts: function (e) {
|
||||
return l('filesystem.getPathParts', { path: e });
|
||||
},
|
||||
getPermissions: function (e) {
|
||||
return l('filesystem.getPermissions', { path: e });
|
||||
},
|
||||
getRelativePath: function (e, t) {
|
||||
return l('filesystem.getRelativePath', { path: e, base: t });
|
||||
},
|
||||
getStats: function (e) {
|
||||
return l('filesystem.getStats', { path: e });
|
||||
},
|
||||
getUnnormalizedPath: function (e) {
|
||||
return l('filesystem.getUnnormalizedPath', { path: e });
|
||||
},
|
||||
getWatchers: function () {
|
||||
return l('filesystem.getWatchers');
|
||||
},
|
||||
move: function (e, t) {
|
||||
return l('filesystem.move', { source: e, destination: t });
|
||||
},
|
||||
openFile: function (e) {
|
||||
return l('filesystem.openFile', { path: e });
|
||||
},
|
||||
readBinaryFile: function (e, t) {
|
||||
return new Promise((n, o) => {
|
||||
l('filesystem.readBinaryFile', { path: e, ...t })
|
||||
.then((e) => {
|
||||
n(r(e));
|
||||
})
|
||||
.catch((e) => {
|
||||
o(e);
|
||||
});
|
||||
});
|
||||
},
|
||||
readDirectory: function (e, t) {
|
||||
return l('filesystem.readDirectory', { path: e, ...t });
|
||||
},
|
||||
readFile: function (e, t) {
|
||||
return l('filesystem.readFile', { path: e, ...t });
|
||||
},
|
||||
remove: function (e) {
|
||||
return l('filesystem.remove', { path: e });
|
||||
},
|
||||
removeWatcher: function (e) {
|
||||
return l('filesystem.removeWatcher', { id: e });
|
||||
},
|
||||
setPermissions: function (e, t, n) {
|
||||
return l('filesystem.setPermissions', { path: e, ...t, mode: n });
|
||||
},
|
||||
updateOpenedFile: function (e, t, n) {
|
||||
return l('filesystem.updateOpenedFile', { id: e, event: t, data: n });
|
||||
},
|
||||
writeBinaryFile: w,
|
||||
writeFile: function (e, t) {
|
||||
return l('filesystem.writeFile', { path: e, data: t });
|
||||
},
|
||||
};
|
||||
function p(e, t) {
|
||||
return l('os.execCommand', { command: e, ...t });
|
||||
}
|
||||
var h = {
|
||||
__proto__: null,
|
||||
execCommand: p,
|
||||
getEnv: function (e) {
|
||||
return l('os.getEnv', { key: e });
|
||||
},
|
||||
getEnvs: function () {
|
||||
return l('os.getEnvs');
|
||||
},
|
||||
getPath: function (e) {
|
||||
return l('os.getPath', { name: e });
|
||||
},
|
||||
getSpawnedProcesses: function () {
|
||||
return l('os.getSpawnedProcesses');
|
||||
},
|
||||
open: function (e) {
|
||||
return l('os.open', { url: e });
|
||||
},
|
||||
setTray: function (e) {
|
||||
return l('os.setTray', e);
|
||||
},
|
||||
showFolderDialog: function (e, t) {
|
||||
return l('os.showFolderDialog', { title: e, ...t });
|
||||
},
|
||||
showMessageBox: function (e, t, n, r) {
|
||||
return l('os.showMessageBox', { title: e, content: t, choice: n, icon: r });
|
||||
},
|
||||
showNotification: function (e, t, n) {
|
||||
return l('os.showNotification', { title: e, content: t, icon: n });
|
||||
},
|
||||
showOpenDialog: function (e, t) {
|
||||
return l('os.showOpenDialog', { title: e, ...t });
|
||||
},
|
||||
showSaveDialog: function (e, t) {
|
||||
return l('os.showSaveDialog', { title: e, ...t });
|
||||
},
|
||||
spawnProcess: function (e, t) {
|
||||
return l('os.spawnProcess', { command: e, ...t });
|
||||
},
|
||||
updateSpawnedProcess: function (e, t, n) {
|
||||
return l('os.updateSpawnedProcess', { id: e, event: t, data: n });
|
||||
},
|
||||
};
|
||||
var y = {
|
||||
__proto__: null,
|
||||
getArch: function () {
|
||||
return l('computer.getArch');
|
||||
},
|
||||
getCPUInfo: function () {
|
||||
return l('computer.getCPUInfo');
|
||||
},
|
||||
getDisplays: function () {
|
||||
return l('computer.getDisplays');
|
||||
},
|
||||
getKernelInfo: function () {
|
||||
return l('computer.getKernelInfo');
|
||||
},
|
||||
getMemoryInfo: function () {
|
||||
return l('computer.getMemoryInfo');
|
||||
},
|
||||
getMousePosition: function () {
|
||||
return l('computer.getMousePosition');
|
||||
},
|
||||
getOSInfo: function () {
|
||||
return l('computer.getOSInfo');
|
||||
},
|
||||
};
|
||||
var _ = {
|
||||
__proto__: null,
|
||||
clear: function () {
|
||||
return l('storage.clear');
|
||||
},
|
||||
getData: function (e) {
|
||||
return l('storage.getData', { key: e });
|
||||
},
|
||||
getKeys: function () {
|
||||
return l('storage.getKeys');
|
||||
},
|
||||
removeData: function (e) {
|
||||
return l('storage.removeData', { key: e });
|
||||
},
|
||||
setData: function (e, t) {
|
||||
return l('storage.setData', { key: e, data: t });
|
||||
},
|
||||
};
|
||||
function v(e, t) {
|
||||
return l('debug.log', { message: e, type: t });
|
||||
}
|
||||
var N = { __proto__: null, log: v };
|
||||
function E(e) {
|
||||
return l('app.exit', { code: e });
|
||||
}
|
||||
var P = {
|
||||
__proto__: null,
|
||||
broadcast: function (e, t) {
|
||||
return l('app.broadcast', { event: e, data: t });
|
||||
},
|
||||
exit: E,
|
||||
getConfig: function () {
|
||||
return l('app.getConfig');
|
||||
},
|
||||
killProcess: function () {
|
||||
return l('app.killProcess');
|
||||
},
|
||||
readProcessInput: function (e) {
|
||||
return l('app.readProcessInput', { readAll: e });
|
||||
},
|
||||
restartProcess: function (e) {
|
||||
return new Promise(async (t) => {
|
||||
let n = window.NL_ARGS.reduce((e, t) => (t.includes(' ') && (t = `"${t}"`), (e += ' ' + t)), '');
|
||||
(e?.args && (n += ' ' + e.args), await p(n, { background: !0 }), E(), t());
|
||||
});
|
||||
},
|
||||
writeProcessError: function (e) {
|
||||
return l('app.writeProcessError', { data: e });
|
||||
},
|
||||
writeProcessOutput: function (e) {
|
||||
return l('app.writeProcessOutput', { data: e });
|
||||
},
|
||||
};
|
||||
const b = new Set(),
|
||||
D = new Map(),
|
||||
T = new Map();
|
||||
function O(e = 0, t = 0) {
|
||||
return l('window.beginDrag', { screenX: e, screenY: t });
|
||||
}
|
||||
function S() {
|
||||
return l('window.getSize');
|
||||
}
|
||||
var L = {
|
||||
__proto__: null,
|
||||
beginDrag: O,
|
||||
center: function () {
|
||||
return l('window.center');
|
||||
},
|
||||
create: function (e, t) {
|
||||
return new Promise((n, r) => {
|
||||
function o(e) {
|
||||
return ('string' != typeof e || ((e = e.trim()).includes(' ') && (e = `"${e}"`)), e);
|
||||
}
|
||||
t = { ...t, useSavedState: !1 };
|
||||
let i = window.NL_ARGS.reduce(
|
||||
(e, t, n) => (
|
||||
(t.includes('--path=') ||
|
||||
t.includes('--debug-mode') ||
|
||||
t.includes('--load-dir-res') ||
|
||||
0 == n) &&
|
||||
(e += ' ' + o(t)),
|
||||
e
|
||||
),
|
||||
''
|
||||
);
|
||||
i += ' --url=' + o(e);
|
||||
for (let e in t) {
|
||||
if ('processArgs' == e) continue;
|
||||
i += ` --window${'-' + e.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()}=${o(t[e])}`;
|
||||
}
|
||||
(t && t.processArgs && (i += ' ' + t.processArgs),
|
||||
p(i, { background: !0 })
|
||||
.then((e) => {
|
||||
n(e);
|
||||
})
|
||||
.catch((e) => {
|
||||
r(e);
|
||||
}));
|
||||
});
|
||||
},
|
||||
exitFullScreen: function () {
|
||||
return l('window.exitFullScreen');
|
||||
},
|
||||
focus: function () {
|
||||
return l('window.focus');
|
||||
},
|
||||
getPosition: function () {
|
||||
return l('window.getPosition');
|
||||
},
|
||||
getSize: S,
|
||||
getTitle: function () {
|
||||
return l('window.getTitle');
|
||||
},
|
||||
hide: function () {
|
||||
return l('window.hide');
|
||||
},
|
||||
isFullScreen: function () {
|
||||
return l('window.isFullScreen');
|
||||
},
|
||||
isMaximized: function () {
|
||||
return l('window.isMaximized');
|
||||
},
|
||||
isMinimized: function () {
|
||||
return l('window.isMinimized');
|
||||
},
|
||||
isVisible: function () {
|
||||
return l('window.isVisible');
|
||||
},
|
||||
maximize: function () {
|
||||
return l('window.maximize');
|
||||
},
|
||||
minimize: function () {
|
||||
return l('window.minimize');
|
||||
},
|
||||
move: function (e, t) {
|
||||
return l('window.move', { x: e, y: t });
|
||||
},
|
||||
print: function () {
|
||||
return l('window.print');
|
||||
},
|
||||
setAlwaysOnTop: function (e) {
|
||||
return l('window.setAlwaysOnTop', { onTop: e });
|
||||
},
|
||||
setBorderless: function (e) {
|
||||
return l('window.setBorderless', { borderless: e });
|
||||
},
|
||||
setDraggableRegion: function (e, t) {
|
||||
return new Promise((n, r) => {
|
||||
const o = e instanceof HTMLElement ? e : document.getElementById(e);
|
||||
if (!o) return r({ code: 'NE_WD_DOMNOTF', message: 'Unable to find DOM element' });
|
||||
if (b.has(o))
|
||||
return r({
|
||||
code: 'NE_WD_ALRDREL',
|
||||
message: 'This DOM element is already an active draggable region',
|
||||
});
|
||||
if (t?.exclude?.length) {
|
||||
const e = new Set();
|
||||
for (const n of t.exclude) {
|
||||
const t = n instanceof HTMLElement ? n : document.getElementById(n);
|
||||
t && e.add(t);
|
||||
}
|
||||
e.size && D.set(o, e);
|
||||
}
|
||||
const a =
|
||||
((s = o),
|
||||
async function (e) {
|
||||
if (0 !== e.button) return;
|
||||
const t = D.get(s);
|
||||
if (t) for (const n of t) if (n.contains(e.target)) return;
|
||||
(await O(e.screenX, e.screenY), e.preventDefault());
|
||||
});
|
||||
var s;
|
||||
(o.addEventListener('pointerdown', a), b.add(o), T.set(o, a));
|
||||
n({
|
||||
success: !0,
|
||||
message: 'Draggable region was activated',
|
||||
exclusions: {
|
||||
add(...e) {
|
||||
if (!b.has(o))
|
||||
throw {
|
||||
code: 'NE_WD_NOTDRRE',
|
||||
message:
|
||||
'DOM element is no longer an active draggable region. You likely called unsetDraggableRegion on this element too early!',
|
||||
};
|
||||
let t = D.get(o);
|
||||
t || ((t = new Set()), D.set(o, t));
|
||||
const n = i(e);
|
||||
for (const e of n) t.add(e);
|
||||
},
|
||||
remove(...e) {
|
||||
if (!b.has(o))
|
||||
throw {
|
||||
code: 'NE_WD_NOTDRRE',
|
||||
message:
|
||||
'DOM element is no longer an active draggable region. You likely called unsetDraggableRegion on this element too early!',
|
||||
};
|
||||
const t = D.get(o);
|
||||
if (!t) return;
|
||||
const n = i(e);
|
||||
for (const e of n) t.delete(e);
|
||||
},
|
||||
removeAll() {
|
||||
if (!b.has(o))
|
||||
throw {
|
||||
code: 'NE_WD_NOTDRRE',
|
||||
message:
|
||||
'DOM element is no longer an active draggable region. You likely called unsetDraggableRegion on this element too early!',
|
||||
};
|
||||
D.delete(o);
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
setFullScreen: function () {
|
||||
return l('window.setFullScreen');
|
||||
},
|
||||
setIcon: function (e) {
|
||||
return l('window.setIcon', { icon: e });
|
||||
},
|
||||
setMainMenu: function (e) {
|
||||
return l('window.setMainMenu', e);
|
||||
},
|
||||
setSize: function (e) {
|
||||
return new Promise(async (t, n) => {
|
||||
let r = await S();
|
||||
l('window.setSize', (e = { ...r, ...e }))
|
||||
.then((e) => {
|
||||
t(e);
|
||||
})
|
||||
.catch((e) => {
|
||||
n(e);
|
||||
});
|
||||
});
|
||||
},
|
||||
setTitle: function (e) {
|
||||
return l('window.setTitle', { title: e });
|
||||
},
|
||||
show: function () {
|
||||
return l('window.show');
|
||||
},
|
||||
snapshot: function (e) {
|
||||
return l('window.snapshot', { path: e });
|
||||
},
|
||||
unmaximize: function () {
|
||||
return l('window.unmaximize');
|
||||
},
|
||||
unminimize: function () {
|
||||
return l('window.unminimize');
|
||||
},
|
||||
unsetDraggableRegion: function (e) {
|
||||
return new Promise((t, n) => {
|
||||
const r = e instanceof HTMLElement ? e : document.getElementById(e);
|
||||
if (!r) return n({ code: 'NE_WD_DOMNOTF', message: 'Unable to find DOM element' });
|
||||
if (!b.has(r))
|
||||
return n({ code: 'NE_WD_NOTDRRE', message: 'DOM element is not an active draggable region' });
|
||||
const o = T.get(r);
|
||||
(o && (r.removeEventListener('pointerdown', o), T.delete(r)),
|
||||
b.delete(r),
|
||||
D.delete(r),
|
||||
t({ success: !0, message: 'Draggable region was deactivated' }));
|
||||
});
|
||||
},
|
||||
};
|
||||
var M = {
|
||||
__proto__: null,
|
||||
broadcast: function (e, t) {
|
||||
return l('events.broadcast', { event: e, data: t });
|
||||
},
|
||||
dispatch: n,
|
||||
off: function (e, t) {
|
||||
return (
|
||||
window.removeEventListener(e, t),
|
||||
Promise.resolve({ success: !0, message: 'Event listener removed' })
|
||||
);
|
||||
},
|
||||
on: t,
|
||||
};
|
||||
function x() {
|
||||
return l('extensions.getStats');
|
||||
}
|
||||
var F = {
|
||||
__proto__: null,
|
||||
broadcast: function (e, t) {
|
||||
return l('extensions.broadcast', { event: e, data: t });
|
||||
},
|
||||
dispatch: function (e, t, n) {
|
||||
return new Promise(async (r, o) => {
|
||||
const i = await x();
|
||||
if (i.loaded.includes(e))
|
||||
if (i.connected.includes(e))
|
||||
try {
|
||||
r(await l('extensions.dispatch', { extensionId: e, event: t, data: n }));
|
||||
} catch (e) {
|
||||
o(e);
|
||||
}
|
||||
else
|
||||
!(function (e, t) {
|
||||
e in u ? u[e].push(t) : (u[e] = [t]);
|
||||
})(e, {
|
||||
method: 'extensions.dispatch',
|
||||
data: { extensionId: e, event: t, data: n },
|
||||
resolve: r,
|
||||
reject: o,
|
||||
});
|
||||
else o({ code: 'NE_EX_EXTNOTL', message: `${e} is not loaded` });
|
||||
});
|
||||
},
|
||||
getStats: x,
|
||||
};
|
||||
let R = null;
|
||||
var A = {
|
||||
__proto__: null,
|
||||
checkForUpdates: function (e) {
|
||||
return new Promise(async (t, n) => {
|
||||
if (!e) return n({ code: 'NE_RT_NATRTER', message: 'Missing require parameter: url' });
|
||||
try {
|
||||
const r = await fetch(e);
|
||||
((R = JSON.parse(await r.text())),
|
||||
!(function (e) {
|
||||
return !!(
|
||||
e.applicationId &&
|
||||
e.applicationId == window.NL_APPID &&
|
||||
e.version &&
|
||||
e.resourcesURL
|
||||
);
|
||||
})(R)
|
||||
? n({
|
||||
code: 'NE_UP_CUPDMER',
|
||||
message: 'Invalid update manifest or mismatching applicationId',
|
||||
})
|
||||
: t(R));
|
||||
} catch (e) {
|
||||
n({ code: 'NE_UP_CUPDERR', message: 'Unable to fetch update manifest' });
|
||||
}
|
||||
});
|
||||
},
|
||||
install: function () {
|
||||
return new Promise(async (e, t) => {
|
||||
if (!R)
|
||||
return t({
|
||||
code: 'NE_UP_UPDNOUF',
|
||||
message:
|
||||
'No update manifest loaded. Make sure that updater.checkForUpdates() is called before install().',
|
||||
});
|
||||
try {
|
||||
const t = await fetch(R.resourcesURL),
|
||||
n = await t.arrayBuffer();
|
||||
(await w(window.NL_PATH + '/resources.neu', n),
|
||||
e({ success: !0, message: 'Update installed. Restart the process to see updates' }));
|
||||
} catch (e) {
|
||||
t({ code: 'NE_UP_UPDINER', message: 'Update installation error' });
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
var I = {
|
||||
__proto__: null,
|
||||
clear: function () {
|
||||
return l('clipboard.clear');
|
||||
},
|
||||
getFormat: function () {
|
||||
return l('clipboard.getFormat');
|
||||
},
|
||||
readHTML: function () {
|
||||
return l('clipboard.readHTML');
|
||||
},
|
||||
readImage: function (e = '') {
|
||||
return new Promise((t, n) => {
|
||||
l('clipboard.readImage')
|
||||
.then((n) => {
|
||||
if (n) {
|
||||
const r = window.atob(n.data);
|
||||
let o,
|
||||
i,
|
||||
a,
|
||||
s = 32 == n.bpp ? 4 : 3;
|
||||
switch (e.toLowerCase()) {
|
||||
case 'rgb':
|
||||
((o = n.width * n.height * 3), (i = [0, 1, 2]));
|
||||
break;
|
||||
case 'rgba':
|
||||
((o = n.width * n.height * 4), (i = [0, 1, 2, 3]));
|
||||
break;
|
||||
case 'argb':
|
||||
((o = n.width * n.height * 4), (i = [3, 0, 1, 2]));
|
||||
break;
|
||||
case 'bgra':
|
||||
((o = n.width * n.height * 4), (i = [2, 1, 0, 3]));
|
||||
break;
|
||||
default:
|
||||
((o = r.length), (a = new Uint8Array(o)));
|
||||
for (let e = 0; e < o; e++) a[e] = r.charCodeAt(e);
|
||||
return ((n.data = a), void t(n));
|
||||
}
|
||||
a = new Uint8Array(o);
|
||||
let c,
|
||||
u,
|
||||
d,
|
||||
l,
|
||||
f,
|
||||
g = 255 == new Uint8Array(new Uint32Array([255]).buffer)[0],
|
||||
w = [],
|
||||
m = 0;
|
||||
for (let e = 0; e < r.length; e += s)
|
||||
((c = r.charCodeAt(e)),
|
||||
(u = r.charCodeAt(e + 1)),
|
||||
(d = r.charCodeAt(e + 2)),
|
||||
(l = 4 == s ? r.charCodeAt(e + 3) : 255),
|
||||
(f = g
|
||||
? ((l << 24) | (d << 16) | (u << 8) | c) >>> 0
|
||||
: ((c << 24) | (u << 16) | (d << 8) | l) >>> 0),
|
||||
(w = [
|
||||
(f >> n.redShift) & 255,
|
||||
(f >> n.greenShift) & 255,
|
||||
(f >> n.blueShift) & 255,
|
||||
(f >> n.alphaShift) & 255,
|
||||
]),
|
||||
i.forEach((e, t) => {
|
||||
a[t + m] = w[e];
|
||||
}),
|
||||
(m += i.length));
|
||||
n.data = a;
|
||||
}
|
||||
t(n);
|
||||
})
|
||||
.catch((e) => {
|
||||
n(e);
|
||||
});
|
||||
});
|
||||
},
|
||||
readText: function () {
|
||||
return l('clipboard.readText');
|
||||
},
|
||||
writeHTML: function (e) {
|
||||
return l('clipboard.writeHTML', { data: e });
|
||||
},
|
||||
writeImage: function (e) {
|
||||
const t = { ...e };
|
||||
return (e?.data && (t.data = o(e.data)), l('clipboard.writeImage', t));
|
||||
},
|
||||
writeText: function (e) {
|
||||
return l('clipboard.writeText', { data: e });
|
||||
},
|
||||
};
|
||||
var C = {
|
||||
__proto__: null,
|
||||
extractDirectory: function (e, t) {
|
||||
return l('resources.extractDirectory', { path: e, destination: t });
|
||||
},
|
||||
extractFile: function (e, t) {
|
||||
return l('resources.extractFile', { path: e, destination: t });
|
||||
},
|
||||
getFiles: function () {
|
||||
return l('resources.getFiles');
|
||||
},
|
||||
getStats: function (e) {
|
||||
return l('resources.getStats', { path: e });
|
||||
},
|
||||
readBinaryFile: function (e) {
|
||||
return new Promise((t, n) => {
|
||||
l('resources.readBinaryFile', { path: e })
|
||||
.then((e) => {
|
||||
t(r(e));
|
||||
})
|
||||
.catch((e) => {
|
||||
n(e);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFile: function (e) {
|
||||
return l('resources.readFile', { path: e });
|
||||
},
|
||||
};
|
||||
var U = {
|
||||
__proto__: null,
|
||||
getMounts: function () {
|
||||
return l('server.getMounts');
|
||||
},
|
||||
mount: function (e, t) {
|
||||
return l('server.mount', { path: e, target: t });
|
||||
},
|
||||
unmount: function (e) {
|
||||
return l('server.unmount', { path: e });
|
||||
},
|
||||
};
|
||||
var k = {
|
||||
__proto__: null,
|
||||
getMethods: function () {
|
||||
return l('custom.getMethods');
|
||||
},
|
||||
};
|
||||
let z = !1;
|
||||
return (
|
||||
(e.app = P),
|
||||
(e.clipboard = I),
|
||||
(e.computer = y),
|
||||
(e.custom = k),
|
||||
(e.debug = N),
|
||||
(e.events = M),
|
||||
(e.extensions = F),
|
||||
(e.filesystem = m),
|
||||
(e.init = function (e = {}) {
|
||||
if (((e = { exportCustomMethods: !0, ...e }), !z)) {
|
||||
if (
|
||||
(d(),
|
||||
window.NL_ARGS.find((e) => '--neu-dev-auto-reload' == e) &&
|
||||
t('neuDev_reloadApp', async () => {
|
||||
(await v('Reloading the application...'), location.reload());
|
||||
}),
|
||||
e.exportCustomMethods && window.NL_CMETHODS && window.NL_CMETHODS.length > 0)
|
||||
)
|
||||
for (const e of window.NL_CMETHODS)
|
||||
Neutralino.custom[e] = (...t) => {
|
||||
let n = {};
|
||||
for (const [e, r] of t.entries())
|
||||
n =
|
||||
'object' != typeof r || Array.isArray(r) || null == r
|
||||
? { ...n, ['arg' + e]: r }
|
||||
: { ...n, ...r };
|
||||
return l('custom.' + e, n);
|
||||
};
|
||||
((window.NL_CVERSION = '6.5.0'),
|
||||
(window.NL_CCOMMIT = '425c526c318342e0e5d0f17caceef2a53049eda4'),
|
||||
(z = !0));
|
||||
}
|
||||
}),
|
||||
(e.os = h),
|
||||
(e.resources = C),
|
||||
(e.server = U),
|
||||
(e.storage = _),
|
||||
(e.updater = A),
|
||||
(e.window = L),
|
||||
e
|
||||
);
|
||||
})({});
|
||||
|
|
@ -1,374 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Monochrome Shell</title>
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
/* Seamless blend */
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="__neutralino_globals.js"></script>
|
||||
<script src="neutralino.js"></script>
|
||||
|
||||
<!-- Load the app from the local Neutralino server -->
|
||||
<iframe id="app-frame" allow="autoplay; fullscreen; microphone; clipboard-read; clipboard-write"></iframe>
|
||||
|
||||
<script>
|
||||
// initialize Neutralino in the Shell (Local Context)
|
||||
try {
|
||||
Neutralino.init();
|
||||
console.log('[Shell] Neutralino initialized.');
|
||||
|
||||
const setupTray = async () => {
|
||||
const iconPath = '/dist/assets/appicon.png';
|
||||
console.log('[Shell] Setting tray icon:', iconPath);
|
||||
const tray = {
|
||||
icon: iconPath,
|
||||
menuItems: [
|
||||
{ id: 'show', text: 'Show Monochrome' },
|
||||
{ id: 'sep', text: '-' },
|
||||
{ id: 'quit', text: 'Quit' },
|
||||
],
|
||||
};
|
||||
try {
|
||||
await Neutralino.os.setTray(tray);
|
||||
console.log('[Shell] Tray set successfully');
|
||||
} catch (e) {
|
||||
console.error('[Shell] Tray error:', e);
|
||||
await Neutralino.os.showMessageBox(
|
||||
'Tray Error',
|
||||
`Failed to set tray: ${JSON.stringify(e)}`,
|
||||
'ERROR'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Neutralino.events.on('ready', setupTray);
|
||||
|
||||
Neutralino.events.on('trayMenuItemClicked', async (event) => {
|
||||
switch (event.detail.id) {
|
||||
case 'show':
|
||||
await Neutralino.window.show();
|
||||
await Neutralino.window.unminimize();
|
||||
await Neutralino.window.focus();
|
||||
break;
|
||||
case 'quit':
|
||||
await Neutralino.app.exit();
|
||||
break;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('[Shell] Failed to init Neutralino:', e);
|
||||
}
|
||||
|
||||
// Point iframe to local server using the port from Neutralino
|
||||
// NL_PORT is available globally after init (or we can parse it/wait for it)
|
||||
// Neutralino.init() usually populates window.NL_PORT or we read it from sessionStorage
|
||||
|
||||
const initFrame = async () => {
|
||||
// Simplified Dev Mode Detection using Neutralino's internal args
|
||||
// 'neu run' adds --neu-dev-auto-reload, which we can use to detect dev environment.
|
||||
const args = window.NL_ARGS || [];
|
||||
const isDev = args.some((arg) => arg.includes('--neu-dev-auto-reload') || arg.includes('--debug-mode'));
|
||||
|
||||
// Static Dev Port
|
||||
const DEV_PORT = '5173';
|
||||
|
||||
let port = window.NL_PORT || sessionStorage.getItem('NL_PORT') || '5050';
|
||||
const iframe = document.getElementById('app-frame');
|
||||
|
||||
const targetPort = isDev ? DEV_PORT : port;
|
||||
const targetUrl = `http://localhost:${targetPort}/?mode=neutralino`;
|
||||
|
||||
if (isDev) {
|
||||
console.log(`[Shell] Dev mode detected via NL_ARGS. Waiting 2s for Vite on port ${targetPort}...`);
|
||||
await new Promise((r) => setTimeout(r, 2000));
|
||||
} else {
|
||||
console.log(`[Shell] Production mode detected.`);
|
||||
}
|
||||
|
||||
console.log(`[Shell] Loading app from: ${targetUrl}`);
|
||||
iframe.src = targetUrl;
|
||||
};
|
||||
|
||||
initFrame();
|
||||
|
||||
const iframe = document.getElementById('app-frame');
|
||||
|
||||
// Forward generic Neutralino events to the Iframe
|
||||
const forwardEvent = (eventName, detail) => {
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{
|
||||
type: 'NL_EVENT',
|
||||
eventName: eventName,
|
||||
detail: detail,
|
||||
},
|
||||
'*'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Listen for specific events to forward
|
||||
// Add more here if the app needs them (e.g., tray events)
|
||||
Neutralino.events.on('windowFocus', () => forwardEvent('windowFocus'));
|
||||
Neutralino.events.on('windowBlur', () => forwardEvent('windowBlur'));
|
||||
|
||||
// Media Key Events (Linux Fix)
|
||||
Neutralino.events.on('mediaNext', () => forwardEvent('mediaNext'));
|
||||
Neutralino.events.on('mediaPrevious', () => forwardEvent('mediaPrevious'));
|
||||
Neutralino.events.on('mediaPlayPause', () => forwardEvent('mediaPlayPause'));
|
||||
Neutralino.events.on('mediaStop', () => forwardEvent('mediaStop'));
|
||||
|
||||
// Handle commands from the Iframe (via Bridge)
|
||||
window.addEventListener('message', async (event) => {
|
||||
const { type, eventName, data, extensionId } = event.data;
|
||||
|
||||
// Security: In a real scenario, check event.origin if possible.
|
||||
// But since this loads valid HTTPS content, it's generally safe for this context.
|
||||
|
||||
switch (type) {
|
||||
case 'NL_INIT':
|
||||
console.log('[Shell] Bridge connected.');
|
||||
break;
|
||||
|
||||
case 'NL_BROADCAST':
|
||||
// e.g. Discord RPC updates
|
||||
try {
|
||||
// console.log('[Shell] Broadcasting:', eventName, data);
|
||||
await Neutralino.events.broadcast(eventName, data);
|
||||
} catch (e) {
|
||||
console.error('[Shell] Broadcast failed:', e);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_EXTENSION':
|
||||
// e.g. specific extension dispatch
|
||||
try {
|
||||
// console.log('[Shell] Dispatching to extension:', extensionId, eventName);
|
||||
await Neutralino.extensions.dispatch(extensionId, eventName, data);
|
||||
} catch (e) {
|
||||
console.error('[Shell] Extension dispatch failed:', e);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_APP_EXIT':
|
||||
Neutralino.app.exit();
|
||||
break;
|
||||
|
||||
case 'NL_WINDOW_MIN':
|
||||
Neutralino.window.minimize();
|
||||
break;
|
||||
|
||||
case 'NL_WINDOW_MAX':
|
||||
try {
|
||||
const isMax = await Neutralino.window.isMaximized();
|
||||
if (isMax) Neutralino.window.unmaximize();
|
||||
else Neutralino.window.maximize();
|
||||
} catch (e) {
|
||||
console.error('[Shell] Window toggle failed:', e);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_WINDOW_SET_TITLE':
|
||||
try {
|
||||
await Neutralino.window.setTitle(event.data.title);
|
||||
} catch (e) {
|
||||
console.error('[Shell] Set title failed:', e);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_OS_OPEN':
|
||||
try {
|
||||
console.log('[Shell] Opening external URL:', event.data.url);
|
||||
await Neutralino.os.open(event.data.url);
|
||||
} catch (e) {
|
||||
console.error('[Shell] Failed to open URL:', e);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_OS_SHOW_SAVE_DIALOG':
|
||||
try {
|
||||
const result = await Neutralino.os.showSaveDialog(event.data.title, event.data.options);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Show Save Dialog failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_OS_SHOW_FOLDER_DIALOG':
|
||||
try {
|
||||
const result = await Neutralino.os.showFolderDialog(event.data.title, event.data.options);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Show Folder Dialog failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_READ_BINARY':
|
||||
try {
|
||||
const result = await Neutralino.filesystem.readBinaryFile(event.data.path);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
// result is ArrayBuffer, should be transferable
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result },
|
||||
'*',
|
||||
[result]
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Read Binary File failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_READ_DIR':
|
||||
try {
|
||||
const result = await Neutralino.filesystem.readDirectory(event.data.path);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Read Directory failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_STATS':
|
||||
try {
|
||||
const result = await Neutralino.filesystem.getStats(event.data.path);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Get Stats failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_WRITE_BINARY':
|
||||
try {
|
||||
// buffer comes as ArrayBuffer in event.data.buffer (if transferred) or event.data.buffer
|
||||
await Neutralino.filesystem.writeBinaryFile(event.data.path, event.data.buffer);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result: 'success' },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Write Binary File failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_APPEND_BINARY':
|
||||
try {
|
||||
await Neutralino.filesystem.appendBinaryFile(event.data.path, event.data.buffer);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result: 'success' },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Append Binary File failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NL_FS_CREATE_DIR':
|
||||
try {
|
||||
await Neutralino.filesystem.createDirectory(event.data.path);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, result: 'success' },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[Shell] Create Directory failed:', e);
|
||||
if (iframe && iframe.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{ type: 'NL_RESPONSE', id: event.data.id, error: e },
|
||||
'*'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import fs from 'fs';
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
const CONFIG_FILE = 'neutralino.config.json';
|
||||
const DEV_CONFIG_FILE = 'neutralino.config.dev.json';
|
||||
const BACKUP_CONFIG_FILE = 'neutralino.config.prod.bak';
|
||||
|
||||
function restoreConfig() {
|
||||
if (fs.existsSync(BACKUP_CONFIG_FILE)) {
|
||||
try {
|
||||
// If the current config is the dev one (we can check via content or assume), remove it
|
||||
if (fs.existsSync(CONFIG_FILE)) {
|
||||
fs.unlinkSync(CONFIG_FILE);
|
||||
}
|
||||
fs.renameSync(BACKUP_CONFIG_FILE, CONFIG_FILE);
|
||||
console.log('Restored production configuration.');
|
||||
} catch (e) {
|
||||
console.error('Failed to restore configuration:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we clean up on exit
|
||||
process.on('SIGINT', () => {
|
||||
restoreConfig();
|
||||
process.exit();
|
||||
});
|
||||
|
||||
process.on('exit', () => {
|
||||
restoreConfig();
|
||||
});
|
||||
|
||||
async function run() {
|
||||
if (!fs.existsSync(DEV_CONFIG_FILE)) {
|
||||
console.error('Error: neutralino.config.dev.json not found.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
// Backup production config
|
||||
if (fs.existsSync(CONFIG_FILE)) {
|
||||
fs.renameSync(CONFIG_FILE, BACKUP_CONFIG_FILE);
|
||||
}
|
||||
|
||||
// Copy dev config to main
|
||||
fs.copyFileSync(DEV_CONFIG_FILE, CONFIG_FILE);
|
||||
console.log('Switched to development configuration.');
|
||||
|
||||
// Run neu
|
||||
const neu = spawn('npx', ['neu', 'run'], { stdio: 'inherit', shell: true });
|
||||
|
||||
neu.on('close', (code) => {
|
||||
console.log(`Neutralino process exited with code ${code}`);
|
||||
restoreConfig();
|
||||
process.exit(code);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Error running dev environment:', e);
|
||||
restoreConfig();
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
import neutralino from 'vite-plugin-neutralino';
|
||||
import authGatePlugin from './vite-plugin-auth-gate.js';
|
||||
import path from 'path';
|
||||
import uploadPlugin from './vite-plugin-upload.js';
|
||||
|
|
@ -17,7 +16,6 @@ function getGitCommitHash() {
|
|||
}
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const IS_NEUTRALINO = mode === 'neutralino';
|
||||
const commitHash = getGitCommitHash();
|
||||
|
||||
return {
|
||||
|
|
@ -59,7 +57,6 @@ export default defineConfig(({ mode }) => {
|
|||
sourcemap: true,
|
||||
},
|
||||
plugins: [
|
||||
IS_NEUTRALINO && neutralino(),
|
||||
authGatePlugin(),
|
||||
uploadPlugin(),
|
||||
blobAssetPlugin(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue