This commit is contained in:
JellyBrick
2026-01-29 17:25:53 +09:00
7 changed files with 220 additions and 229 deletions

View File

@ -126,7 +126,7 @@
"socks": "2.8.7", "socks": "2.8.7",
"solid-element": "1.9.1", "solid-element": "1.9.1",
"solid-floating-ui": "0.3.1", "solid-floating-ui": "0.3.1",
"solid-js": "1.9.10", "solid-js": "1.9.11",
"solid-styled-components": "0.28.5", "solid-styled-components": "0.28.5",
"solid-transition-group": "0.3.0", "solid-transition-group": "0.3.0",
"tiny-pinyin": "1.3.2", "tiny-pinyin": "1.3.2",
@ -141,7 +141,7 @@
"@electron-toolkit/tsconfig": "1.0.1", "@electron-toolkit/tsconfig": "1.0.1",
"@eslint/js": "9.39.2", "@eslint/js": "9.39.2",
"@malept/flatpak-bundler": "0.4.0", "@malept/flatpak-bundler": "0.4.0",
"@playwright/test": "1.57.0", "@playwright/test": "1.58.0",
"@stylistic/eslint-plugin": "5.7.1", "@stylistic/eslint-plugin": "5.7.1",
"@total-typescript/ts-reset": "0.6.1", "@total-typescript/ts-reset": "0.6.1",
"@types/electron-localshortcut": "3.1.3", "@types/electron-localshortcut": "3.1.3",
@ -154,7 +154,7 @@
"cross-env": "10.1.0", "cross-env": "10.1.0",
"del-cli": "6.0.0", "del-cli": "6.0.0",
"discord-api-types": "0.38.37", "discord-api-types": "0.38.37",
"electron": "38.7.2", "electron": "38.8.0",
"electron-builder": "26.4.0", "electron-builder": "26.4.0",
"electron-builder-squirrel-windows": "26.4.0", "electron-builder-squirrel-windows": "26.4.0",
"electron-devtools-installer": "4.0.0", "electron-devtools-installer": "4.0.0",

158
pnpm-lock.yaml generated
View File

