Compare commits

...

10 Commits

16 changed files with 341 additions and 122 deletions

View File

@ -28,7 +28,7 @@ jobs:
- name: Setup NodeJS - name: Setup NodeJS
if: startsWith(matrix.os, 'macOS') != true if: startsWith(matrix.os, 'macOS') != true
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: ${{ env.NODE_VERSION }} node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm' cache: 'pnpm'

View File

@ -2,8 +2,36 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v2.1.3](https://github.com/th-ch/youtube-music/compare/v2.1.2...v2.1.3)
- fix: fixed bugs in downloader [`#1342`](https://github.com/th-ch/youtube-music/pull/1342)
- feat(discord): rename `Listen Along` to `Play on YTM` [`#1341`](https://github.com/th-ch/youtube-music/issues/1341)
- chore(deps): bump deps [`4333891`](https://github.com/th-ch/youtube-music/commit/4333891ccabe42aedf756fd48618be715db13262)
- Update changelog for v2.1.2 [`fa4c69d`](https://github.com/th-ch/youtube-music/commit/fa4c69d228d4e06a7858e2b22fcdfa075a8ca766)
- fix(store): fix listenAlong statement [`bceaa05`](https://github.com/th-ch/youtube-music/commit/bceaa05197d47a4a4bbd22e767d1e4d6ec277514)
#### [v2.1.2](https://github.com/th-ch/youtube-music/compare/v2.1.1...v2.1.2)
> 19 October 2023
- feat(in-app-menu): add an option to hide the window controls [`#1335`](https://github.com/th-ch/youtube-music/pull/1335)
- fix: fixed an issue where the album name was missing [`#1334`](https://github.com/th-ch/youtube-music/pull/1334)
- chore(deps): update dependency electron to v27.0.1 [`#1331`](https://github.com/th-ch/youtube-music/pull/1331)
- fix: fixed an issue where only the first 100 songs in a playlist were downloaded [`#1329`](https://github.com/th-ch/youtube-music/pull/1329)
- Updated readme plugins list [`#1326`](https://github.com/th-ch/youtube-music/pull/1326)
- QOL: Move source code under the src directory. [`#1318`](https://github.com/th-ch/youtube-music/pull/1318)
- feat: migrate from `npm` to `pnpm` [`#1316`](https://github.com/th-ch/youtube-music/pull/1316)
- fix: fix unresponsive (fix #1325) [`#1325`](https://github.com/th-ch/youtube-music/issues/1325)
- fix(blocker): remove the `app.isPackaged` check (fix #1315) [`#1315`](https://github.com/th-ch/youtube-music/issues/1315)
- fix(discord): `Discord RPC fails if a song's title is only one character` (fix #1314) [`#1314`](https://github.com/th-ch/youtube-music/issues/1314)
- chore(deps): Bump @rollup/plugin-commonjs, pnpm version, Remove ytpl [`9705f84`](https://github.com/th-ch/youtube-music/commit/9705f8489d7bf262bfd8b15ab84c2d3485f10eae)
- chore(deps): Bump rollup, @xhayper/discord-rpc version [`00a3e8d`](https://github.com/th-ch/youtube-music/commit/00a3e8d35ec335e1913be19f30ae09dbe0b7acdd)
- chore(deps): update dependency rollup to v4.1.4 [`6774d54`](https://github.com/th-ch/youtube-music/commit/6774d54f5eca432edc2e11743d9d1b1c2fda9ac8)
#### [v2.1.1](https://github.com/th-ch/youtube-music/compare/v2.1.0...v2.1.1) #### [v2.1.1](https://github.com/th-ch/youtube-music/compare/v2.1.0...v2.1.1)
> 14 October 2023
- hotfix(downloader): can't get an album title (fix #1313) [`#1313`](https://github.com/th-ch/youtube-music/issues/1313) - hotfix(downloader): can't get an album title (fix #1313) [`#1313`](https://github.com/th-ch/youtube-music/issues/1313)
- Update changelog for v2.1.0 [`92cab89`](https://github.com/th-ch/youtube-music/commit/92cab89d17175741e60e65ea61633e23ebdc1f45) - Update changelog for v2.1.0 [`92cab89`](https://github.com/th-ch/youtube-music/commit/92cab89d17175741e60e65ea61633e23ebdc1f45)
- Bump version to 2.1.1 [`3bb5bc2`](https://github.com/th-ch/youtube-music/commit/3bb5bc2ca1856f4e222ee1e01e865f1ab804fdba) - Bump version to 2.1.1 [`3bb5bc2`](https://github.com/th-ch/youtube-music/commit/3bb5bc2ca1856f4e222ee1e01e865f1ab804fdba)

View File

@ -1,7 +1,7 @@
{ {
"name": "youtube-music", "name": "youtube-music",
"productName": "YouTube Music", "productName": "YouTube Music",
"version": "2.1.2", "version": "2.2.0",
"description": "YouTube Music Desktop App - including custom plugins", "description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/index.js", "main": "./dist/index.js",
"license": "MIT", "license": "MIT",
@ -176,16 +176,16 @@
"@types/electron-localshortcut": "3.1.2", "@types/electron-localshortcut": "3.1.2",
"@types/howler": "2.2.10", "@types/howler": "2.2.10",
"@types/html-to-text": "9.0.3", "@types/html-to-text": "9.0.3",
"@typescript-eslint/eslint-plugin": "6.8.0", "@typescript-eslint/eslint-plugin": "6.9.0",
"auto-changelog": "2.4.0", "auto-changelog": "2.4.0",
"builtin-modules": "^3.3.0", "builtin-modules": "^3.3.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"del-cli": "5.1.0", "del-cli": "5.1.0",
"electron": "27.0.1", "electron": "27.0.2",
"electron-builder": "24.6.4", "electron-builder": "24.6.4",
"electron-devtools-installer": "3.2.0", "electron-devtools-installer": "3.2.0",
"eslint": "8.51.0", "eslint": "8.52.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.29.0",
"eslint-plugin-prettier": "5.0.1", "eslint-plugin-prettier": "5.0.1",
"node-gyp": "9.4.0", "node-gyp": "9.4.0",
"playwright": "1.39.0", "playwright": "1.39.0",

189
pnpm-lock.yaml generated
View File

@ -15,10 +15,10 @@ overrides:
dependencies: dependencies:
'@cliqz/adblocker-electron': '@cliqz/adblocker-electron':
specifier: 1.26.8 specifier: 1.26.8
version: 1.26.8(electron@27.0.1) version: 1.26.8(electron@27.0.2)
'@cliqz/adblocker-electron-preload': '@cliqz/adblocker-electron-preload':
specifier: 1.26.8 specifier: 1.26.8
version: 1.26.8(electron@27.0.1) version: 1.26.8(electron@27.0.2)
'@ffmpeg.wasm/core-mt': '@ffmpeg.wasm/core-mt':
specifier: 0.12.0 specifier: 0.12.0
version: 0.12.0 version: 0.12.0
@ -51,7 +51,7 @@ dependencies:
version: 10.2.0 version: 10.2.0
custom-electron-prompt: custom-electron-prompt:
specifier: 1.5.7 specifier: 1.5.7
version: 1.5.7(electron@27.0.1) version: 1.5.7(electron@27.0.2)
electron-debug: electron-debug:
specifier: 3.2.0 specifier: 3.2.0
version: 3.2.0 version: 3.2.0
@ -145,8 +145,8 @@ devDependencies:
specifier: 9.0.3 specifier: 9.0.3
version: 9.0.3 version: 9.0.3
'@typescript-eslint/eslint-plugin': '@typescript-eslint/eslint-plugin':
specifier: 6.8.0 specifier: 6.9.0
version: 6.8.0(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2) version: 6.9.0(@typescript-eslint/parser@6.7.5)(eslint@8.52.0)(typescript@5.2.2)
auto-changelog: auto-changelog:
specifier: 2.4.0 specifier: 2.4.0
version: 2.4.0 version: 2.4.0
@ -160,8 +160,8 @@ devDependencies:
specifier: 5.1.0 specifier: 5.1.0
version: 5.1.0 version: 5.1.0
electron: electron:
specifier: 27.0.1 specifier: 27.0.2
version: 27.0.1 version: 27.0.2
electron-builder: electron-builder:
specifier: 24.6.4 specifier: 24.6.4
version: 24.6.4 version: 24.6.4
@ -169,14 +169,14 @@ devDependencies:
specifier: 3.2.0 specifier: 3.2.0
version: 3.2.0 version: 3.2.0
eslint: eslint:
specifier: 8.51.0 specifier: 8.52.0
version: 8.51.0 version: 8.52.0
eslint-plugin-import: eslint-plugin-import:
specifier: 2.28.1 specifier: 2.29.0
version: 2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0) version: 2.29.0(@typescript-eslint/parser@6.7.5)(eslint@8.52.0)
eslint-plugin-prettier: eslint-plugin-prettier:
specifier: 5.0.1 specifier: 5.0.1
version: 5.0.1(eslint@8.51.0)(prettier@3.0.3) version: 5.0.1(eslint@8.52.0)(prettier@3.0.3)
node-gyp: node-gyp:
specifier: 9.4.0 specifier: 9.4.0
version: 9.4.0 version: 9.4.0
@ -252,23 +252,23 @@ packages:
'@cliqz/adblocker-extended-selectors': 1.26.8 '@cliqz/adblocker-extended-selectors': 1.26.8
dev: false dev: false
/@cliqz/adblocker-electron-preload@1.26.8(electron@27.0.1): /@cliqz/adblocker-electron-preload@1.26.8(electron@27.0.2):
resolution: {integrity: sha512-sWhND23IrP6f7wUtUt3+lAbNdmMYucwKVsMcMtInAk6vKz5bxpECsp+QBHXE7Z3MXLwa0dATGRVcC4RTLZBb/A==} resolution: {integrity: sha512-sWhND23IrP6f7wUtUt3+lAbNdmMYucwKVsMcMtInAk6vKz5bxpECsp+QBHXE7Z3MXLwa0dATGRVcC4RTLZBb/A==}
peerDependencies: peerDependencies:
electron: '>11' electron: '>11'
dependencies: dependencies:
'@cliqz/adblocker-content': 1.26.8 '@cliqz/adblocker-content': 1.26.8
electron: 27.0.1 electron: 27.0.2
dev: false dev: false
/@cliqz/adblocker-electron@1.26.8(electron@27.0.1): /@cliqz/adblocker-electron@1.26.8(electron@27.0.2):
resolution: {integrity: sha512-8vuqiPMCOzGPfUehfvv7eDwQRw3sm3sdR3eZYU2wNGPNbUHf6gZbSBcsx12n3QNcbAxbdydtc/a3X4Eu5VOlxg==} resolution: {integrity: sha512-8vuqiPMCOzGPfUehfvv7eDwQRw3sm3sdR3eZYU2wNGPNbUHf6gZbSBcsx12n3QNcbAxbdydtc/a3X4Eu5VOlxg==}
peerDependencies: peerDependencies:
electron: '>11' electron: '>11'
dependencies: dependencies:
'@cliqz/adblocker': 1.26.8 '@cliqz/adblocker': 1.26.8
'@cliqz/adblocker-electron-preload': 1.26.8(electron@27.0.1) '@cliqz/adblocker-electron-preload': 1.26.8(electron@27.0.2)
electron: 27.0.1 electron: 27.0.2
tldts-experimental: 6.0.16 tldts-experimental: 6.0.16
dev: false dev: false
@ -364,13 +364,13 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@eslint-community/eslint-utils@4.4.0(eslint@8.51.0): /@eslint-community/eslint-utils@4.4.0(eslint@8.52.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies: dependencies:
eslint: 8.51.0 eslint: 8.52.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
dev: true dev: true
@ -396,8 +396,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@eslint/js@8.51.0: /@eslint/js@8.52.0:
resolution: {integrity: sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==} resolution: {integrity: sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
@ -425,11 +425,11 @@ packages:
resolution: {integrity: sha512-FEyg37hDvQtrQVlFxbit7ov5e487BjsR32bZfJ4oAb5i+NnlbGaNyy6iYBZ8ocVHo8fgug+SL+mFdDTzqjvPww==} resolution: {integrity: sha512-FEyg37hDvQtrQVlFxbit7ov5e487BjsR32bZfJ4oAb5i+NnlbGaNyy6iYBZ8ocVHo8fgug+SL+mFdDTzqjvPww==}
dev: false dev: false
/@humanwhocodes/config-array@0.11.11: /@humanwhocodes/config-array@0.11.13:
resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
engines: {node: '>=10.10.0'} engines: {node: '>=10.10.0'}
dependencies: dependencies:
'@humanwhocodes/object-schema': 1.2.1 '@humanwhocodes/object-schema': 2.0.1
debug: 4.3.4 debug: 4.3.4
minimatch: 3.1.2 minimatch: 3.1.2
transitivePeerDependencies: transitivePeerDependencies:
@ -441,8 +441,8 @@ packages:
engines: {node: '>=12.22'} engines: {node: '>=12.22'}
dev: true dev: true
/@humanwhocodes/object-schema@1.2.1: /@humanwhocodes/object-schema@2.0.1:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: true dev: true
/@isaacs/cliui@8.0.2: /@isaacs/cliui@8.0.2:
@ -912,7 +912,7 @@ packages:
/@types/electron-localshortcut@3.1.2: /@types/electron-localshortcut@3.1.2:
resolution: {integrity: sha512-eWnTxzZHtYLL7PZuWP/hizUyX6VVjI5eUa5lzyA0gCDeLqHbgyccD8JsJ1Ew+vtjY2XUA8y05hwS6XOf3kIOCw==} resolution: {integrity: sha512-eWnTxzZHtYLL7PZuWP/hizUyX6VVjI5eUa5lzyA0gCDeLqHbgyccD8JsJ1Ew+vtjY2XUA8y05hwS6XOf3kIOCw==}
dependencies: dependencies:
electron: 27.0.1 electron: 27.0.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -1041,8 +1041,8 @@ packages:
'@types/node': 20.8.6 '@types/node': 20.8.6
optional: true optional: true
/@typescript-eslint/eslint-plugin@6.8.0(@typescript-eslint/parser@6.7.5)(eslint@8.51.0)(typescript@5.2.2): /@typescript-eslint/eslint-plugin@6.9.0(@typescript-eslint/parser@6.7.5)(eslint@8.52.0)(typescript@5.2.2):
resolution: {integrity: sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==} resolution: {integrity: sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
@ -1053,13 +1053,13 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@eslint-community/regexpp': 4.9.1 '@eslint-community/regexpp': 4.9.1
'@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.7.5(eslint@8.52.0)(typescript@5.2.2)
'@typescript-eslint/scope-manager': 6.8.0 '@typescript-eslint/scope-manager': 6.9.0
'@typescript-eslint/type-utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/type-utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
'@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.8.0 '@typescript-eslint/visitor-keys': 6.9.0
debug: 4.3.4 debug: 4.3.4
eslint: 8.51.0 eslint: 8.52.0
graphemer: 1.4.0 graphemer: 1.4.0
ignore: 5.2.4 ignore: 5.2.4
natural-compare: 1.4.0 natural-compare: 1.4.0
@ -1070,7 +1070,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/parser@6.7.5(eslint@8.51.0)(typescript@5.2.2): /@typescript-eslint/parser@6.7.5(eslint@8.52.0)(typescript@5.2.2):
resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==} resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
@ -1085,7 +1085,7 @@ packages:
'@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.7.5(typescript@5.2.2)
'@typescript-eslint/visitor-keys': 6.7.5 '@typescript-eslint/visitor-keys': 6.7.5
debug: 4.3.4 debug: 4.3.4
eslint: 8.51.0 eslint: 8.52.0
typescript: 5.2.2 typescript: 5.2.2
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -1099,16 +1099,16 @@ packages:
'@typescript-eslint/visitor-keys': 6.7.5 '@typescript-eslint/visitor-keys': 6.7.5
dev: true dev: true
/@typescript-eslint/scope-manager@6.8.0: /@typescript-eslint/scope-manager@6.9.0:
resolution: {integrity: sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==} resolution: {integrity: sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
dependencies: dependencies:
'@typescript-eslint/types': 6.8.0 '@typescript-eslint/types': 6.9.0
'@typescript-eslint/visitor-keys': 6.8.0 '@typescript-eslint/visitor-keys': 6.9.0
dev: true dev: true
/@typescript-eslint/type-utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): /@typescript-eslint/type-utils@6.9.0(eslint@8.52.0)(typescript@5.2.2):
resolution: {integrity: sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==} resolution: {integrity: sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
@ -1117,10 +1117,10 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.9.0(typescript@5.2.2)
'@typescript-eslint/utils': 6.8.0(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/utils': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
debug: 4.3.4 debug: 4.3.4
eslint: 8.51.0 eslint: 8.52.0
ts-api-utils: 1.0.3(typescript@5.2.2) ts-api-utils: 1.0.3(typescript@5.2.2)
typescript: 5.2.2 typescript: 5.2.2
transitivePeerDependencies: transitivePeerDependencies:
@ -1132,8 +1132,8 @@ packages:
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
dev: true dev: true
/@typescript-eslint/types@6.8.0: /@typescript-eslint/types@6.9.0:
resolution: {integrity: sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==} resolution: {integrity: sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
dev: true dev: true
@ -1158,8 +1158,8 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/typescript-estree@6.8.0(typescript@5.2.2): /@typescript-eslint/typescript-estree@6.9.0(typescript@5.2.2):
resolution: {integrity: sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==} resolution: {integrity: sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@ -1167,8 +1167,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/types': 6.8.0 '@typescript-eslint/types': 6.9.0
'@typescript-eslint/visitor-keys': 6.8.0 '@typescript-eslint/visitor-keys': 6.9.0
debug: 4.3.4 debug: 4.3.4
globby: 11.1.0 globby: 11.1.0
is-glob: 4.0.3 is-glob: 4.0.3
@ -1179,19 +1179,19 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils@6.8.0(eslint@8.51.0)(typescript@5.2.2): /@typescript-eslint/utils@6.9.0(eslint@8.52.0)(typescript@5.2.2):
resolution: {integrity: sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==} resolution: {integrity: sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies: peerDependencies:
eslint: ^7.0.0 || ^8.0.0 eslint: ^7.0.0 || ^8.0.0
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0)
'@types/json-schema': 7.0.13 '@types/json-schema': 7.0.13
'@types/semver': 7.5.3 '@types/semver': 7.5.3
'@typescript-eslint/scope-manager': 6.8.0 '@typescript-eslint/scope-manager': 6.9.0
'@typescript-eslint/types': 6.8.0 '@typescript-eslint/types': 6.9.0
'@typescript-eslint/typescript-estree': 6.8.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': 6.9.0(typescript@5.2.2)
eslint: 8.51.0 eslint: 8.52.0
semver: 7.5.4 semver: 7.5.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -1206,14 +1206,18 @@ packages:
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
dev: true dev: true
/@typescript-eslint/visitor-keys@6.8.0: /@typescript-eslint/visitor-keys@6.9.0:
resolution: {integrity: sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==} resolution: {integrity: sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==}
engines: {node: ^16.0.0 || >=18.0.0} engines: {node: ^16.0.0 || >=18.0.0}
dependencies: dependencies:
'@typescript-eslint/types': 6.8.0 '@typescript-eslint/types': 6.9.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
dev: true dev: true
/@ungap/structured-clone@1.2.0:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
dev: true
/@xhayper/discord-rpc@1.0.24: /@xhayper/discord-rpc@1.0.24:
resolution: {integrity: sha512-gzC8OaOSz7cGALSHyyq6nANQvBfyfntbSq+Qh+cNanoKX8ybOj+jWKmDP6PbLVDWoBftTU3JYsWXrLml2df2Hw==} resolution: {integrity: sha512-gzC8OaOSz7cGALSHyyq6nANQvBfyfntbSq+Qh+cNanoKX8ybOj+jWKmDP6PbLVDWoBftTU3JYsWXrLml2df2Hw==}
engines: {node: '>=14.18.0'} engines: {node: '>=14.18.0'}
@ -1929,12 +1933,12 @@ packages:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
/custom-electron-prompt@1.5.7(electron@27.0.1): /custom-electron-prompt@1.5.7(electron@27.0.2):
resolution: {integrity: sha512-ptRPJr6CpT06GWLMtg3GD2Lr7gWfXdWI+hR1S39eq+m/mUa2E118YmX6mPCbHdg5QB/W9UVhSpRqBM8FUh1G8w==} resolution: {integrity: sha512-ptRPJr6CpT06GWLMtg3GD2Lr7gWfXdWI+hR1S39eq+m/mUa2E118YmX6mPCbHdg5QB/W9UVhSpRqBM8FUh1G8w==}
peerDependencies: peerDependencies:
electron: '>=10.0.0' electron: '>=10.0.0'
dependencies: dependencies:
electron: 27.0.1 electron: 27.0.2
dev: false dev: false
/dashdash@2.0.0: /dashdash@2.0.0:
@ -2372,8 +2376,8 @@ packages:
- supports-color - supports-color
dev: false dev: false
/electron@27.0.1: /electron@27.0.2:
resolution: {integrity: sha512-AjDGgpf2thNxVXoNqEG+0GCUK4upAEa2B+IoM5Yk9YrOLd6uUOEMfGI9rhPtj+jC14iKOvBdefY2uAzcDC0qng==} resolution: {integrity: sha512-4fbcHQ40ZDlqhr5Pamm+M5BF7ry2lGqjFTWTJ/mrBwuiPWu6xhV/RWgUhKBaLqKNfAaNl3eMxV3Jc82gv6JauQ==}
engines: {node: '>= 12.20.55'} engines: {node: '>= 12.20.55'}
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true
@ -2536,13 +2540,13 @@ packages:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
dependencies: dependencies:
debug: 3.2.7 debug: 3.2.7
is-core-module: 2.13.0 is-core-module: 2.13.1
resolve: 1.22.8 resolve: 1.22.8
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.51.0): /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0):
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
engines: {node: '>=4'} engines: {node: '>=4'}
peerDependencies: peerDependencies:
@ -2563,16 +2567,16 @@ packages:
eslint-import-resolver-webpack: eslint-import-resolver-webpack:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.7.5(eslint@8.52.0)(typescript@5.2.2)
debug: 3.2.7 debug: 3.2.7
eslint: 8.51.0 eslint: 8.52.0
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint@8.51.0): /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.7.5)(eslint@8.52.0):
resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==} resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==}
engines: {node: '>=4'} engines: {node: '>=4'}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': '*' '@typescript-eslint/parser': '*'
@ -2581,18 +2585,18 @@ packages:
'@typescript-eslint/parser': '@typescript-eslint/parser':
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 6.7.5(eslint@8.51.0)(typescript@5.2.2) '@typescript-eslint/parser': 6.7.5(eslint@8.52.0)(typescript@5.2.2)
array-includes: 3.1.7 array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3 array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2 array.prototype.flat: 1.3.2
array.prototype.flatmap: 1.3.2 array.prototype.flatmap: 1.3.2
debug: 3.2.7 debug: 3.2.7
doctrine: 2.1.0 doctrine: 2.1.0
eslint: 8.51.0 eslint: 8.52.0
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.51.0) eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0)
has: 1.0.4 hasown: 2.0.0
is-core-module: 2.13.0 is-core-module: 2.13.1
is-glob: 4.0.3 is-glob: 4.0.3
minimatch: 3.1.2 minimatch: 3.1.2
object.fromentries: 2.0.7 object.fromentries: 2.0.7
@ -2606,7 +2610,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/eslint-plugin-prettier@5.0.1(eslint@8.51.0)(prettier@3.0.3): /eslint-plugin-prettier@5.0.1(eslint@8.52.0)(prettier@3.0.3):
resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -2620,7 +2624,7 @@ packages:
eslint-config-prettier: eslint-config-prettier:
optional: true optional: true
dependencies: dependencies:
eslint: 8.51.0 eslint: 8.52.0
prettier: 3.0.3 prettier: 3.0.3
prettier-linter-helpers: 1.0.0 prettier-linter-helpers: 1.0.0
synckit: 0.8.5 synckit: 0.8.5
@ -2639,18 +2643,19 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/eslint@8.51.0: /eslint@8.52.0:
resolution: {integrity: sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==} resolution: {integrity: sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true hasBin: true
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.51.0) '@eslint-community/eslint-utils': 4.4.0(eslint@8.52.0)
'@eslint-community/regexpp': 4.9.1 '@eslint-community/regexpp': 4.9.1
'@eslint/eslintrc': 2.1.2 '@eslint/eslintrc': 2.1.2
'@eslint/js': 8.51.0 '@eslint/js': 8.52.0
'@humanwhocodes/config-array': 0.11.11 '@humanwhocodes/config-array': 0.11.13
'@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8 '@nodelib/fs.walk': 1.2.8
'@ungap/structured-clone': 1.2.0
ajv: 6.12.6 ajv: 6.12.6
chalk: 4.1.2 chalk: 4.1.2
cross-spawn: 7.0.3 cross-spawn: 7.0.3
@ -3255,6 +3260,13 @@ packages:
resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==}
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}
/hasown@2.0.0:
resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
engines: {node: '>= 0.4'}
dependencies:
function-bind: 1.1.2
dev: true
/hexy@0.2.11: /hexy@0.2.11:
resolution: {integrity: sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==} resolution: {integrity: sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==}
hasBin: true hasBin: true
@ -3470,6 +3482,12 @@ packages:
has: 1.0.4 has: 1.0.4
dev: true dev: true
/is-core-module@2.13.1:
resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
dependencies:
hasown: 2.0.0
dev: true
/is-date-object@1.0.5: /is-date-object@1.0.5:
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -4656,7 +4674,7 @@ packages:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true hasBin: true
dependencies: dependencies:
is-core-module: 2.13.0 is-core-module: 2.13.1
path-parse: 1.0.7 path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0 supports-preserve-symlinks-flag: 1.0.0
dev: true dev: true
@ -5346,6 +5364,7 @@ packages:
/undici-types@5.25.3: /undici-types@5.25.3:
resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==} resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==}
requiresBuild: true
/undici@5.26.3: /undici@5.26.3:
resolution: {integrity: sha512-H7n2zmKEWgOllKkIUkLvFmsJQj062lSm3uA4EYApG8gLuiOM0/go9bIoC3HVaSnfg4xunowDE2i9p8drkXuvDw==} resolution: {integrity: sha512-H7n2zmKEWgOllKkIUkLvFmsJQj062lSm3uA4EYApG8gLuiOM0/go9bIoC3HVaSnfg4xunowDE2i9p8drkXuvDw==}

View File

@ -81,7 +81,16 @@ const defaultConfig = {
disableDefaultLists: false, disableDefaultLists: false,
}, },
'album-color-theme': {}, 'album-color-theme': {},
'ambient-mode': {}, 'ambient-mode': {
enabled: false,
quality: 50,
buffer: 30,
interpolationTime: 1500,
blur: 100,
size: 100,
opacity: 1,
fullscreen: false,
},
'audio-compressor': {}, 'audio-compressor': {},
'blur-nav-bar': {}, 'blur-nav-bar': {},
'bypass-age-restrictions': {}, 'bypass-age-restrictions': {},
@ -107,7 +116,7 @@ const defaultConfig = {
autoReconnect: true, // If enabled, will try to reconnect to discord every 5 seconds after disconnecting or failing to connect autoReconnect: true, // If enabled, will try to reconnect to discord every 5 seconds after disconnecting or failing to connect
activityTimoutEnabled: true, // If enabled, the discord rich presence gets cleared when music paused after the time specified below activityTimoutEnabled: true, // If enabled, the discord rich presence gets cleared when music paused after the time specified below
activityTimoutTime: 10 * 60 * 1000, // 10 minutes activityTimoutTime: 10 * 60 * 1000, // 10 minutes
listenAlong: true, // Add a "listen along" button to rich presence playOnYouTubeMusic: true, // Add a "Play on YouTube Music" button to rich presence
hideGitHubButton: false, // Disable the "View App On GitHub" button hideGitHubButton: false, // Disable the "View App On GitHub" button
hideDurationLeft: false, // Hides the start and end time of the song to rich presence hideDurationLeft: false, // Hides the start and end time of the song to rich presence
}, },

View File

@ -22,8 +22,20 @@ export function isEnabled(plugin: string) {
return pluginConfig !== undefined && pluginConfig.enabled; return pluginConfig !== undefined && pluginConfig.enabled;
} }
export function setOptions<T>(plugin: string, options: T) { /**
* Set options for a plugin
* @param plugin Plugin name
* @param options Options to set
* @param exclude Options to exclude from the options object
*/
export function setOptions<T>(plugin: string, options: T, exclude: string[] = ['enabled']) {
const plugins = store.get('plugins') as Record<string, T>; const plugins = store.get('plugins') as Record<string, T>;
// HACK: This is a workaround for preventing changed options from being overwritten
exclude.forEach((key) => {
if (Object.prototype.hasOwnProperty.call(options, key)) {
delete options[key as keyof T];
}
});
store.set('plugins', { store.set('plugins', {
...plugins, ...plugins,
[plugin]: { [plugin]: {
@ -33,8 +45,8 @@ export function setOptions<T>(plugin: string, options: T) {
}); });
} }
export function setMenuOptions<T>(plugin: string, options: T) { export function setMenuOptions<T>(plugin: string, options: T, exclude: string[] = ['enabled']) {
setOptions(plugin, options); setOptions(plugin, options, exclude);
if (store.get('options.restartOnConfigChanges')) { if (store.get('options.restartOnConfigChanges')) {
restart(); restart();
} }
@ -45,11 +57,11 @@ export function getOptions<T>(plugin: string): T {
} }
export function enable(plugin: string) { export function enable(plugin: string) {
setMenuOptions(plugin, { enabled: true }); setMenuOptions(plugin, { enabled: true }, []);
} }
export function disable(plugin: string) { export function disable(plugin: string) {
setMenuOptions(plugin, { enabled: false }); setMenuOptions(plugin, { enabled: false }, []);
} }
export default { export default {

View File

@ -20,6 +20,13 @@ const setDefaultPluginOptions = (store: Conf<Record<string, unknown>>, plugin: k
}; };
const migrations = { const migrations = {
'>=2.1.3'(store: Conf<Record<string, unknown>>) {
const listenAlong = store.get('plugins.discord.listenAlong');
if (listenAlong !== undefined) {
store.set('plugins.discord.playOnYouTubeMusic', listenAlong);
store.delete('plugins.discord.listenAlong');
}
},
'>=2.1.0'(store: Conf<Record<string, unknown>>) { '>=2.1.0'(store: Conf<Record<string, unknown>>) {
const originalPreset = store.get('plugins.downloader.preset') as string | undefined; const originalPreset = store.get('plugins.downloader.preset') as string | undefined;
if (originalPreset) { if (originalPreset) {

View File

@ -8,6 +8,7 @@ import { startingPages } from './providers/extracted-data';
import promptOptions from './providers/prompt-options'; import promptOptions from './providers/prompt-options';
import adblockerMenu from './plugins/adblocker/menu'; import adblockerMenu from './plugins/adblocker/menu';
import ambientModeMenu from './plugins/ambient-mode/menu';
import captionsSelectorMenu from './plugins/captions-selector/menu'; import captionsSelectorMenu from './plugins/captions-selector/menu';
import crossfadeMenu from './plugins/crossfade/menu'; import crossfadeMenu from './plugins/crossfade/menu';
import disableAutoplayMenu from './plugins/disable-autoplay/menu'; import disableAutoplayMenu from './plugins/disable-autoplay/menu';
@ -32,6 +33,7 @@ const betaPlugins = ['crossfade', 'lumiastream'];
const pluginMenus = { const pluginMenus = {
'adblocker': adblockerMenu, 'adblocker': adblockerMenu,
'ambient-mode': ambientModeMenu,
'disable-autoplay': disableAutoplayMenu, 'disable-autoplay': disableAutoplayMenu,
'captions-selector': captionsSelectorMenu, 'captions-selector': captionsSelectorMenu,
'crossfade': crossfadeMenu, 'crossfade': crossfadeMenu,

View File

@ -1,10 +1,14 @@
import { BrowserWindow } from 'electron'; import { BrowserWindow } from 'electron';
import config from './config';
import style from './style.css'; import style from './style.css';
import { injectCSS } from '../utils'; import { injectCSS } from '../utils';
export default (win: BrowserWindow) => {
config.subscribeAll((newConfig) => {
win.webContents.send('ambient-mode:config-change', newConfig);
});
export default (win: BrowserWindow) => {
injectCSS(win.webContents, style); injectCSS(win.webContents, style);
}; };

View File

@ -0,0 +1,4 @@
import { PluginConfig } from '../../config/dynamic';
const config = new PluginConfig('ambient-mode');
export default config;

View File

@ -1,9 +1,15 @@
import { ipcRenderer } from 'electron';
import { ConfigType } from '../../config/dynamic'; import { ConfigType } from '../../config/dynamic';
export default (_: ConfigType<'ambient-mode'>) => { export default (config: ConfigType<'ambient-mode'>) => {
const interpolationTime = 3000; // interpolation time (ms) let interpolationTime = config.interpolationTime; // interpolation time (ms)
const framerate = 30; // frame let buffer = config.buffer; // frame
const qualityRatio = 50; // width size (pixel) let qualityRatio = config.quality; // width size (pixel)
let sizeRatio = config.size / 100; // size ratio (percent)
let blur = config.blur; // blur (pixel)
let opacity = config.opacity; // opacity (percent)
let isFullscreen = config.fullscreen; // fullscreen (boolean)
let unregister: (() => void) | null = null; let unregister: (() => void) | null = null;
@ -37,7 +43,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
context.globalAlpha = 1; context.globalAlpha = 1;
if (lastImageData) { if (lastImageData) {
const frameOffset = (1 / framerate) * (1000 / interpolationTime); const frameOffset = (1 / buffer) * (1000 / interpolationTime);
context.globalAlpha = 1 - (frameOffset * 2); // because of alpha value must be < 1 context.globalAlpha = 1 - (frameOffset * 2); // because of alpha value must be < 1
context.putImageData(lastImageData, 0, 0); context.putImageData(lastImageData, 0, 0);
context.globalAlpha = frameOffset; context.globalAlpha = frameOffset;
@ -61,8 +67,18 @@ export default (_: ConfigType<'ambient-mode'>) => {
blurCanvas.width = qualityRatio; blurCanvas.width = qualityRatio;
blurCanvas.height = Math.floor(newHeight / newWidth * qualityRatio); blurCanvas.height = Math.floor(newHeight / newWidth * qualityRatio);
blurCanvas.style.width = `${newWidth}px`; blurCanvas.style.width = `${newWidth * sizeRatio}px`;
blurCanvas.style.height = `${newHeight}px`; blurCanvas.style.height = `${newHeight * sizeRatio}px`;
if (isFullscreen) blurCanvas.classList.add('fullscreen');
else blurCanvas.classList.remove('fullscreen');
const leftOffset = newWidth * (sizeRatio - 1) / 2;
const topOffset = newHeight * (sizeRatio - 1) / 2;
blurCanvas.style.setProperty('--left', `${-1 * leftOffset}px`);
blurCanvas.style.setProperty('--top', `${-1 * topOffset}px`);
blurCanvas.style.setProperty('--blur', `${blur}px`);
blurCanvas.style.setProperty('--opacity', `${opacity}`);
}; };
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
@ -75,10 +91,22 @@ export default (_: ConfigType<'ambient-mode'>) => {
const resizeObserver = new ResizeObserver(() => { const resizeObserver = new ResizeObserver(() => {
applyVideoAttributes(); applyVideoAttributes();
}); });
const onConfigSync = (_: Electron.IpcRendererEvent, newConfig: ConfigType<'ambient-mode'>) => {
if (typeof newConfig.interpolationTime === 'number') interpolationTime = newConfig.interpolationTime;
if (typeof newConfig.buffer === 'number') buffer = newConfig.buffer;
if (typeof newConfig.quality === 'number') qualityRatio = newConfig.quality;
if (typeof newConfig.size === 'number') sizeRatio = newConfig.size / 100;
if (typeof newConfig.blur === 'number') blur = newConfig.blur;
if (typeof newConfig.opacity === 'number') opacity = newConfig.opacity;
if (typeof newConfig.fullscreen === 'boolean') isFullscreen = newConfig.fullscreen;
applyVideoAttributes();
};
ipcRenderer.on('ambient-mode:config-change', onConfigSync);
/* hooking */ /* hooking */
let canvasInterval: NodeJS.Timeout | null = null; let canvasInterval: NodeJS.Timeout | null = null;
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / framerate))); canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / buffer)));
applyVideoAttributes(); applyVideoAttributes();
observer.observe(songVideo, { attributes: true }); observer.observe(songVideo, { attributes: true });
resizeObserver.observe(songVideo); resizeObserver.observe(songVideo);
@ -90,7 +118,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
}; };
const onPlay = () => { const onPlay = () => {
if (canvasInterval) clearInterval(canvasInterval); if (canvasInterval) clearInterval(canvasInterval);
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / framerate))); canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / buffer)));
}; };
songVideo.addEventListener('pause', onPause); songVideo.addEventListener('pause', onPause);
songVideo.addEventListener('play', onPlay); songVideo.addEventListener('play', onPlay);
@ -107,6 +135,7 @@ export default (_: ConfigType<'ambient-mode'>) => {
observer.disconnect(); observer.disconnect();
resizeObserver.disconnect(); resizeObserver.disconnect();
ipcRenderer.off('ambient-mode:config-change', onConfigSync);
window.removeEventListener('resize', applyVideoAttributes); window.removeEventListener('resize', applyVideoAttributes);
wrapper.removeChild(blurCanvas); wrapper.removeChild(blurCanvas);

View File

@ -0,0 +1,87 @@
import config from './config';
import { MenuTemplate } from '../../menu';
const interpolationTimeList = [0, 500, 1000, 1500, 2000, 3000, 4000, 5000];
const qualityList = [10, 25, 50, 100, 200, 500, 1000];
const sizeList = [100, 110, 125, 150, 175, 200, 300];
const bufferList = [1, 5, 10, 20, 30];
const blurAmountList = [0, 5, 10, 25, 50, 100, 150, 200, 500];
const opacityList = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
export default (): MenuTemplate => [
{
label: 'Smoothness transition',
submenu: interpolationTimeList.map((interpolationTime) => ({
label: `During ${interpolationTime / 1000}s`,
type: 'radio',
checked: config.get('interpolationTime') === interpolationTime,
click() {
config.set('interpolationTime', interpolationTime);
},
})),
},
{
label: 'Quality',
submenu: qualityList.map((quality) => ({
label: `${quality} pixels`,
type: 'radio',
checked: config.get('quality') === quality,
click() {
config.set('quality', quality);
},
})),
},
{
label: 'Size',
submenu: sizeList.map((size) => ({
label: `${size}%`,
type: 'radio',
checked: config.get('size') === size,
click() {
config.set('size', size);
},
})),
},
{
label: 'Buffer',
submenu: bufferList.map((buffer) => ({
label: `${buffer}`,
type: 'radio',
checked: config.get('buffer') === buffer,
click() {
config.set('buffer', buffer);
},
})),
},
{
label: 'Opacity',
submenu: opacityList.map((opacity) => ({
label: `${opacity * 100}%`,
type: 'radio',
checked: config.get('opacity') === opacity,
click() {
config.set('opacity', opacity);
},
})),
},
{
label: 'Blur amount',
submenu: blurAmountList.map((blur) => ({
label: `${blur} pixels`,
type: 'radio',
checked: config.get('blur') === blur,
click() {
config.set('blur', blur);
},
})),
},
{
label: 'Using fullscreen',
type: 'checkbox',
checked: config.get('fullscreen'),
click(item) {
config.set('fullscreen', item.checked);
},
},
];

View File

@ -1,7 +1,26 @@
#song-video canvas.html5-blur-canvas{ #song-video canvas.html5-blur-canvas {
position: absolute; filter: blur(var(--blur, 100px));
left: 0; opacity: var(--opacity, 1);
top: 0;
filter: blur(100px); pointer-events: none;
}
#song-video canvas.html5-blur-canvas:not(.fullscreen) {
position: absolute;
left: var(--left, 0px);
top: var(--top, 0px);
}
#song-video canvas.html5-blur-canvas.fullscreen {
position: fixed;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
}
#song-video .html5-video-container > video {
top: 0 !important;
} }

View File

@ -170,7 +170,7 @@ export default (
largeImageKey: songInfo.imageSrc ?? '', largeImageKey: songInfo.imageSrc ?? '',
largeImageText: songInfo.album ?? '', largeImageText: songInfo.album ?? '',
buttons: [ buttons: [
...(options.listenAlong ? [{ label: 'Listen Along', url: songInfo.url ?? '' }] : []), ...(options.playOnYouTubeMusic ? [{ label: 'Play on YouTube Music', url: songInfo.url ?? '' }] : []),
...(options.hideGitHubButton ? [] : [{ label: 'View App On GitHub', url: 'https://github.com/th-ch/youtube-music' }]), ...(options.hideGitHubButton ? [] : [{ label: 'View App On GitHub', url: 'https://github.com/th-ch/youtube-music' }]),
], ],
}; };

View File

@ -47,11 +47,11 @@ export default (win: Electron.BrowserWindow, options: DiscordOptions, refreshMen
}, },
}, },
{ {
label: 'Listen Along', label: 'Play on YouTube Music',
type: 'checkbox', type: 'checkbox',
checked: options.listenAlong, checked: options.playOnYouTubeMusic,
click(item: Electron.MenuItem) { click(item: Electron.MenuItem) {
options.listenAlong = item.checked; options.playOnYouTubeMusic = item.checked;
setMenuOptions('discord', options); setMenuOptions('discord', options);
}, },
}, },

View File

@ -84,8 +84,8 @@ export const getCookieFromWindow = async (win: BrowserWindow) => {
url: 'https://music.youtube.com', url: 'https://music.youtube.com',
}) })
) )
.map((it) => it.name + '=' + it.value + ';') .map((it) => it.name + '=' + it.value)
.join(''); .join(';');
}; };
export default async (win_: BrowserWindow) => { export default async (win_: BrowserWindow) => {
@ -450,12 +450,11 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
try { try {
givenUrl = new URL(givenUrl ?? ''); givenUrl = new URL(givenUrl ?? '');
} catch { } catch {
return; givenUrl = new URL(win.webContents.getURL());
} }
const playlistId = const playlistId =
getPlaylistID(givenUrl) || getPlaylistID(givenUrl) ||
getPlaylistID(new URL(win.webContents.getURL())) ||
getPlaylistID(new URL(playingUrl)); getPlaylistID(new URL(playingUrl));
if (!playlistId) { if (!playlistId) {
@ -604,7 +603,7 @@ function getFFmpegMetadataArgs(metadata: CustomSongInfo) {
// Playlist radio modifier needs to be cut from playlist ID // Playlist radio modifier needs to be cut from playlist ID
const INVALID_PLAYLIST_MODIFIER = 'RDAMPL'; const INVALID_PLAYLIST_MODIFIER = 'RDAMPL';
const getPlaylistID = (aURL: URL) => { const getPlaylistID = (aURL?: URL): string | null | undefined => {
const result = const result =
aURL?.searchParams.get('list') || aURL?.searchParams.get('playlist'); aURL?.searchParams.get('list') || aURL?.searchParams.get('playlist');
if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) { if (result?.startsWith(INVALID_PLAYLIST_MODIFIER)) {