Compare commits

...

34 Commits

Author SHA1 Message Date
4e66b0cedd fix: remove snap arm 2024-10-14 22:23:37 +09:00
11fe54d640 fix(style): fix youtube music player layout not aligned issue 2024-10-14 22:01:26 +09:00
446529f738 fix: remove pacman 2024-10-14 21:59:56 +09:00
ac6e9deeb9 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (397 of 397 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-10-14 14:42:58 +02:00
100873163f fix: remove "compression": "maximum" 2024-10-14 21:34:33 +09:00
e141e18bac fix: fix build 2024-10-14 21:27:42 +09:00
f4da0c2c95 fix: enum value must be one of xz,lzo, got 'maximum' 2024-10-14 21:17:15 +09:00
7507bce3cc fix: fix org.electronjs.Electron2.BaseApp/x86_64/20.08 2024-10-14 21:03:10 +09:00
2b970fade8 fix: fix org.freedesktop.Sdk/x86_64/20.08 2024-10-14 20:51:36 +09:00
35f0e43082 fix: remove duplicate flatpak 2024-10-14 20:38:25 +09:00
ae4410a613 fix(flatpak): remove armhf/arm64 2024-10-14 20:32:05 +09:00
5534174016 fix: fix flatpak build 2024-10-14 20:27:33 +09:00
15cf6c77c3 fix: fix flatpak release 2024-10-14 20:12:54 +09:00
18a8fc462d fix: fix pnpm-lock 2024-10-14 20:01:02 +09:00
d3acb4945a chore(flatpak-builder): Add more details when failing 2024-10-14 19:57:41 +09:00
32d3c58b44 fix: fix release workflow 2024-10-14 19:33:37 +09:00
bd8c2eb390 fix: configuration has an unknown property 'AppImage' 2024-10-14 19:26:24 +09:00
a81fa9c0d1 fix: apt update 2024-10-14 19:22:02 +09:00
1d0f7d7a48 fix: fix release 2024-10-14 19:20:04 +09:00
b6687307df Bump version to 3.6.1 2024-10-14 19:16:25 +09:00
7e07a44f68 fix(downloader): fix #2371 2024-10-14 18:27:04 +09:00
5ca66530ee fix(ytm-bugs): incorrect video ratio
- Close #2459
2024-10-14 18:16:22 +09:00
95acbe2b65 fix: fix conflict with adguard 2024-10-14 18:06:08 +09:00
534aeb163a fix(api-server): fix init/authentication error
- Close #2497
2024-10-14 17:51:59 +09:00
6abcbee290 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (397 of 397 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-10-14 09:54:33 +02:00
4457a043a4 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (397 of 397 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-10-14 09:54:05 +02:00
410a052fea chore(i18n): Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (397 of 397 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt_BR/
2024-10-14 09:51:36 +02:00
e4287085a1 chore(i18n): Translated using Weblate (Filipino)
Currently translated at 87.1% (346 of 397 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fil/
2024-10-14 09:51:36 +02:00
b6cefef8fb fix(api-server): Various fixes and improvements (#2496) 2024-10-14 16:48:11 +09:00
9d7e2a06bc fix(deps): update dependency electron-debug to v4.1.0 (#2499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 16:45:19 +09:00
d516fc2153 fix(renderer): fix force like buttons display logic (#2493) 2024-10-14 04:27:23 +09:00
77bfe8e218 fix: RSS feed CORS issue
- Close #1620
2024-10-14 04:04:17 +09:00
0fcbe38837 fix(deps): update dependency i18next to v23.16.0 (#2492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 03:46:38 +09:00
b85a40f683 Update changelog for v3.6.0 2024-10-13 13:57:28 +00:00
19 changed files with 407 additions and 122 deletions

View File

@ -62,6 +62,12 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
sudo snap install snapcraft --classic sudo snap install snapcraft --classic
sudo apt update
sudo apt install -y flatpak flatpak-builder
sudo flatpak remote-add --if-not-exists --system flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y flathub org.freedesktop.Platform/x86_64/20.08
sudo flatpak install -y flathub org.freedesktop.Sdk/x86_64/20.08
sudo flatpak install -y flathub org.electronjs.Electron2.BaseApp/x86_64/20.08
pnpm release:linux pnpm release:linux
- name: Build and release on Windows - name: Build and release on Windows

View File

@ -2,8 +2,56 @@
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.
#### [v3.6.0](https://github.com/th-ch/youtube-music/compare/v3.5.3...v3.6.0)
- feat(api-server): remote control api [`#1909`](https://github.com/th-ch/youtube-music/pull/1909)
- chore(deps): update playwright monorepo to v1.48.0 [`#2489`](https://github.com/th-ch/youtube-music/pull/2489)
- fix(`synced-lyrics`): Fix 2 issues [`#2441`](https://github.com/th-ch/youtube-music/pull/2441)
- chore(deps): update dependency typescript to v5.6.3 [`#2486`](https://github.com/th-ch/youtube-music/pull/2486)
- chore(deps): update dependency electron to v32.2.0 [`#2487`](https://github.com/th-ch/youtube-music/pull/2487)
- chore(deps): update dependency del-cli to v6 [`#2475`](https://github.com/th-ch/youtube-music/pull/2475)
- chore(deps): update dependency typescript-eslint to v8.8.1 [`#2477`](https://github.com/th-ch/youtube-music/pull/2477)
- fix(deps): update dependency solid-js to v1.9.2 [`#2480`](https://github.com/th-ch/youtube-music/pull/2480)
- Revert "chore(deps): update dependency electron-builder to v25" [`#2488`](https://github.com/th-ch/youtube-music/pull/2488)
- chore(deps): update dependency electron-builder to v25 [`#2406`](https://github.com/th-ch/youtube-music/pull/2406)
- fix(deps): update dependency deepmerge-ts to v7.1.3 [`#2481`](https://github.com/th-ch/youtube-music/pull/2481)
- fix(deps): update dependency ts-morph to v24 [`#2474`](https://github.com/th-ch/youtube-music/pull/2474)
- fix(deps): update dependency i18next to v23.15.2 [`#2471`](https://github.com/th-ch/youtube-music/pull/2471)
- chore(deps): update eslint monorepo to v9.12.0 [`#2470`](https://github.com/th-ch/youtube-music/pull/2470)
- chore(deps): update dependency @stylistic/eslint-plugin-js to v2.9.0 [`#2469`](https://github.com/th-ch/youtube-music/pull/2469)
- chore(deps): bump micromatch from 4.0.5 to 4.0.8 [`#2465`](https://github.com/th-ch/youtube-music/pull/2465)
- chore(deps): bump braces from 3.0.2 to 3.0.3 [`#2466`](https://github.com/th-ch/youtube-music/pull/2466)
- fix(deps): update dependency electron-updater to v6.3.9 [`#2468`](https://github.com/th-ch/youtube-music/pull/2468)
- fix(deps): update dependency deepmerge-ts to v7.1.1 [`#2467`](https://github.com/th-ch/youtube-music/pull/2467)
- chore(deps): update dependency typescript-eslint to v8.8.0 [`#2457`](https://github.com/th-ch/youtube-music/pull/2457)
- chore(deps): update dependency @babel/runtime to v7.25.7 [`#2462`](https://github.com/th-ch/youtube-music/pull/2462)
- chore(deps): update dependency rollup to v4.24.0 [`#2458`](https://github.com/th-ch/youtube-music/pull/2458)
- chore(deps): update dependency eslint-plugin-import to v2.31.0 [`#2464`](https://github.com/th-ch/youtube-music/pull/2464)
- chore(deps): update dependency rollup to v4.22.5 [`#2448`](https://github.com/th-ch/youtube-music/pull/2448)
- chore(deps): update dependency typescript-eslint to v8.7.0 [`#2450`](https://github.com/th-ch/youtube-music/pull/2450)
- fix(deps): update dependency solid-js to v1.9.1 [`#2451`](https://github.com/th-ch/youtube-music/pull/2451)
- chore(deps): update dependency vite to v5.4.8 [`#2449`](https://github.com/th-ch/youtube-music/pull/2449)
- chore(deps): update dependency discord-api-types to v0.37.101 [`#2440`](https://github.com/th-ch/youtube-music/pull/2440)
- chore(deps): update dependency esbuild to v0.24.0 [`#2439`](https://github.com/th-ch/youtube-music/pull/2439)
- chore(deps): update eslint monorepo to v9.11.1 [`#2442`](https://github.com/th-ch/youtube-music/pull/2442)
- chore(deps): update dependency @types/howler to v2.2.12 [`#2443`](https://github.com/th-ch/youtube-music/pull/2443)
- chore(deps): update dependency vite to v5.4.7 [`#2434`](https://github.com/th-ch/youtube-music/pull/2434)
- chore(deps): update playwright monorepo to v1.47.2 [`#2436`](https://github.com/th-ch/youtube-music/pull/2436)
- chore(deps): update eslint monorepo to v9.11.0 [`#2437`](https://github.com/th-ch/youtube-music/pull/2437)
- fix(deps): update dependency youtubei.js to v10.5.0 [`#2431`](https://github.com/th-ch/youtube-music/pull/2431)
- chore(deps): update dependency rollup to v4.22.4 [`#2430`](https://github.com/th-ch/youtube-music/pull/2430)
- chore(deps): update dependency electron to v32.1.2 [`#2433`](https://github.com/th-ch/youtube-music/pull/2433)
- feat: ESLint Flat Config (v9 support #2229) [`#2426`](https://github.com/th-ch/youtube-music/pull/2426)
- fix(taskbar-mediacontrol): fix icon color [`#2485`](https://github.com/th-ch/youtube-music/issues/2485)
- chore(eslint): apply eslint-plugin-prettier [`#2438`](https://github.com/th-ch/youtube-music/issues/2438)
- fix: apply fix from eslint [`cb1381b`](https://github.com/th-ch/youtube-music/commit/cb1381bbb394e2bbb404f44817ef96411dabc8a9)
- chore(i18n): Translated using Weblate (Portuguese (Brazil)) [`bcff26c`](https://github.com/th-ch/youtube-music/commit/bcff26c85b18258806f3960309776bc860c3a54e)
- chore(i18n): Translated using Weblate (Persian) [`ead448e`](https://github.com/th-ch/youtube-music/commit/ead448ed98095339557903eb0f84c4a6d0f32058)
#### [v3.5.3](https://github.com/th-ch/youtube-music/compare/v3.5.2...v3.5.3) #### [v3.5.3](https://github.com/th-ch/youtube-music/compare/v3.5.2...v3.5.3)
> 17 September 2024
- fix: fix `trustedHTML` issue [`#2339`](https://github.com/th-ch/youtube-music/issues/2339) - fix: fix `trustedHTML` issue [`#2339`](https://github.com/th-ch/youtube-music/issues/2339)
- chore(deps): update dependency rollup to v4.21.3 [`6edc84a`](https://github.com/th-ch/youtube-music/commit/6edc84a8bd6c7e009041117ba0d2004783eb3a47) - chore(deps): update dependency rollup to v4.21.3 [`6edc84a`](https://github.com/th-ch/youtube-music/commit/6edc84a8bd6c7e009041117ba0d2004783eb3a47)
- chore(deps): update typescript-eslint monorepo to v8.6.0 [`d4c8a43`](https://github.com/th-ch/youtube-music/commit/d4c8a4320d733f7bddc4dcd1de93644790e71d66) - chore(deps): update typescript-eslint monorepo to v8.6.0 [`d4c8a43`](https://github.com/th-ch/youtube-music/commit/d4c8a4320d733f7bddc4dcd1de93644790e71d66)

View File

@ -1,7 +1,7 @@
{ {
"name": "youtube-music", "name": "youtube-music",
"productName": "YouTube Music", "productName": "YouTube Music",
"version": "3.6.0", "version": "3.6.1",
"description": "YouTube Music Desktop App - including custom plugins", "description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js", "main": "./dist/main/index.js",
"license": "MIT", "license": "MIT",
@ -40,7 +40,8 @@
] ]
} }
], ],
"icon": "assets/generated/icons/mac/icon.icns" "icon": "assets/generated/icons/mac/icon.icns",
"compression": "maximum"
}, },
"win": { "win": {
"icon": "assets/generated/icons/win/icon.ico", "icon": "assets/generated/icons/win/icon.ico",
@ -61,7 +62,8 @@
"arm64" "arm64"
] ]
} }
] ],
"compression": "maximum"
}, },
"nsisWeb": { "nsisWeb": {
"runAfterFinish": false "runAfterFinish": false
@ -70,13 +72,67 @@
"icon": "assets/generated/icons/png", "icon": "assets/generated/icons/png",
"category": "AudioVideo", "category": "AudioVideo",
"target": [ "target": [
"AppImage", {
"snap", "target": "AppImage",
"freebsd", "arch": [
"deb", "x64",
"rpm" "arm64",
"armv7l"
]
},
{
"target": "flatpak",
"arch": [
"x64"
]
},
{
"target": "deb",
"arch": [
"x64",
"arm64",
"armv7l"
]
},
{
"target": "rpm",
"arch": [
"x64",
"arm64"
]
},
{
"target": "snap",
"arch": [
"x64"
]
},
{
"target": "freebsd",
"arch": [
"x64",
"arm64",
"armv7l"
]
},
{
"target": "tar.gz",
"arch": [
"x64",
"arm64",
"armv7l"
]
}
] ]
}, },
"appImage": {
"description": "YouTube Music Desktop App bundled with custom plugins (and built-in ad blocker / downloader)",
"category": "AudioVideo"
},
"flatpak": {
"description": "YouTube Music Desktop App bundled with custom plugins (and built-in ad blocker / downloader)",
"category": "AudioVideo"
},
"deb": { "deb": {
"depends": [ "depends": [
"libgtk-3-0", "libgtk-3-0",
@ -139,7 +195,7 @@
"typecheck": "tsc -p tsconfig.json --noEmit" "typecheck": "tsc -p tsconfig.json --noEmit"
}, },
"engines": { "engines": {
"node": ">=18.0.0", "node": ">=18",
"pnpm": ">=8" "pnpm": ">=8"
}, },
"pnpm": { "pnpm": {
@ -153,7 +209,8 @@
}, },
"patchedDependencies": { "patchedDependencies": {
"vudio@2.1.1": "patches/vudio@2.1.1.patch", "vudio@2.1.1": "patches/vudio@2.1.1.patch",
"app-builder-lib@24.13.3": "patches/app-builder-lib@24.13.3.patch" "app-builder-lib@24.13.3": "patches/app-builder-lib@24.13.3.patch",
"@malept/flatpak-bundler": "patches/@malept__flatpak-bundler.patch"
} }
}, },
"dependencies": { "dependencies": {
@ -182,7 +239,7 @@
"custom-electron-prompt": "1.5.8", "custom-electron-prompt": "1.5.8",
"dbus-next": "0.10.2", "dbus-next": "0.10.2",
"deepmerge-ts": "7.1.3", "deepmerge-ts": "7.1.3",
"electron-debug": "4.0.1", "electron-debug": "4.1.0",
"electron-is": "3.0.0", "electron-is": "3.0.0",
"electron-localshortcut": "3.2.1", "electron-localshortcut": "3.2.1",
"electron-store": "10.0.0", "electron-store": "10.0.0",
@ -194,7 +251,7 @@
"hono": "4.6.4", "hono": "4.6.4",
"howler": "2.2.4", "howler": "2.2.4",
"html-to-text": "9.0.5", "html-to-text": "9.0.5",
"i18next": "23.15.2", "i18next": "23.16.0",
"jimp": "1.6.0", "jimp": "1.6.0",
"keyboardevent-from-electron-accelerator": "2.0.0", "keyboardevent-from-electron-accelerator": "2.0.0",
"keyboardevents-areequal": "0.2.2", "keyboardevents-areequal": "0.2.2",

View File

@ -0,0 +1,29 @@
diff --git a/index.js b/index.js
index 5968fcf47b69094993b0f861c03f5560e4a6a9b7..0fe16d4f40612c0abfa57898909ce0083f56944c 100644
--- a/index.js
+++ b/index.js
@@ -56,19 +56,23 @@ function getOptionsWithDefaults (options, manifest) {
async function spawnWithLogging (options, command, args, allowFail) {
return new Promise((resolve, reject) => {
logger(`$ ${command} ${args.join(' ')}`)
+ const output = []
const child = childProcess.spawn(command, args, { cwd: options['working-dir'] })
child.stdout.on('data', (data) => {
+ output.push(data)
logger(`1> ${data}`)
})
child.stderr.on('data', (data) => {
+ output.push(data)
logger(`2> ${data}`)
})
child.on('error', (error) => {
+ logger(`error - ${error.message} ${error.stack}`)
reject(error)
})
child.on('close', (code) => {
if (!allowFail && code !== 0) {
- reject(new Error(`${command} failed with status code ${code}`))
+ reject(new Error(`${command} ${args.join(' ')} failed with status code ${code} ${output.join(' ')}`))
}
resolve(code === 0)
})

27
pnpm-lock.yaml generated
View File

@ -13,6 +13,9 @@ overrides:
'@babel/runtime': 7.25.7 '@babel/runtime': 7.25.7
patchedDependencies: patchedDependencies:
'@malept/flatpak-bundler':
hash: vli4xtu6rndz3xtsscixhngsxa
path: patches/@malept__flatpak-bundler.patch
app-builder-lib@24.13.3: app-builder-lib@24.13.3:
hash: zcnm2qnjaggm2keyecnhiglkke hash: zcnm2qnjaggm2keyecnhiglkke
path: patches/app-builder-lib@24.13.3.patch path: patches/app-builder-lib@24.13.3.patch
@ -100,8 +103,8 @@ importers:
specifier: 7.1.3 specifier: 7.1.3
version: 7.1.3 version: 7.1.3
electron-debug: electron-debug:
specifier: 4.0.1 specifier: 4.1.0
version: 4.0.1 version: 4.1.0
electron-is: electron-is:
specifier: 3.0.0 specifier: 3.0.0
version: 3.0.0 version: 3.0.0
@ -136,8 +139,8 @@ importers:
specifier: 9.0.5 specifier: 9.0.5
version: 9.0.5 version: 9.0.5
i18next: i18next:
specifier: 23.15.2 specifier: 23.16.0
version: 23.15.2 version: 23.16.0
jimp: jimp:
specifier: 1.6.0 specifier: 1.6.0
version: 1.6.0 version: 1.6.0
@ -2095,8 +2098,8 @@ packages:
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
hasBin: true hasBin: true
electron-debug@4.0.1: electron-debug@4.1.0:
resolution: {integrity: sha512-PdUG3SvcK70P05z99PFLUzn0+lPZl5c4quG1bXI7OtPaXxidwh8UONcdRLsr+6J9kf5y1FycJD5nBd80dYrcsA==} resolution: {integrity: sha512-rdbvmotqbaNcSuinPe1tzB5zK+JKal+4LSDbguBcqTLARNqWrGoRS/TkR1gGH4+63boYH3HUaf9r9ECAxgIe9g==}
engines: {node: '>=18'} engines: {node: '>=18'}
electron-devtools-installer@3.2.0: electron-devtools-installer@3.2.0:
@ -2717,8 +2720,8 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'} engines: {node: '>=10.17.0'}
i18next@23.15.2: i18next@23.16.0:
resolution: {integrity: sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==} resolution: {integrity: sha512-Ni3CG6c14teOogY19YNRl+kYaE/Rb59khy0VyHVn4uOZ97E2E/Yziyi6r3C3s9+wacjdLZiq/LLYyx+Cgd+FCw==}
iconv-corefoundation@1.1.7: iconv-corefoundation@1.1.7:
resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
@ -5135,7 +5138,7 @@ snapshots:
dependencies: dependencies:
cross-spawn: 7.0.3 cross-spawn: 7.0.3
'@malept/flatpak-bundler@0.4.0': '@malept/flatpak-bundler@0.4.0(patch_hash=vli4xtu6rndz3xtsscixhngsxa)':
dependencies: dependencies:
debug: 4.3.7 debug: 4.3.7
fs-extra: 9.1.0 fs-extra: 9.1.0
@ -5618,7 +5621,7 @@ snapshots:
'@electron/notarize': 2.2.1 '@electron/notarize': 2.2.1
'@electron/osx-sign': 1.0.5 '@electron/osx-sign': 1.0.5
'@electron/universal': 2.0.1 '@electron/universal': 2.0.1
'@malept/flatpak-bundler': 0.4.0 '@malept/flatpak-bundler': 0.4.0(patch_hash=vli4xtu6rndz3xtsscixhngsxa)
'@types/fs-extra': 9.0.13 '@types/fs-extra': 9.0.13
async-exit-hook: 2.0.1 async-exit-hook: 2.0.1
bluebird-lst: 1.0.9 bluebird-lst: 1.0.9
@ -6351,7 +6354,7 @@ snapshots:
- electron-builder-squirrel-windows - electron-builder-squirrel-windows
- supports-color - supports-color
electron-debug@4.0.1: electron-debug@4.1.0:
dependencies: dependencies:
electron-is-dev: 3.0.1 electron-is-dev: 3.0.1
electron-localshortcut: 3.2.1 electron-localshortcut: 3.2.1
@ -7190,7 +7193,7 @@ snapshots:
human-signals@2.1.0: {} human-signals@2.1.0: {}
i18next@23.15.2: i18next@23.16.0:
dependencies: dependencies:
'@babel/runtime': 7.25.7 '@babel/runtime': 7.25.7

View File

@ -281,24 +281,17 @@
}, },
"api-server": { "api-server": {
"description": "Adds an API server to control the player", "description": "Adds an API server to control the player",
"name": "API Server [Beta]",
"dialog": { "dialog": {
"request": { "request": {
"title": "API authorization request",
"message": "Allow {{ID}} ({{origin}}) to access the API?",
"buttons": { "buttons": {
"allow": "Allow", "allow": "Allow",
"deny": "Deny" "deny": "Deny"
} },
"message": "Allow {{ID}} ({{origin}}) to access the API?",
"title": "API authorization request"
} }
}, },
"menu": { "menu": {
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
},
"auth-strategy": { "auth-strategy": {
"label": "Authorization strategy", "label": "Authorization strategy",
"submenu": { "submenu": {
@ -309,16 +302,23 @@
"label": "No authorization" "label": "No authorization"
} }
} }
} },
},
"prompt": {
"hostname": { "hostname": {
"title": "Hostname", "label": "Hostname"
"label": "Enter the hostname (like 0.0.0.0) for the API server:"
}, },
"port": { "port": {
"title": "Port", "label": "Port"
"label": "Enter the port for the API server:" }
},
"name": "API Server [Beta]",
"prompt": {
"hostname": {
"label": "Enter the hostname (like 0.0.0.0) for the API server:",
"title": "Hostname"
},
"port": {
"label": "Enter the port for the API server:",
"title": "Port"
} }
} }
}, },

View File

@ -293,6 +293,7 @@
}, },
"menu": { "menu": {
"auth-strategy": { "auth-strategy": {
"label": "Estrategia de autorización",
"submenu": { "submenu": {
"auth-at-first": { "auth-at-first": {
"label": "Autorizar la primera solicitud" "label": "Autorizar la primera solicitud"

View File

@ -201,6 +201,7 @@
"restart": "I-restart ang App", "restart": "I-restart ang App",
"show": "Ipakita ang window", "show": "Ipakita ang window",
"tooltip": { "tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}" "with-song-info": "YouTube Music: {{artist}} - {{title}}"
} }
} }
@ -212,6 +213,9 @@
}, },
"adblocker": { "adblocker": {
"description": "I-block ang lahat ng ad at tracking", "description": "I-block ang lahat ng ad at tracking",
"menu": {
"blocker": "Blocker"
},
"name": "Pag-block ng Ad" "name": "Pag-block ng Ad"
}, },
"album-actions": { "album-actions": {
@ -222,7 +226,10 @@
"description": "Naglalapat ng dynamic na tema at visual effect batay sa color palette ng album", "description": "Naglalapat ng dynamic na tema at visual effect batay sa color palette ng album",
"menu": { "menu": {
"color-mix-ratio": { "color-mix-ratio": {
"label": "Ratio ng paghahalo ng kulay" "label": "Ratio ng paghahalo ng kulay",
"submenu": {
"percent": "{{ratio}}%"
}
} }
}, },
"name": "Tema ng Kulay ng Album" "name": "Tema ng Kulay ng Album"
@ -261,6 +268,7 @@
} }
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "Ayos ng Transisyon",
"submenu": { "submenu": {
"during": "Habang {{interpolationTime}} s" "during": "Habang {{interpolationTime}} s"
} }
@ -268,6 +276,50 @@
"use-fullscreen": { "use-fullscreen": {
"label": "Gumamit ng fullscreen" "label": "Gumamit ng fullscreen"
} }
},
"name": "Ambient Mode"
},
"api-server": {
"description": "Nagdadagdag ng API Server upang kontrolin ang player",
"dialog": {
"request": {
"buttons": {
"allow": "Payagan",
"deny": "Tanggihan"
},
"message": "Payagan ang {{ID}} ({{origin}}) upang ma-access ang API?",
"title": "Awtorisasyon ng API request"
}
},
"menu": {
"auth-strategy": {
"label": "Estratehiya ng awtorisasyon",
"submenu": {
"auth-at-first": {
"label": "Mag-autorisa sa unang request"
},
"none": {
"label": "Walang awtorisasyon"
}
}
},
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
}
},
"name": "API Server [Beta]",
"prompt": {
"hostname": {
"label": "Itala ang hostname (tulad ng 0.0.0.0) para sa API server:",
"title": "Hostname"
},
"port": {
"label": "Itala ang port para sa API server:",
"title": "Port"
}
} }
}, },
"audio-compressor": { "audio-compressor": {
@ -301,7 +353,8 @@
} }
}, },
"compact-sidebar": { "compact-sidebar": {
"description": "Laging i-set ang sidebar sa compact mode" "description": "Laging i-set ang sidebar sa compact mode",
"name": "Pinaliit na Sidebar"
}, },
"crossfade": { "crossfade": {
"description": "I-crossfade kada kanta", "description": "I-crossfade kada kanta",
@ -425,7 +478,8 @@
} }
}, },
"lumiastream": { "lumiastream": {
"description": "Nabibigay suporta sa Lumia Stream" "description": "Nabibigay suporta sa Lumia Stream",
"name": "Lumia Stream [Beta]"
}, },
"lyrics-genius": { "lyrics-genius": {
"description": "Nagdaragdag ng suporta sa lyrics para sa karamihan ng kanta", "description": "Nagdaragdag ng suporta sa lyrics para sa karamihan ng kanta",
@ -582,7 +636,8 @@
}, },
"listenbrainz": { "listenbrainz": {
"token": { "token": {
"label": "Ilagay ang ListenBrainz user token:" "label": "Ilagay ang ListenBrainz user token:",
"title": "Token ng ListenBrainz"
} }
} }
} }
@ -696,7 +751,10 @@
} }
}, },
"visualizer": { "visualizer": {
"description": "Idaragdag ng visualizer sa player" "description": "Idaragdag ng visualizer sa player",
"menu": {
"visualizer-type": "Uri ng Visualizer"
}
} }
} }
} }

View File

@ -279,6 +279,49 @@
}, },
"name": "Modo ambiente" "name": "Modo ambiente"
}, },
"api-server": {
"description": "Adiciona um servidor API para controlar o player",
"dialog": {
"request": {
"buttons": {
"allow": "Permitir",
"deny": "Negar"
},
"message": "Permitir que {{ID}} {{origin}} acesse o API?",
"title": "Pedido de autorização API"
}
},
"menu": {
"auth-strategy": {
"label": "Estratégia de autorização",
"submenu": {
"auth-at-first": {
"label": "Autorizar na primeira solicitação"
},
"none": {
"label": "Não autorizar"
}
}
},
"hostname": {
"label": "Nome do anfitrião"
},
"port": {
"label": "Porta"
}
},
"name": "Servidor API [Beta]",
"prompt": {
"hostname": {
"label": "Entre o nome do host (como 0.0.0.0) para o servidor API:",
"title": "Nome do anfitrião"
},
"port": {
"label": "Entre a porta do servidor API:",
"title": "Porta"
}
}
},
"audio-compressor": { "audio-compressor": {
"description": "Aplicar compressão ao áudio (reduz o volume das partes mais altas e aumenta o volume das partes mais baixas)", "description": "Aplicar compressão ao áudio (reduz o volume das partes mais altas e aumenta o volume das partes mais baixas)",
"name": "Compressor de áudio" "name": "Compressor de áudio"

View File

@ -11,6 +11,7 @@ import {
shell, shell,
dialog, dialog,
ipcMain, ipcMain,
protocol,
type BrowserWindowConstructorOptions, type BrowserWindowConstructorOptions,
} from 'electron'; } from 'electron';
import enhanceWebRequest, { import enhanceWebRequest, {
@ -83,6 +84,34 @@ if (!gotTheLock) {
app.exit(); app.exit();
} }
protocol.registerSchemesAsPrivileged([
{
scheme: 'http',
privileges: {
standard: true,
bypassCSP: true,
allowServiceWorkers: true,
supportFetchAPI: true,
corsEnabled: true,
stream: true,
codeCache: true,
},
},
{
scheme: 'https',
privileges: {
standard: true,
bypassCSP: true,
allowServiceWorkers: true,
supportFetchAPI: true,
corsEnabled: true,
stream: true,
codeCache: true,
},
},
{ scheme: 'mailto', privileges: { standard: true } },
]);
// Ozone platform hint: Required for Wayland support // Ozone platform hint: Required for Wayland support
app.commandLine.appendSwitch('ozone-platform-hint', 'auto'); app.commandLine.appendSwitch('ozone-platform-hint', 'auto');
// SharedArrayBuffer: Required for downloader (@ffmpeg/core-mt) // SharedArrayBuffer: Required for downloader (@ffmpeg/core-mt)
@ -531,7 +560,11 @@ app.once('browser-window-created', (_event, win) => {
console.log(log); console.log(log);
} }
if (errorCode !== -3) { if (
errorCode !== -3 &&
// Workaround for #2435
!new URL(validatedURL).hostname.includes('doubleclick.net')
) {
// -3 is a false positive // -3 is a false positive
win.webContents.send('log', log); win.webContents.send('log', log);
win.webContents.loadFile(ErrorHtmlAsset); win.webContents.loadFile(ErrorHtmlAsset);

View File

@ -10,14 +10,15 @@ import { createBackend } from '@/utils';
import { JWTPayloadSchema } from './scheme'; import { JWTPayloadSchema } from './scheme';
import { registerAuth, registerControl } from './routes'; import { registerAuth, registerControl } from './routes';
import type { APIServerConfig } from '../config'; import { type APIServerConfig, AuthStrategy } from '../config';
import type { BackendType } from './types'; import type { BackendType } from './types';
export const backend = createBackend<BackendType, APIServerConfig>({ export const backend = createBackend<BackendType, APIServerConfig>({
async start(ctx) { async start(ctx) {
const config = await ctx.getConfig(); const config = await ctx.getConfig();
this.init(ctx); await this.init(ctx);
registerCallback((songInfo) => { registerCallback((songInfo) => {
this.songInfo = songInfo; this.songInfo = songInfo;
}); });
@ -49,17 +50,20 @@ export const backend = createBackend<BackendType, APIServerConfig>({
this.app.use('*', cors()); this.app.use('*', cors());
// middlewares // middlewares
this.app.use( this.app.use('/api/*', async (ctx, next) => {
'/api/*', if (config.authStrategy !== AuthStrategy.NONE) {
jwt({ return await jwt({
secret: config.secret, secret: config.secret,
}), })(ctx, next);
); }
await next();
});
this.app.use('/api/*', async (ctx, next) => { this.app.use('/api/*', async (ctx, next) => {
const result = await JWTPayloadSchema.spa(await ctx.get('jwtPayload')); const result = await JWTPayloadSchema.spa(await ctx.get('jwtPayload'));
const isAuthorized = const isAuthorized =
result.success && config.authorizedClients.includes(result.data.id); config.authStrategy === AuthStrategy.NONE ||
(result.success && config.authorizedClients.includes(result.data.id));
if (!isAuthorized) { if (!isAuthorized) {
ctx.status(401); ctx.status(401);
return ctx.body('Unauthorized'); return ctx.body('Unauthorized');
@ -73,12 +77,26 @@ export const backend = createBackend<BackendType, APIServerConfig>({
registerAuth(this.app, ctx); registerAuth(this.app, ctx);
// swagger // swagger
this.app.openAPIRegistry.registerComponent(
'securitySchemes',
'bearerAuth',
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
);
this.app.doc('/doc', { this.app.doc('/doc', {
openapi: '3.1.0', openapi: '3.1.0',
info: { info: {
version: '1.0.0', version: '1.0.0',
title: 'Youtube Music API Server', title: 'Youtube Music API Server',
}, },
security: [
{
bearerAuth: [],
},
],
}); });
this.app.get('/swagger', swaggerUI({ url: '/doc' })); this.app.get('/swagger', swaggerUI({ url: '/doc' }));

View File

@ -6,9 +6,9 @@ import { getConnInfo } from '@hono/node-server/conninfo';
import { t } from '@/i18n'; import { t } from '@/i18n';
import { APIServerConfig } from '../../config'; import { type APIServerConfig, AuthStrategy } from '../../config';
import { JWTPayload } from '../scheme';
import type { JWTPayload } from '../scheme';
import type { HonoApp } from '../types'; import type { HonoApp } from '../types';
import type { BackendContext } from '@/types/contexts'; import type { BackendContext } from '@/types/contexts';
@ -18,6 +18,7 @@ const routes = {
path: '/auth/{id}', path: '/auth/{id}',
summary: '', summary: '',
description: '', description: '',
security: [],
request: { request: {
params: z.object({ params: z.object({
id: z.string(), id: z.string(),
@ -51,16 +52,16 @@ export const register = (
if (config.authorizedClients.includes(id)) { if (config.authorizedClients.includes(id)) {
// SKIP CHECK // SKIP CHECK
} else if (config.authStrategy === 'AUTH_AT_FIRST') { } else if (config.authStrategy === AuthStrategy.AUTH_AT_FIRST) {
const result = await dialog.showMessageBox({ const result = await dialog.showMessageBox({
title: t('plugins.api-server.dialog.request.title'), title: t('plugins.api-server.dialog.request.title'),
message: t('plugins.api-server.dialog.request.message', { message: t('plugins.api-server.dialog.request.message', {
origin: getConnInfo(ctx).remote.address, origin: getConnInfo(ctx).remote.address,
id, ID: id,
}), }),
buttons: [ buttons: [
t('plugins.api-server.dialog.request.buttons.allow'), t('plugins.api-server.dialog.request.buttons.allow'),
t('plugins.api-server.dialog.request.deny'), t('plugins.api-server.dialog.request.buttons.deny'),
], ],
defaultId: 1, defaultId: 1,
cancelId: 1, cancelId: 1,
@ -70,7 +71,7 @@ export const register = (
ctx.status(403); ctx.status(403);
return ctx.body(null); return ctx.body(null);
} }
} else if (config.authStrategy === 'NONE') { } else if (config.authStrategy === AuthStrategy.NONE) {
// SKIP CHECK // SKIP CHECK
} }

View File

@ -29,9 +29,6 @@ const routes = {
path: `/api/${API_VERSION}/previous`, path: `/api/${API_VERSION}/previous`,
summary: 'play previous song', summary: 'play previous song',
description: 'Plays the previous song in the queue', description: 'Plays the previous song in the queue',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -43,9 +40,6 @@ const routes = {
path: `/api/${API_VERSION}/next`, path: `/api/${API_VERSION}/next`,
summary: 'play next song', summary: 'play next song',
description: 'Plays the next song in the queue', description: 'Plays the next song in the queue',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -57,9 +51,6 @@ const routes = {
path: `/api/${API_VERSION}/play`, path: `/api/${API_VERSION}/play`,
summary: 'Play', summary: 'Play',
description: 'Change the state of the player to play', description: 'Change the state of the player to play',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -71,9 +62,6 @@ const routes = {
path: `/api/${API_VERSION}/pause`, path: `/api/${API_VERSION}/pause`,
summary: 'Pause', summary: 'Pause',
description: 'Change the state of the player to pause', description: 'Change the state of the player to pause',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -86,9 +74,6 @@ const routes = {
summary: 'Toggle play/pause', summary: 'Toggle play/pause',
description: description:
'Change the state of the player to play if paused, or pause if playing', 'Change the state of the player to play if paused, or pause if playing',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -100,9 +85,6 @@ const routes = {
path: `/api/${API_VERSION}/like`, path: `/api/${API_VERSION}/like`,
summary: 'like song', summary: 'like song',
description: 'Set the current song as liked', description: 'Set the current song as liked',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -114,9 +96,6 @@ const routes = {
path: `/api/${API_VERSION}/dislike`, path: `/api/${API_VERSION}/dislike`,
summary: 'dislike song', summary: 'dislike song',
description: 'Set the current song as disliked', description: 'Set the current song as disliked',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -175,9 +154,6 @@ const routes = {
path: `/api/${API_VERSION}/shuffle`, path: `/api/${API_VERSION}/shuffle`,
summary: 'shuffle', summary: 'shuffle',
description: 'Shuffle the queue', description: 'Shuffle the queue',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -255,9 +231,6 @@ const routes = {
path: `/api/${API_VERSION}/toggle-mute`, path: `/api/${API_VERSION}/toggle-mute`,
summary: 'toggle mute', summary: 'toggle mute',
description: 'Toggle the mute state of the player', description: 'Toggle the mute state of the player',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
204: { 204: {
description: 'Success', description: 'Success',
@ -270,9 +243,6 @@ const routes = {
path: `/api/${API_VERSION}/fullscreen`, path: `/api/${API_VERSION}/fullscreen`,
summary: 'get fullscreen state', summary: 'get fullscreen state',
description: 'Get the current fullscreen state', description: 'Get the current fullscreen state',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
200: { 200: {
description: 'Success', description: 'Success',
@ -291,9 +261,6 @@ const routes = {
path: `/api/${API_VERSION}/queue-info`, path: `/api/${API_VERSION}/queue-info`,
summary: 'get current queue info', summary: 'get current queue info',
description: 'Get the current queue info', description: 'Get the current queue info',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
200: { 200: {
description: 'Success', description: 'Success',
@ -313,9 +280,6 @@ const routes = {
path: `/api/${API_VERSION}/song-info`, path: `/api/${API_VERSION}/song-info`,
summary: 'get current song info', summary: 'get current song info',
description: 'Get the current song info', description: 'Get the current song info',
request: {
headers: AuthHeadersSchema,
},
responses: { responses: {
200: { 200: {
description: 'Success', description: 'Success',

View File

@ -12,7 +12,7 @@ export type BackendType = {
oldConfig?: APIServerConfig; oldConfig?: APIServerConfig;
songInfo?: SongInfo; songInfo?: SongInfo;
init: (ctx: BackendContext<APIServerConfig>) => void; init: (ctx: BackendContext<APIServerConfig>) => Promise<void>;
run: (hostname: string, port: number) => void; run: (hostname: string, port: number) => void;
end: () => void; end: () => void;
}; };

View File

@ -1,8 +1,13 @@
export enum AuthStrategy {
AUTH_AT_FIRST = 'AUTH_AT_FIRST',
NONE = 'NONE',
}
export interface APIServerConfig { export interface APIServerConfig {
enabled: boolean; enabled: boolean;
hostname: string; hostname: string;
port: number; port: number;
authStrategy: 'AUTH_AT_FIRST' | 'NONE'; authStrategy: AuthStrategy;
secret: string; secret: string;
authorizedClients: string[]; authorizedClients: string[];
@ -12,7 +17,7 @@ export const defaultAPIServerConfig: APIServerConfig = {
enabled: true, enabled: true,
hostname: '0.0.0.0', hostname: '0.0.0.0',
port: 26538, port: 26538,
authStrategy: 'AUTH_AT_FIRST', authStrategy: AuthStrategy.AUTH_AT_FIRST,
secret: Date.now().toString(36), secret: Date.now().toString(36),
authorizedClients: [], authorizedClients: [],

View File

@ -3,7 +3,11 @@ import prompt from 'custom-electron-prompt';
import { t } from '@/i18n'; import { t } from '@/i18n';
import promptOptions from '@/providers/prompt-options'; import promptOptions from '@/providers/prompt-options';
import { APIServerConfig, defaultAPIServerConfig } from './config'; import {
type APIServerConfig,
AuthStrategy,
defaultAPIServerConfig,
} from './config';
import type { MenuContext } from '@/types/contexts'; import type { MenuContext } from '@/types/contexts';
import type { MenuTemplate } from '@/menu'; import type { MenuTemplate } from '@/menu';
@ -74,17 +78,17 @@ export const onMenu = async ({
'plugins.api-server.menu.auth-strategy.submenu.auth-at-first.label', 'plugins.api-server.menu.auth-strategy.submenu.auth-at-first.label',
), ),
type: 'radio', type: 'radio',
checked: config.authStrategy === 'AUTH_AT_FIRST', checked: config.authStrategy === AuthStrategy.AUTH_AT_FIRST,
click() { click() {
setConfig({ ...config, authStrategy: 'AUTH_AT_FIRST' }); setConfig({ ...config, authStrategy: AuthStrategy.AUTH_AT_FIRST });
}, },
}, },
{ {
label: t('plugins.api-server.menu.auth-strategy.submenu.none.label'), label: t('plugins.api-server.menu.auth-strategy.submenu.none.label'),
type: 'radio', type: 'radio',
checked: config.authStrategy === 'NONE', checked: config.authStrategy === AuthStrategy.NONE,
click() { click() {
setConfig({ ...config, authStrategy: 'NONE' }); setConfig({ ...config, authStrategy: AuthStrategy.NONE });
}, },
}, },
], ],

View File

@ -172,6 +172,8 @@ function downloadSongOnFinishSetup({
let duration: number | undefined; let duration: number | undefined;
let time = 0; let time = 0;
const defaultDownloadFolder = app.getPath('downloads');
registerCallback((songInfo: SongInfo) => { registerCallback((songInfo: SongInfo) => {
if ( if (
!songInfo.isPaused && !songInfo.isPaused &&
@ -185,7 +187,9 @@ function downloadSongOnFinishSetup({
) { ) {
downloadSong( downloadSong(
currentUrl, currentUrl,
config.downloadOnFinish.folder ?? config.downloadFolder, config.downloadOnFinish.folder ??
config.downloadFolder ??
defaultDownloadFolder,
); );
} else if ( } else if (
config.downloadOnFinish.mode === 'percent' && config.downloadOnFinish.mode === 'percent' &&
@ -193,7 +197,9 @@ function downloadSongOnFinishSetup({
) { ) {
downloadSong( downloadSong(
currentUrl, currentUrl,
config.downloadOnFinish.folder ?? config.downloadFolder, config.downloadOnFinish.folder ??
config.downloadFolder ??
defaultDownloadFolder,
); );
} }
} }

View File

@ -51,6 +51,13 @@ interface YouTubeMusicAppElement extends HTMLElement {
} }
async function onApiLoaded() { async function onApiLoaded() {
// Workaround for #2459
document
.querySelector('button.video-button.ytmusic-av-toggle')
?.addEventListener('click', () =>
window.dispatchEvent(new Event('resize')),
);
window.ipcRenderer.on('ytmd:previous-video', () => { window.ipcRenderer.on('ytmd:previous-video', () => {
document document
.querySelector<HTMLElement>('.previous-button.ytmusic-player-bar') .querySelector<HTMLElement>('.previous-button.ytmusic-player-bar')
@ -129,8 +136,8 @@ async function onApiLoaded() {
} }
}; };
window.ipcRenderer.on('ytmd:get-fullscreen', (event) => { window.ipcRenderer.on('ytmd:get-fullscreen', () => {
event.sender.send('ytmd:set-fullscreen', isFullscreen()); window.ipcRenderer.send('ytmd:set-fullscreen', isFullscreen());
}); });
window.ipcRenderer.on( window.ipcRenderer.on(
@ -148,9 +155,9 @@ async function onApiLoaded() {
?.onVolumeTap(); ?.onVolumeTap();
}); });
window.ipcRenderer.on('ytmd:get-queue', (event) => { window.ipcRenderer.on('ytmd:get-queue', () => {
const queue = document.querySelector<QueueElement>('#queue'); const queue = document.querySelector<QueueElement>('#queue');
event.sender.send('ytmd:get-queue-response', { window.ipcRenderer.send('ytmd:get-queue-response', {
items: queue?.queue.getItems(), items: queue?.queue.getItems(),
autoPlaying: queue?.queue.autoPlaying, autoPlaying: queue?.queue.autoPlaying,
continuation: queue?.queue.continuation, continuation: queue?.queue.continuation,
@ -237,16 +244,16 @@ async function onApiLoaded() {
'options.likeButtons', 'options.likeButtons',
); );
if (likeButtonsOptions) { if (likeButtonsOptions) {
const likeButtons: HTMLElement | null = document.querySelector( const style = document.createElement('style');
'ytmusic-like-button-renderer', style.textContent = `
); ytmusic-player-bar[is-mweb-player-bar-modernization-enabled] .middle-controls-buttons.ytmusic-player-bar, #like-button-renderer {
if (likeButtons) { display: ${likeButtonsOptions === 'hide' ? 'none' : 'inherit'} !important;
likeButtons.style.display = }
{ ytmusic-player-bar[is-mweb-player-bar-modernization-enabled] .middle-controls.ytmusic-player-bar {
hide: 'none', justify-content: ${likeButtonsOptions === 'hide' ? 'flex-start' : 'space-between'} !important;
force: 'inherit', }`;
}[likeButtonsOptions] || '';
} document.head.appendChild(style);
} }
} }

View File

@ -73,6 +73,8 @@ tp-yt-paper-item.ytmusic-guide-entry-renderer::before {
#av-id ~ #player.ytmusic-player-page:not([player-ui-state="FULLSCREEN"]) { #av-id ~ #player.ytmusic-player-page:not([player-ui-state="FULLSCREEN"]) {
margin-top: auto !important; margin-top: auto !important;
margin-bottom: auto !important; margin-bottom: auto !important;
margin-left: var(--ytmusic-player-page-vertical-padding);
margin-right: var(--ytmusic-player-page-vertical-padding);
max-height: calc(100% - (var(--ytmusic-player-page-vertical-padding) * 2)); max-height: calc(100% - (var(--ytmusic-player-page-vertical-padding) * 2));
max-width: calc(100% - var(--ytmusic-player-page-vertical-padding) * 2); max-width: calc(100% - var(--ytmusic-player-page-vertical-padding) * 2);
} }