@ -44,7 +44,7 @@ importers:
version: 1.0.1(@types/node@24.3.0) version: 1.0.1(@types/node@24.3.0)
'@electron/remote': '@electron/remote':
specifier: 2.1.3 specifier: 2.1.3
version: 2.1.3(electron@38.7.2) version: 2.1.3(electron@38.8.0)
'@ffmpeg.wasm/core-mt': '@ffmpeg.wasm/core-mt':
specifier: 0.12.0 specifier: 0.12.0
version: 0.12.0 version: 0.12.0
@ -59,10 +59,10 @@ importers:
version: 2.0.5 version: 2.0.5
'@ghostery/adblocker-electron': '@ghostery/adblocker-electron':
specifier: 2.13.4 specifier: 2.13.4
version: 2.13.4(electron@38.7.2) version: 2.13.4(electron@38.8.0)
'@ghostery/adblocker-electron-preload': '@ghostery/adblocker-electron-preload':
specifier: 2.13.4 specifier: 2.13.4
version: 2.13.4(electron@38.7.2) version: 2.13.4(electron@38.8.0)
'@hono/node-server': '@hono/node-server':
specifier: 1.19.9 specifier: 1.19.9
version: 1.19.9(hono@4.11.7) version: 1.19.9(hono@4.11.7)
@ -119,7 +119,7 @@ importers:
version: 14.0.0 version: 14.0.0
custom-electron-prompt: custom-electron-prompt:
specifier: 1.6.1 specifier: 1.6.1
version: 1.6.1(electron@38.7.2) version: 1.6.1(electron@38.8.0)
deepmerge-ts: deepmerge-ts:
specifier: 7.1.5 specifier: 7.1.5
version: 7.1.5 version: 7.1.5
@ -221,19 +221,19 @@ importers:
version: 2.8.7 version: 2.8.7
solid-element: solid-element:
specifier: 1.9.1 specifier: 1.9.1
version: 1.9.1(solid-js@1.9.10) version: 1.9.1(solid-js@1.9.11)
solid-floating-ui: solid-floating-ui:
specifier: 0.3.1 specifier: 0.3.1
version: 0.3.1(@floating-ui/dom@1.7.5)(solid-js@1.9.10) version: 0.3.1(@floating-ui/dom@1.7.5)(solid-js@1.9.11)
solid-js: solid-js:
specifier: 1.9.10 specifier: 1.9.11
version: 1.9.10 version: 1.9.11
solid-styled-components: solid-styled-components:
specifier: 0.28.5 specifier: 0.28.5
version: 0.28.5(solid-js@1.9.10) version: 0.28.5(solid-js@1.9.11)
solid-transition-group: solid-transition-group:
specifier: 0.3.0 specifier: 0.3.0
version: 0.3.0(solid-js@1.9.10) version: 0.3.0(solid-js@1.9.11)
tiny-pinyin: tiny-pinyin:
specifier: 1.3.2 specifier: 1.3.2
version: 1.3.2 version: 1.3.2
@ -242,7 +242,7 @@ importers:
version: 1.3.4 version: 1.3.4
virtua: virtua:
specifier: 0.48.5 specifier: 0.48.5
version: 0.48.5(solid-js@1.9.10) version: 0.48.5(solid-js@1.9.11)
vudio: vudio:
specifier: 2.1.1 specifier: 2.1.1
version: 2.1.1(patch_hash=0e06c2ed11c02bdc490c209fa80070e98517c2735c641f5738b6e15d7dc1959d) version: 2.1.1(patch_hash=0e06c2ed11c02bdc490c209fa80070e98517c2735c641f5738b6e15d7dc1959d)
@ -263,8 +263,8 @@ importers:
specifier: 0.4.0 specifier: 0.4.0
version: 0.4.0(patch_hash=c787371eeb2af011ea934e8818a0dad6d7dcb2df31bbb1686babc7231af0183c) version: 0.4.0(patch_hash=c787371eeb2af011ea934e8818a0dad6d7dcb2df31bbb1686babc7231af0183c)
'@playwright/test': '@playwright/test':
specifier: 1.57.0 specifier: 1.58.0
version: 1.57.0 version: 1.58.0
'@stylistic/eslint-plugin': '@stylistic/eslint-plugin':
specifier: 5.7.1 specifier: 5.7.1
version: 5.7.1(eslint@9.39.2(jiti@2.6.1)) version: 5.7.1(eslint@9.39.2(jiti@2.6.1))
@ -302,8 +302,8 @@ importers:
specifier: 0.38.37 specifier: 0.38.37
version: 0.38.37 version: 0.38.37
electron: electron:
specifier: 38.7.2 specifier: 38.8.0
version: 38.7.2 version: 38.8.0
electron-builder: electron-builder:
specifier: 26.4.0 specifier: 26.4.0
version: 26.4.0(electron-builder-squirrel-windows@26.4.0) version: 26.4.0(electron-builder-squirrel-windows@26.4.0)
@ -366,7 +366,7 @@ importers:
version: 2.5.2 version: 2.5.2
vite-plugin-solid: vite-plugin-solid:
specifier: 2.11.10 specifier: 2.11.10
version: 2.11.10(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1))(solid-js@1.9.10) version: 2.11.10(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1))(solid-js@1.9.11)
ws: ws:
specifier: 8.19.0 specifier: 8.19.0
version: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) version: 8.19.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)
@ -1136,8 +1136,8 @@ packages:
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
'@playwright/test@1.57.0': '@playwright/test@1.58.0':
resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} resolution: {integrity: sha512-fWza+Lpbj6SkQKCrU6si4iu+fD2dD3gxNHFhUPxsfXBPhnv3rRSQVd0NtBUT9Z/RhF/boCBcuUaMUSTRTopjZg==}
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
@ -2293,8 +2293,8 @@ packages:
resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
electron@38.7.2: electron@38.8.0:
resolution: {integrity: sha512-BcjR0IHqp3uv4ytVQwW2/9zAWo17Rjwrydn6RS+g+vqhpcPTzmBHDCHKaEcqheSl/7zzKPgFZdvT21BoSfrxRQ==} resolution: {integrity: sha512-cMvNuIFdXXDr4pJd5xD+F8FDjQhin9vyJ5hGSb5cZRIUb1VqfvRyP2nLBzU2Iazj0z3L686AUOkykp6Xd8bT1w==}
engines: {node: '>= 12.20.55'} engines: {node: '>= 12.20.55'}
hasBin: true hasBin: true
@ -3825,13 +3825,13 @@ packages:
resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==} resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==}
hasBin: true hasBin: true
playwright-core@1.57.0: playwright-core@1.58.0:
resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} resolution: {integrity: sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw==}
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
playwright@1.57.0: playwright@1.58.0:
resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} resolution: {integrity: sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
hasBin: true hasBin: true
@ -4115,14 +4115,14 @@ packages:
resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==}
engines: {node: '>=10'} engines: {node: '>=10'}
seroval-plugins@1.3.2: seroval-plugins@1.5.0:
resolution: {integrity: sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==} resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==}
engines: {node: '>=10'} engines: {node: '>=10'}
peerDependencies: peerDependencies:
seroval: ^1.0 seroval: ^1.0
seroval@1.3.2: seroval@1.5.0:
resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==}
engines: {node: '>=10'} engines: {node: '>=10'}
serve-handler@6.1.6: serve-handler@6.1.6:
@ -4223,8 +4223,8 @@ packages:
'@floating-ui/dom': ^1.5 '@floating-ui/dom': ^1.5
solid-js: ^1.8 solid-js: ^1.8
solid-js@1.9.10: solid-js@1.9.11:
resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==}
solid-refresh@0.6.3: solid-refresh@0.6.3:
resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==}
@ -5110,9 +5110,9 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@electron/remote@2.1.3(electron@38.7.2)': '@electron/remote@2.1.3(electron@38.8.0)':
dependencies: dependencies:
electron: 38.7.2 electron: 38.8.0
'@electron/universal@3.0.2': '@electron/universal@3.0.2':
dependencies: dependencies:
@ -5303,16 +5303,16 @@ snapshots:
dependencies: dependencies:
'@ghostery/adblocker-extended-selectors': 2.13.4 '@ghostery/adblocker-extended-selectors': 2.13.4
'@ghostery/adblocker-electron-preload@2.13.4(electron@38.7.2)': '@ghostery/adblocker-electron-preload@2.13.4(electron@38.8.0)':
dependencies: dependencies:
'@ghostery/adblocker-content': 2.13.4 '@ghostery/adblocker-content': 2.13.4
electron: 38.7.2 electron: 38.8.0
'@ghostery/adblocker-electron@2.13.4(electron@38.7.2)': '@ghostery/adblocker-electron@2.13.4(electron@38.8.0)':
dependencies: dependencies:
'@ghostery/adblocker': 2.13.4 '@ghostery/adblocker': 2.13.4
'@ghostery/adblocker-electron-preload': 2.13.4(electron@38.7.2) '@ghostery/adblocker-electron-preload': 2.13.4(electron@38.8.0)
electron: 38.7.2 electron: 38.8.0
tldts-experimental: 7.0.19 tldts-experimental: 7.0.19
'@ghostery/adblocker-extended-selectors@2.13.4': {} '@ghostery/adblocker-extended-selectors@2.13.4': {}
@ -5718,9 +5718,9 @@ snapshots:
'@pkgr/core@0.2.9': {} '@pkgr/core@0.2.9': {}
'@playwright/test@1.57.0': '@playwright/test@1.58.0':
dependencies: dependencies:
playwright: 1.57.0 playwright: 1.58.0
'@polka/url@1.0.0-next.29': {} '@polka/url@1.0.0-next.29': {}
@ -5801,18 +5801,18 @@ snapshots:
'@skyra/jaro-winkler@1.1.1': {} '@skyra/jaro-winkler@1.1.1': {}
'@solid-primitives/refs@1.1.2(solid-js@1.9.10)': '@solid-primitives/refs@1.1.2(solid-js@1.9.11)':
dependencies: dependencies:
'@solid-primitives/utils': 6.3.2(solid-js@1.9.10) '@solid-primitives/utils': 6.3.2(solid-js@1.9.11)
solid-js: 1.9.10 solid-js: 1.9.11
'@solid-primitives/transition-group@1.1.2(solid-js@1.9.10)': '@solid-primitives/transition-group@1.1.2(solid-js@1.9.11)':
dependencies: dependencies:
solid-js: 1.9.10 solid-js: 1.9.11
'@solid-primitives/utils@6.3.2(solid-js@1.9.10)': '@solid-primitives/utils@6.3.2(solid-js@1.9.11)':
dependencies: dependencies:
solid-js: 1.9.10 solid-js: 1.9.11
'@stylistic/eslint-plugin@5.7.1(eslint@9.39.2(jiti@2.6.1))': '@stylistic/eslint-plugin@5.7.1(eslint@9.39.2(jiti@2.6.1))':
dependencies: dependencies:
@ -5877,7 +5877,7 @@ snapshots:
'@types/electron-localshortcut@3.1.3': '@types/electron-localshortcut@3.1.3':
dependencies: dependencies:
electron: 38.7.2 electron: 38.8.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -6312,12 +6312,12 @@ snapshots:
parse5: 7.3.0 parse5: 7.3.0
validate-html-nesting: 1.2.3 validate-html-nesting: 1.2.3
babel-preset-solid@1.9.9(@babel/core@7.28.3)(solid-js@1.9.10): babel-preset-solid@1.9.9(@babel/core@7.28.3)(solid-js@1.9.11):
dependencies: dependencies:
'@babel/core': 7.28.3 '@babel/core': 7.28.3
babel-plugin-jsx-dom-expressions: 0.40.1(@babel/core@7.28.3) babel-plugin-jsx-dom-expressions: 0.40.1(@babel/core@7.28.3)
optionalDependencies: optionalDependencies:
solid-js: 1.9.10 solid-js: 1.9.11
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
@ -6658,9 +6658,9 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
custom-electron-prompt@1.6.1(electron@38.7.2): custom-electron-prompt@1.6.1(electron@38.8.0):
optionalDependencies: optionalDependencies:
electron: 38.7.2 electron: 38.8.0
data-uri-to-buffer@4.0.1: {} data-uri-to-buffer@4.0.1: {}
@ -6986,7 +6986,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
electron@38.7.2: electron@38.8.0:
dependencies: dependencies:
'@electron/get': 2.0.3 '@electron/get': 2.0.3
'@types/node': 22.17.2 '@types/node': 22.17.2
@ -8629,11 +8629,11 @@ snapshots:
dependencies: dependencies:
pngjs: 6.0.0 pngjs: 6.0.0
playwright-core@1.57.0: {} playwright-core@1.58.0: {}
playwright@1.57.0: playwright@1.58.0:
dependencies: dependencies:
playwright-core: 1.57.0 playwright-core: 1.58.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
@ -8910,11 +8910,11 @@ snapshots:
type-fest: 0.13.1 type-fest: 0.13.1
optional: true optional: true
seroval-plugins@1.3.2(seroval@1.3.2): seroval-plugins@1.5.0(seroval@1.5.0):
dependencies: dependencies:
seroval: 1.3.2 seroval: 1.5.0
seroval@1.3.2: {} seroval@1.5.0: {}
serve-handler@6.1.6: serve-handler@6.1.6:
dependencies: dependencies:
@ -9040,42 +9040,42 @@ snapshots:
ip-address: 10.0.1 ip-address: 10.0.1
smart-buffer: 4.2.0 smart-buffer: 4.2.0
solid-element@1.9.1(solid-js@1.9.10): solid-element@1.9.1(solid-js@1.9.11):
dependencies: dependencies:
component-register: 0.8.7 component-register: 0.8.7
solid-js: 1.9.10 solid-js: 1.9.11
solid-floating-ui@0.3.1(@floating-ui/dom@1.7.5)(solid-js@1.9.10): solid-floating-ui@0.3.1(@floating-ui/dom@1.7.5)(solid-js@1.9.11):
dependencies: dependencies:
'@floating-ui/dom': 1.7.5 '@floating-ui/dom': 1.7.5
solid-js: 1.9.10 solid-js: 1.9.11
solid-js@1.9.10: solid-js@1.9.11:
dependencies: dependencies:
csstype: 3.1.3 csstype: 3.1.3
seroval: 1.3.2 seroval: 1.5.0
seroval-plugins: 1.3.2(seroval@1.3.2) seroval-plugins: 1.5.0(seroval@1.5.0)
solid-refresh@0.6.3(solid-js@1.9.10): solid-refresh@0.6.3(solid-js@1.9.11):
dependencies: dependencies:
'@babel/generator': 7.28.3 '@babel/generator': 7.28.3
'@babel/helper-module-imports': 7.27.1 '@babel/helper-module-imports': 7.27.1
'@babel/types': 7.28.2 '@babel/types': 7.28.2
solid-js: 1.9.10 solid-js: 1.9.11
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
solid-styled-components@0.28.5(solid-js@1.9.10): solid-styled-components@0.28.5(solid-js@1.9.11):
dependencies: dependencies:
csstype: 3.1.3 csstype: 3.1.3
goober: 2.1.16(csstype@3.1.3) goober: 2.1.16(csstype@3.1.3)
solid-js: 1.9.10 solid-js: 1.9.11
solid-transition-group@0.3.0(solid-js@1.9.10): solid-transition-group@0.3.0(solid-js@1.9.11):
dependencies: dependencies:
'@solid-primitives/refs': 1.1.2(solid-js@1.9.10) '@solid-primitives/refs': 1.1.2(solid-js@1.9.11)
'@solid-primitives/transition-group': 1.1.2(solid-js@1.9.10) '@solid-primitives/transition-group': 1.1.2(solid-js@1.9.11)
solid-js: 1.9.10 solid-js: 1.9.11
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
@ -9452,9 +9452,9 @@ snapshots:
extsprintf: 1.4.1 extsprintf: 1.4.1
optional: true optional: true
virtua@0.48.5(solid-js@1.9.10): virtua@0.48.5(solid-js@1.9.11):
optionalDependencies: optionalDependencies:
solid-js: 1.9.10 solid-js: 1.9.11
vite-dev-rpc@1.1.0(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1)): vite-dev-rpc@1.1.0(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1)):
dependencies: dependencies:
@ -9485,14 +9485,14 @@ snapshots:
dependencies: dependencies:
lib-esm: 0.4.2 lib-esm: 0.4.2
vite-plugin-solid@2.11.10(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1))(solid-js@1.9.10): vite-plugin-solid@2.11.10(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1))(solid-js@1.9.11):
dependencies: dependencies:
'@babel/core': 7.28.3 '@babel/core': 7.28.3
'@types/babel__core': 7.20.5 '@types/babel__core': 7.20.5
babel-preset-solid: 1.9.9(@babel/core@7.28.3)(solid-js@1.9.10) babel-preset-solid: 1.9.9(@babel/core@7.28.3)(solid-js@1.9.11)
merge-anything: 5.1.7 merge-anything: 5.1.7
solid-js: 1.9.10 solid-js: 1.9.11
solid-refresh: 0.6.3(solid-js@1.9.10) solid-refresh: 0.6.3(solid-js@1.9.11)
vite: rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1) vite: rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1)
vitefu: 1.1.1(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1)) vitefu: 1.1.1(rolldown-vite@7.3.1(@types/node@24.3.0)(jiti@2.6.1)(yaml@2.8.1))
transitivePeerDependencies: transitivePeerDependencies:

