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 }}
run: |
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
- 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.
#### [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)
> 17 September 2024
- 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 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",
"productName": "YouTube Music",
"version": "3.6.0",
"version": "3.6.1",
"description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js",
"license": "MIT",
@ -40,7 +40,8 @@
]
}
],
"icon": "assets/generated/icons/mac/icon.icns"
"icon": "assets/generated/icons/mac/icon.icns",
"compression": "maximum"
},
"win": {
"icon": "assets/generated/icons/win/icon.ico",
@ -61,7 +62,8 @@
"arm64"
]
}
]
],
"compression": "maximum"
},
"nsisWeb": {
"runAfterFinish": false
@ -70,13 +72,67 @@
"icon": "assets/generated/icons/png",
"category": "AudioVideo",
"target": [
"AppImage",
"snap",
"freebsd",
"deb",
"rpm"
{
"target": "AppImage",
"arch": [
"x64",
"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": {
"depends": [
"libgtk-3-0",
@ -139,7 +195,7 @@
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"engines": {
"node": ">=18.0.0",
"node": ">=18",
"pnpm": ">=8"
},
"pnpm": {
@ -153,7 +209,8 @@
},
"patchedDependencies": {
"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": {
@ -182,7 +239,7 @@
"custom-electron-prompt": "1.5.8",
"dbus-next": "0.10.2",
"deepmerge-ts": "7.1.3",
"electron-debug": "4.0.1",
"electron-debug": "4.1.0",
"electron-is": "3.0.0",
"electron-localshortcut": "3.2.1",
"electron-store": "10.0.0",
@ -194,7 +251,7 @@
"hono": "4.6.4",
"howler": "2.2.4",
"html-to-text": "9.0.5",
"i18next": "23.15.2",
"i18next": "23.16.0",
"jimp": "1.6.0",
"keyboardevent-from-electron-accelerator": "2.0.0",
"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
patchedDependencies:
'@malept/flatpak-bundler':
hash: vli4xtu6rndz3xtsscixhngsxa
path: patches/@malept__flatpak-bundler.patch
app-builder-lib@24.13.3:
hash: zcnm2qnjaggm2keyecnhiglkke
path: patches/app-builder-lib@24.13.3.patch
@ -100,8 +103,8 @@ importers:
specifier: 7.1.3
version: 7.1.3
electron-debug:
specifier: 4.0.1
version: 4.0.1
specifier: 4.1.0
version: 4.1.0
electron-is:
specifier: 3.0.0
version: 3.0.0
@ -136,8 +139,8 @@ importers:
specifier: 9.0.5
version: 9.0.5
i18next:
specifier: 23.15.2
version: 23.15.2
specifier: 23.16.0
version: 23.16.0
jimp:
specifier: 1.6.0
version: 1.6.0
@ -2095,8 +2098,8 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
electron-debug@4.0.1:
resolution: {integrity: sha512-PdUG3SvcK70P05z99PFLUzn0+lPZl5c4quG1bXI7OtPaXxidwh8UONcdRLsr+6J9kf5y1FycJD5nBd80dYrcsA==}
electron-debug@4.1.0:
resolution: {integrity: sha512-rdbvmotqbaNcSuinPe1tzB5zK+JKal+4LSDbguBcqTLARNqWrGoRS/TkR1gGH4+63boYH3HUaf9r9ECAxgIe9g==}
engines: {node: '>=18'}
electron-devtools-installer@3.2.0:
@ -2717,8 +2720,8 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
i18next@23.15.2:
resolution: {integrity: sha512-zcPSWzCvw6uKnuYHIqs4W7hTuB9e3AFcSdZgvCWoPXIZsBjBd4djN2/2uOHIB+1DFFkQnMBXvhNg7J3WyCuywQ==}
i18next@23.16.0:
resolution: {integrity: sha512-Ni3CG6c14teOogY19YNRl+kYaE/Rb59khy0VyHVn4uOZ97E2E/Yziyi6r3C3s9+wacjdLZiq/LLYyx+Cgd+FCw==}
iconv-corefoundation@1.1.7:
resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==}
@ -5135,7 +5138,7 @@ snapshots:
dependencies:
cross-spawn: 7.0.3
'@malept/flatpak-bundler@0.4.0':
'@malept/flatpak-bundler@0.4.0(patch_hash=vli4xtu6rndz3xtsscixhngsxa)':
dependencies:
debug: 4.3.7
fs-extra: 9.1.0
@ -5618,7 +5621,7 @@ snapshots:
'@electron/notarize': 2.2.1
'@electron/osx-sign': 1.0.5
'@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
async-exit-hook: 2.0.1
bluebird-lst: 1.0.9
@ -6351,7 +6354,7 @@ snapshots:
- electron-builder-squirrel-windows
- supports-color
electron-debug@4.0.1:
electron-debug@4.1.0:
dependencies:
electron-is-dev: 3.0.1
electron-localshortcut: 3.2.1
@ -7190,7 +7193,7 @@ snapshots:
human-signals@2.1.0: {}
i18next@23.15.2:
i18next@23.16.0:
dependencies:
'@babel/runtime': 7.25.7

View File

@ -281,24 +281,17 @@
},
"api-server": {
"description": "Adds an API server to control the player",
"name": "API Server [Beta]",
"dialog": {
"request": {
"title": "API authorization request",
"message": "Allow {{ID}} ({{origin}}) to access the API?",
"buttons": {
"allow": "Allow",
"deny": "Deny"
}
},
"message": "Allow {{ID}} ({{origin}}) to access the API?",
"title": "API authorization request"
}
},
"menu": {
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
},
"auth-strategy": {
"label": "Authorization strategy",
"submenu": {
@ -309,16 +302,23 @@
"label": "No authorization"
}
}
}
},
"prompt": {
},
"hostname": {
"title": "Hostname",
"label": "Enter the hostname (like 0.0.0.0) for the API server:"
"label": "Hostname"
},
"port": {
"title": "Port",
"label": "Enter the port for the API server:"
"label": "Port"
}
},
"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": {
"auth-strategy": {
"label": "Estrategia de autorización",
"submenu": {
"auth-at-first": {
"label": "Autorizar la primera solicitud"

View File

@ -201,6 +201,7 @@
"restart": "I-restart ang App",
"show": "Ipakita ang window",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
@ -212,6 +213,9 @@
},
"adblocker": {
"description": "I-block ang lahat ng ad at tracking",
"menu": {
"blocker": "Blocker"
},
"name": "Pag-block ng Ad"
},
"album-actions": {
@ -222,7 +226,10 @@
"description": "Naglalapat ng dynamic na tema at visual effect batay sa color palette ng album",
"menu": {
"color-mix-ratio": {
"label": "Ratio ng paghahalo ng kulay"
"label": "Ratio ng paghahalo ng kulay",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Tema ng Kulay ng Album"
@ -261,6 +268,7 @@
}
},
"smoothness-transition": {
"label": "Ayos ng Transisyon",
"submenu": {
"during": "Habang {{interpolationTime}} s"
}
@ -268,6 +276,50 @@
"use-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": {
@ -301,7 +353,8 @@
}
},
"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": {
"description": "I-crossfade kada kanta",
@ -425,7 +478,8 @@
}
},
"lumiastream": {
"description": "Nabibigay suporta sa Lumia Stream"
"description": "Nabibigay suporta sa Lumia Stream",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Nagdaragdag ng suporta sa lyrics para sa karamihan ng kanta",
@ -582,7 +636,8 @@
},
"listenbrainz": {
"token": {
"label": "Ilagay ang ListenBrainz user token:"
"label": "Ilagay ang ListenBrainz user token:",
"title": "Token ng ListenBrainz"
}
}
}
@ -696,7 +751,10 @@
}
},
"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"
},
"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": {
"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"

View File

@ -11,6 +11,7 @@ import {
shell,
dialog,
ipcMain,
protocol,
type BrowserWindowConstructorOptions,
} from 'electron';
import enhanceWebRequest, {
@ -83,6 +84,34 @@ if (!gotTheLock) {
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
app.commandLine.appendSwitch('ozone-platform-hint', 'auto');
// SharedArrayBuffer: Required for downloader (@ffmpeg/core-mt)
@ -531,7 +560,11 @@ app.once('browser-window-created', (_event, win) => {
console.log(log);
}
if (errorCode !== -3) {
if (
errorCode !== -3 &&
// Workaround for #2435
!new URL(validatedURL).hostname.includes('doubleclick.net')
) {
// -3 is a false positive
win.webContents.send('log', log);
win.webContents.loadFile(ErrorHtmlAsset);

View File

@ -10,14 +10,15 @@ import { createBackend } from '@/utils';
import { JWTPayloadSchema } from './scheme';
import { registerAuth, registerControl } from './routes';
import type { APIServerConfig } from '../config';
import { type APIServerConfig, AuthStrategy } from '../config';
import type { BackendType } from './types';
export const backend = createBackend<BackendType, APIServerConfig>({
async start(ctx) {
const config = await ctx.getConfig();
this.init(ctx);
await this.init(ctx);
registerCallback((songInfo) => {
this.songInfo = songInfo;
});
@ -49,17 +50,20 @@ export const backend = createBackend<BackendType, APIServerConfig>({
this.app.use('*', cors());
// middlewares
this.app.use(
'/api/*',
jwt({
secret: config.secret,
}),
);
this.app.use('/api/*', async (ctx, next) => {
if (config.authStrategy !== AuthStrategy.NONE) {
return await jwt({
secret: config.secret,
})(ctx, next);
}
await next();
});
this.app.use('/api/*', async (ctx, next) => {
const result = await JWTPayloadSchema.spa(await ctx.get('jwtPayload'));
const isAuthorized =
result.success && config.authorizedClients.includes(result.data.id);
config.authStrategy === AuthStrategy.NONE ||
(result.success && config.authorizedClients.includes(result.data.id));
if (!isAuthorized) {
ctx.status(401);
return ctx.body('Unauthorized');
@ -73,12 +77,26 @@ export const backend = createBackend<BackendType, APIServerConfig>({
registerAuth(this.app, ctx);
// swagger
this.app.openAPIRegistry.registerComponent(
'securitySchemes',
'bearerAuth',
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
);
this.app.doc('/doc', {
openapi: '3.1.0',
info: {
version: '1.0.0',
title: 'Youtube Music API Server',
},
security: [
{
bearerAuth: [],
},
],
});
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 { APIServerConfig } from '../../config';
import { JWTPayload } from '../scheme';
import { type APIServerConfig, AuthStrategy } from '../../config';
import type { JWTPayload } from '../scheme';
import type { HonoApp } from '../types';
import type { BackendContext } from '@/types/contexts';
@ -18,6 +18,7 @@ const routes = {
path: '/auth/{id}',
summary: '',
description: '',
security: [],
request: {
params: z.object({
id: z.string(),
@ -51,16 +52,16 @@ export const register = (
if (config.authorizedClients.includes(id)) {
// SKIP CHECK
} else if (config.authStrategy === 'AUTH_AT_FIRST') {
} else if (config.authStrategy === AuthStrategy.AUTH_AT_FIRST) {
const result = await dialog.showMessageBox({
title: t('plugins.api-server.dialog.request.title'),
message: t('plugins.api-server.dialog.request.message', {
origin: getConnInfo(ctx).remote.address,
id,
ID: id,
}),
buttons: [
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,
cancelId: 1,
@ -70,7 +71,7 @@ export const register = (
ctx.status(403);
return ctx.body(null);
}
} else if (config.authStrategy === 'NONE') {
} else if (config.authStrategy === AuthStrategy.NONE) {
// SKIP CHECK
}

View File

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

View File

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

View File

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

View File

@ -3,7 +3,11 @@ import prompt from 'custom-electron-prompt';
import { t } from '@/i18n';
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 { MenuTemplate } from '@/menu';
@ -74,17 +78,17 @@ export const onMenu = async ({
'plugins.api-server.menu.auth-strategy.submenu.auth-at-first.label',
),
type: 'radio',
checked: config.authStrategy === 'AUTH_AT_FIRST',
checked: config.authStrategy === AuthStrategy.AUTH_AT_FIRST,
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'),
type: 'radio',
checked: config.authStrategy === 'NONE',
checked: config.authStrategy === AuthStrategy.NONE,
click() {
setConfig({ ...config, authStrategy: 'NONE' });
setConfig({ ...config, authStrategy: AuthStrategy.NONE });
},
},
],

View File

@ -172,6 +172,8 @@ function downloadSongOnFinishSetup({
let duration: number | undefined;
let time = 0;
const defaultDownloadFolder = app.getPath('downloads');
registerCallback((songInfo: SongInfo) => {
if (
!songInfo.isPaused &&
@ -185,7 +187,9 @@ function downloadSongOnFinishSetup({
) {
downloadSong(
currentUrl,
config.downloadOnFinish.folder ?? config.downloadFolder,
config.downloadOnFinish.folder ??
config.downloadFolder ??
defaultDownloadFolder,
);
} else if (
config.downloadOnFinish.mode === 'percent' &&
@ -193,7 +197,9 @@ function downloadSongOnFinishSetup({
) {
downloadSong(
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() {
// Workaround for #2459
document
.querySelector('button.video-button.ytmusic-av-toggle')
?.addEventListener('click', () =>
window.dispatchEvent(new Event('resize')),
);
window.ipcRenderer.on('ytmd:previous-video', () => {
document
.querySelector<HTMLElement>('.previous-button.ytmusic-player-bar')
@ -129,8 +136,8 @@ async function onApiLoaded() {
}
};
window.ipcRenderer.on('ytmd:get-fullscreen', (event) => {
event.sender.send('ytmd:set-fullscreen', isFullscreen());
window.ipcRenderer.on('ytmd:get-fullscreen', () => {
window.ipcRenderer.send('ytmd:set-fullscreen', isFullscreen());
});
window.ipcRenderer.on(
@ -148,9 +155,9 @@ async function onApiLoaded() {
?.onVolumeTap();
});
window.ipcRenderer.on('ytmd:get-queue', (event) => {
window.ipcRenderer.on('ytmd:get-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(),
autoPlaying: queue?.queue.autoPlaying,
continuation: queue?.queue.continuation,
@ -237,16 +244,16 @@ async function onApiLoaded() {
'options.likeButtons',
);
if (likeButtonsOptions) {
const likeButtons: HTMLElement | null = document.querySelector(
'ytmusic-like-button-renderer',
);
if (likeButtons) {
likeButtons.style.display =
{
hide: 'none',
force: 'inherit',
}[likeButtonsOptions] || '';
}
const style = document.createElement('style');
style.textContent = `
ytmusic-player-bar[is-mweb-player-bar-modernization-enabled] .middle-controls-buttons.ytmusic-player-bar, #like-button-renderer {
display: ${likeButtonsOptions === 'hide' ? 'none' : 'inherit'} !important;
}
ytmusic-player-bar[is-mweb-player-bar-modernization-enabled] .middle-controls.ytmusic-player-bar {
justify-content: ${likeButtonsOptions === 'hide' ? 'flex-start' : 'space-between'} !important;
}`;
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"]) {
margin-top: 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-width: calc(100% - var(--ytmusic-player-page-vertical-padding) * 2);
}