View File

@ -18,7 +18,6 @@ export type VisualizerPluginConfig = {
type: 'butterchurn' | 'vudio' | 'wave'; type: 'butterchurn' | 'vudio' | 'wave';
butterchurn: { butterchurn: {
preset: string; preset: string;
renderingFrequencyInMs: number;
blendTimeInSeconds: number; blendTimeInSeconds: number;
}; };
vudio: { vudio: {
@ -57,17 +56,23 @@ export type VisualizerPluginConfig = {
}; };
}; };
type RenderProps = {
visualizerInstance: Visualizer | null;
audioContext: AudioContext | null;
audioSource: MediaElementAudioSourceNode | null;
observer: ResizeObserver | null;
};
export default createPlugin({ export default createPlugin({
name: () => t('plugins.visualizer.name'), name: () => t('plugins.visualizer.name'),
description: () => t('plugins.visualizer.description'), description: () => t('plugins.visualizer.description'),
restartNeeded: true, restartNeeded: false,
config: { config: {
enabled: false, enabled: false,
type: 'butterchurn', type: 'butterchurn',
// Config per visualizer // Config per visualizer
butterchurn: { butterchurn: {
preset: 'martin [shadow harlequins shape code] - fata morgana', preset: 'martin [shadow harlequins shape code] - fata morgana',
renderingFrequencyInMs: 500,
blendTimeInSeconds: 2.7, blendTimeInSeconds: 2.7,
}, },
vudio: { vudio: {
@ -148,81 +153,91 @@ export default createPlugin({
}, },
renderer: { renderer: {
async onPlayerApiReady(_, { getConfig }) { props: {
const config = await getConfig(); visualizerInstance: null,
audioContext: null,
audioSource: null,
observer: null,
} as RenderProps,
// eslint-disable-next-line @typescript-eslint/no-explicit-any createVisualizer(
let visualizerType: { new (...args: any[]): Visualizer<unknown> } = vudio; this: { props: RenderProps },
config: VisualizerPluginConfig,
) {
this.props.visualizerInstance?.destroy();
this.props.visualizerInstance = null;
if (!this.props.audioContext || !this.props.audioSource) return;
if (!config.enabled) return;
const video = document.querySelector<
HTMLVideoElement & { captureStream(): MediaStream }
>('video');
if (!video) {
return;
}
const visualizerContainer =
document.querySelector<HTMLElement>('#player');
if (!visualizerContainer) {
return;
}
let canvas = document.querySelector<HTMLCanvasElement>('#visualizer');
if (!canvas) {
canvas = document.createElement('canvas');
canvas.id = 'visualizer';
visualizerContainer?.prepend(canvas);
}
const gainNode = this.props.audioContext.createGain();
gainNode.gain.value = 1.25;
this.props.audioSource.connect(gainNode);
let visualizerType: {
new (...args: ConstructorParameters<typeof vudio>): Visualizer;
} = vudio;
if (config.type === 'wave') { if (config.type === 'wave') {
visualizerType = wave; visualizerType = wave;
} else if (config.type === 'butterchurn') { } else if (config.type === 'butterchurn') {
visualizerType = butterchurn; visualizerType = butterchurn;
} }
this.props.visualizerInstance = new visualizerType(
this.props.audioContext,
this.props.audioSource,
canvas,
gainNode,
video.captureStream(),
config,
);
const resizeVisualizer = () => {
if (canvas && visualizerContainer) {
const { width, height } =
window.getComputedStyle(visualizerContainer);
canvas.width = Math.ceil(parseFloat(width));
canvas.height = Math.ceil(parseFloat(height));
}
this.props.visualizerInstance?.resize(canvas.width, canvas.height);
};
resizeVisualizer();
this.props.observer?.disconnect();
this.props.observer = new ResizeObserver(resizeVisualizer);
this.props.observer.observe(visualizerContainer);
},
onConfigChange(newConfig) {
this.createVisualizer(newConfig);
},
onPlayerApiReady(_, { getConfig }) {
document.addEventListener( document.addEventListener(
'peard:audio-can-play', 'peard:audio-can-play',
(e) => { async (e) => {
const video = document.querySelector< this.props.audioContext = e.detail.audioContext;
HTMLVideoElement & { captureStream(): MediaStream } this.props.audioSource = e.detail.audioSource;
>('video'); this.createVisualizer(await getConfig());
if (!video) {
return;
}
const visualizerContainer =
document.querySelector<HTMLElement>('#player');
if (!visualizerContainer) {
return;
}
let canvas = document.querySelector<HTMLCanvasElement>('#visualizer');
if (!canvas) {
canvas = document.createElement('canvas');
canvas.id = 'visualizer';
visualizerContainer?.prepend(canvas);
}
const resizeCanvas = () => {
if (canvas) {
canvas.width = visualizerContainer.clientWidth;
canvas.height = visualizerContainer.clientHeight;
}
};
resizeCanvas();
const gainNode = e.detail.audioContext.createGain();
gainNode.gain.value = 1.25;
e.detail.audioSource.connect(gainNode);
const visualizer = new visualizerType(
e.detail.audioContext,
e.detail.audioSource,
visualizerContainer,
canvas,
gainNode,
video.captureStream(),
config,
);
const resizeVisualizer = (width: number, height: number) => {
resizeCanvas();
visualizer.resize(width, height);
};
resizeVisualizer(canvas.width, canvas.height);
const visualizerContainerObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
resizeVisualizer(
entry.contentRect.width,
entry.contentRect.height,
);
}
});
visualizerContainerObserver.observe(visualizerContainer);
visualizer.render();
}, },
{ passive: true }, { passive: true },
); );

View File

@ -5,54 +5,49 @@ import { Visualizer } from './visualizer';
import type { VisualizerPluginConfig } from '../index'; import type { VisualizerPluginConfig } from '../index';
class ButterchurnVisualizer extends Visualizer<Butterchurn> { class ButterchurnVisualizer extends Visualizer {
name = 'butterchurn'; private readonly visualizer: ReturnType<typeof Butterchurn.createVisualizer>;
private destroyed: boolean = false;
visualizer: ReturnType<typeof Butterchurn.createVisualizer>; private animFrameHandle: number | null;
private readonly renderingFrequencyInMs: number;
constructor( constructor(
audioContext: AudioContext, audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode, audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement, canvas: HTMLCanvasElement,
audioNode: GainNode, audioNode: GainNode,
stream: MediaStream, _stream: MediaStream,
options: VisualizerPluginConfig, config: VisualizerPluginConfig,
) { ) {
super( super(audioSource, audioNode);
audioContext,
audioSource, const preset = ButterchurnPresets[config.butterchurn.preset];
visualizerContainer, const renderVisualizer = () => {
canvas, if (this.destroyed) return;
audioNode, this.visualizer.render();
stream, this.animFrameHandle = requestAnimationFrame(renderVisualizer);
options, };
);
this.visualizer = Butterchurn.createVisualizer(audioContext, canvas, { this.visualizer = Butterchurn.createVisualizer(audioContext, canvas, {
width: canvas.width, width: canvas.width,
height: canvas.height, height: canvas.height,
}); });
this.visualizer.loadPreset(preset, config.butterchurn.blendTimeInSeconds);
const preset = ButterchurnPresets[options.butterchurn.preset];
this.visualizer.loadPreset(preset, options.butterchurn.blendTimeInSeconds);
this.visualizer.connectAudio(audioNode); this.visualizer.connectAudio(audioNode);
this.renderingFrequencyInMs = options.butterchurn.renderingFrequencyInMs; // Start animation request loop. Do not use setInterval!
this.animFrameHandle = requestAnimationFrame(renderVisualizer);
} }
resize(width: number, height: number) { resize(width: number, height: number) {
this.visualizer.setRendererSize(width, height); this.visualizer.setRendererSize(width, height);
} }
render() { destroy() {
const renderVisualizer = () => { if (this.animFrameHandle) cancelAnimationFrame(this.animFrameHandle);
requestAnimationFrame(renderVisualizer); this.destroyed = true;
this.visualizer.render(); try {
}; this.audioSource.disconnect(this.audioNode);
setTimeout(renderVisualizer, this.renderingFrequencyInMs); } catch {}
} }
} }

View File

@ -1,22 +1,15 @@
import type { VisualizerPluginConfig } from '../index'; export abstract class Visualizer {
protected audioNode: GainNode;
export abstract class Visualizer<T> { protected audioSource: MediaElementAudioSourceNode;
/**
* The name must be the same as the file name.
*/
abstract name: string;
abstract visualizer: T;
protected constructor( protected constructor(
_audioContext: AudioContext,
_audioSource: MediaElementAudioSourceNode, _audioSource: MediaElementAudioSourceNode,
_visualizerContainer: HTMLElement,
_canvas: HTMLCanvasElement,
_audioNode: GainNode, _audioNode: GainNode,
_stream: MediaStream, ) {
_options: VisualizerPluginConfig, this.audioNode = _audioNode;
) {} this.audioSource = _audioSource;
}
abstract resize(width: number, height: number): void; abstract resize(width: number, height: number): void;
abstract render(): void; abstract destroy(): void;
} }

View File

@ -4,35 +4,24 @@ import { Visualizer } from './visualizer';
import type { VisualizerPluginConfig } from '../index'; import type { VisualizerPluginConfig } from '../index';
class VudioVisualizer extends Visualizer<Vudio> { class VudioVisualizer extends Visualizer {
name = 'vudio'; private readonly visualizer: Vudio;
visualizer: Vudio;
constructor( constructor(
audioContext: AudioContext, _audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode, audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement, canvas: HTMLCanvasElement,
audioNode: GainNode, audioNode: GainNode,
stream: MediaStream, stream: MediaStream,
options: VisualizerPluginConfig, config: VisualizerPluginConfig,
) { ) {
super( super(audioSource, audioNode);
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
);
this.visualizer = new Vudio(stream, canvas, { this.visualizer = new Vudio(stream, canvas, {
width: canvas.width, width: canvas.width,
height: canvas.height, height: canvas.height,
// Visualizer config // Visualizer config
...options, ...config,
}); });
this.visualizer.dance(); this.visualizer.dance();
@ -45,7 +34,12 @@ class VudioVisualizer extends Visualizer<Vudio> {
}); });
} }
render() {} destroy() {
this.visualizer.pause();
try {
this.audioSource.disconnect(this.audioNode);
} catch {}
}
} }
export default VudioVisualizer; export default VudioVisualizer;

View File

@ -4,35 +4,24 @@ import { Visualizer } from './visualizer';
import type { VisualizerPluginConfig } from '../index'; import type { VisualizerPluginConfig } from '../index';
class WaveVisualizer extends Visualizer<Wave> { class WaveVisualizer extends Visualizer {
name = 'wave'; private readonly visualizer: Wave;
visualizer: Wave;
constructor( constructor(
audioContext: AudioContext, audioContext: AudioContext,
audioSource: MediaElementAudioSourceNode, audioSource: MediaElementAudioSourceNode,
visualizerContainer: HTMLElement,
canvas: HTMLCanvasElement, canvas: HTMLCanvasElement,
audioNode: GainNode, audioNode: GainNode,
stream: MediaStream, _stream: MediaStream,
options: VisualizerPluginConfig, config: VisualizerPluginConfig,
) { ) {
super( super(audioSource, audioNode);
audioContext,
audioSource,
visualizerContainer,
canvas,
audioNode,
stream,
options,
);
this.visualizer = new Wave( this.visualizer = new Wave(
{ context: audioContext, source: audioSource }, { context: audioContext, source: audioSource },
canvas, canvas,
); );
for (const animation of options.wave.animations) { for (const animation of config.wave.animations) {
const TargetVisualizer = const TargetVisualizer =
this.visualizer.animations[ this.visualizer.animations[
animation.type as keyof typeof this.visualizer.animations animation.type as keyof typeof this.visualizer.animations
@ -46,7 +35,12 @@ class WaveVisualizer extends Visualizer<Wave> {
resize(_: number, __: number) {} resize(_: number, __: number) {}
render() {} destroy() {
this.visualizer.clearAnimations();
try {
this.audioSource.disconnect(this.audioNode);
} catch {}
}
} }
export default WaveVisualizer; export default WaveVisualizer;