Compare commits

..

74 Commits

Author SHA1 Message Date
0d462ac3a2 HOTFIX: Bump version to 3.7.4 2025-02-18 00:37:57 +09:00
bcb94f6de8 chore(deps): update dependency rollup to v4.34.8 (#2982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-18 00:36:54 +09:00
fe925ec8ee fix(plugin-loader): update context filtering logic for backend mode (#2990) 2025-02-18 00:35:55 +09:00
86c77d141f Update changelog for v3.7.3 2025-02-17 04:04:16 +00:00
754ca3caaa Bump version to 3.7.3 2025-02-17 12:47:57 +09:00
61ea104d7b fix(downloader): use the upgrade button to check for premium status (#2987) 2025-02-17 12:42:07 +09:00
573bdfae03 chore(deps): update dependency electron-vite to v3 (#2986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 02:45:21 +09:00
cca493b7d5 fix: build performance 2025-02-17 02:44:47 +09:00
f47262d27b fix(album-color-theme): fix Color deps 2025-02-17 01:44:24 +09:00
65bf9129ea fix(action-release): bump pnpm version to v10 2025-02-16 15:22:07 +09:00
87e9b9f7a8 fix: revert some deps 2025-02-16 14:43:13 +09:00
07bc4f05fd chore(deps): update dependency @babel/runtime to v7.26.9 (#2980)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-16 14:37:52 +09:00
e3a6808087 fix: pnpm overrides 2025-02-16 14:37:22 +09:00
e9184e5d60 fix: bump deps 2025-02-16 14:30:02 +09:00
a5b32d96f8 fix(action): bump pnpm version to v10 2025-02-16 14:14:08 +09:00
040db7539c fix(deps): fix pnpm 2025-02-16 14:12:28 +09:00
da646c1d53 fix(vite): set server.cors.origin (#2981) 2025-02-16 13:23:35 +09:00
5f5917f972 chore(deps-dev): bump esbuild from 0.24.2 to 0.25.0 (#2973)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-16 00:08:47 +09:00
eccb0d2f08 fix(deps): update dependency solid-transition-group to v0.3.0 (#2949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-15 03:50:09 +09:00
4cd9dd17df fix: remove disable-gpu-memory-buffer-video-frames flag (#2963) 2025-02-15 03:49:52 +09:00
5de07b9a96 fix(downloader): fix pmd undefined 2025-02-14 21:23:19 +09:00
151f067beb chore(i18n): Translated using Weblate (Hindi)
Currently translated at 33.2% (135 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hi/
2025-02-10 07:01:54 +01:00
c68a7bd19f chore(i18n): Translated using Weblate (Filipino)
Currently translated at 86.6% (352 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fil/
2025-02-10 07:01:53 +01:00
b87e5e31df chore(i18n): Translated using Weblate (Arabic)
Currently translated at 35.9% (146 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ar/
2025-02-08 21:49:42 +01:00
03229d61c8 chore(i18n): Translated using Weblate (Arabic)
Currently translated at 35.9% (146 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ar/
2025-02-08 01:01:53 +00:00
b6330eed18 fix(deps): update dependency semver to v7.7.0 (#2948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:47:32 +09:00
b254812ac2 chore(deps): update playwright monorepo to v1.50.1 (#2943)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:45:11 +09:00
7e243e2fbf fix(deps): update dependency @hono/node-server to v1.13.8 (#2944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:44:10 +09:00
307e52cc89 fix(deps): update dependency electron-store to v10.0.1 (#2945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:43:45 +09:00
f7b7ea916f chore(deps): update dependency rollup to v4.34.1 (#2946)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:43:34 +09:00
3eccf8daca chore(deps): update dependency typescript-eslint to v8.22.0 (#2947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 18:43:23 +09:00
aa48944212 fix(synced-lyrics): Fix reverse direction of synced lyrics for persian or other rtl languages (#2940)
Add direction auto to synced lyrics to fix reverse direction in rtl languages
2025-02-02 23:55:07 +09:00
4d51f1a412 chore(deps): update dependency electron to v34.0.2 (#2942)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:54:45 +09:00
d3c9f76582 chore(deps): update dependency discord-api-types to v0.37.119 (#2941)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:46:22 +09:00
d638a6cf28 fix(deps): update dependency hono to v4.6.20 (#2932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:46:12 +09:00
f93651b219 chore(deps): update eslint monorepo to v9.19.0 (#2935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:45:20 +09:00
cb8c6c69fe fix(deps): update dependency bgutils-js to v3.1.3 (#2934)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:45:10 +09:00
4e7266fb1b fix(deps): update dependency i18next to v24.2.2 (#2933)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:44:59 +09:00
8de75ff3a5 fix(deps): update dependency happy-dom to v16.8.1 (#2936)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 23:44:38 +09:00
3236c88eb2 chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 11.8% (48 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-01-27 18:02:51 +00:00
c9f0ad14c2 chore(deps): update dependency @babel/runtime to v7.26.7 (#2924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:36:15 +09:00
0a9199c92b chore(config): migrate renovate config (#2925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:36:04 +09:00
3ffcff7d9c fix(deps): update dependency @ghostery/adblocker-electron-preload to v2.5.0 (#2923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:27:46 +09:00
ddf614d362 fix(deps): update dependency @ghostery/adblocker-electron to v2.5.0 (#2922)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:21:45 +09:00
6f1a77bbb9 chore(deps): update playwright monorepo to v1.50.0 (#2921)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:21:33 +09:00
8595f9761e fix: pnpm patch key 2025-01-25 00:21:18 +09:00
cc442182fd chore(deps): update dependency vite-plugin-inspect to v10.1.0 (#2920)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:20:11 +09:00
b827a05eea chore(deps): update dependency rollup to v4.32.0 (#2919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:14:57 +09:00
250abab8bc fix(deps): update dependency hono to v4.6.18 (#2918)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:14:46 +09:00
8e45518ccf fix(deps): update dependency deepmerge-ts to v7.1.4 (#2917)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:14:36 +09:00
7485e065ed chore(deps): update dependency vite to v6.0.11 (#2894)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:14:21 +09:00
c1d88f91d4 chore(deps): update dependency electron to v34.0.1 (#2916)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:14:09 +09:00
124a2bd8d0 fix: pnpm patch 2025-01-25 00:13:55 +09:00
f8f94f9665 Rename app-builder-lib@26.0.0-alpha.9.patch to app-builder-lib@26.0.0-alpha.10.patch 2025-01-25 00:13:15 +09:00
5e98a82b23 chore(deps): update dependency electron-builder-squirrel-windows to v26.0.0-alpha.10 (#2899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:12:48 +09:00
a5c20a66b3 chore(deps): update dependency electron-builder to v26.0.0-alpha.10 (#2898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:07:25 +09:00
cc84116ad1 chore(deps): update dependency typescript-eslint to v8.21.0 (#2901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:06:16 +09:00
a2e2031708 chore(deps): update dependency discord-api-types to v0.37.117 (#2895)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:05:46 +09:00
5001eabf23 fix(deps): update dependency youtubei.js to v13 (#2904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:05:14 +09:00
aac2974430 chore(deps): update dependency vite to v6.0.9 [security] (#2907)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:04:50 +09:00
f7f005bb3d fix(deps): update dependency happy-dom to v16.7.2 (#2902)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:02:58 +09:00
e1f6d5b7f2 fix(discord-plugin): handle album name padding if length < 2 (#2903) 2025-01-25 00:02:38 +09:00
b6b607897e feat(navigation): added nav icon padding (#2905) 2025-01-25 00:02:24 +09:00
651ebb2b1a chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 97.7% (397 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2025-01-23 22:01:53 +01:00
9fa24deed2 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 100.0% (406 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2025-01-23 22:01:52 +01:00
c81022d373 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 99.5% (404 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2025-01-23 22:01:51 +01:00
b726dc7580 chore(i18n): Translated using Weblate (Hindi)
Currently translated at 30.7% (125 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hi/
2025-01-22 06:47:10 +01:00
471aa7d0a6 chore(i18n): Translated using Weblate (Persian)
Currently translated at 100.0% (406 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fa/
2025-01-22 06:47:09 +01:00
f34d645ac3 chore(deps): update dependency rollup to v4.31.0 (#2891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-20 11:55:56 +09:00
d2a11a560e chore(deps): update dependency eslint-plugin-prettier to v5.2.3 (#2889)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-19 22:08:46 +09:00
9d185872db chore(i18n): Translated using Weblate (Persian)
Currently translated at 100.0% (406 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fa/
2025-01-18 15:56:20 +01:00
d0ff71aa66 chore(deps): update dependency vite-plugin-inspect to v10.0.7 (#2882)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-18 22:44:03 +09:00
bc8999585f fix(deps): update dependency hono to v4.6.17 (#2883)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-18 18:15:36 +09:00
1e1582e31f Update changelog for v3.7.2 2025-01-18 05:44:19 +00:00
24 changed files with 2508 additions and 1932 deletions

View File

@ -23,7 +23,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
version: 10
run_install: false
- name: Setup NodeJS
@ -98,7 +98,7 @@ jobs:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
version: 10
run_install: false
- name: Setup NodeJS

View File

@ -2,8 +2,110 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v3.7.3](https://github.com/th-ch/youtube-music/compare/v3.7.2...v3.7.3)
- fix(downloader): use the upgrade button to check for premium status [`#2987`](https://github.com/th-ch/youtube-music/pull/2987)
- chore(deps): update dependency electron-vite to v3 [`#2986`](https://github.com/th-ch/youtube-music/pull/2986)
- chore(deps): update dependency @babel/runtime to v7.26.9 [`#2980`](https://github.com/th-ch/youtube-music/pull/2980)
- fix(vite): set server.cors.origin [`#2981`](https://github.com/th-ch/youtube-music/pull/2981)
- chore(deps-dev): bump esbuild from 0.24.2 to 0.25.0 [`#2973`](https://github.com/th-ch/youtube-music/pull/2973)
- fix(deps): update dependency solid-transition-group to v0.3.0 [`#2949`](https://github.com/th-ch/youtube-music/pull/2949)
- fix: remove disable-gpu-memory-buffer-video-frames flag [`#2963`](https://github.com/th-ch/youtube-music/pull/2963)
- fix(deps): update dependency semver to v7.7.0 [`#2948`](https://github.com/th-ch/youtube-music/pull/2948)
- chore(deps): update playwright monorepo to v1.50.1 [`#2943`](https://github.com/th-ch/youtube-music/pull/2943)
- fix(deps): update dependency @hono/node-server to v1.13.8 [`#2944`](https://github.com/th-ch/youtube-music/pull/2944)
- fix(deps): update dependency electron-store to v10.0.1 [`#2945`](https://github.com/th-ch/youtube-music/pull/2945)
- chore(deps): update dependency rollup to v4.34.1 [`#2946`](https://github.com/th-ch/youtube-music/pull/2946)
- chore(deps): update dependency typescript-eslint to v8.22.0 [`#2947`](https://github.com/th-ch/youtube-music/pull/2947)
- fix(synced-lyrics): Fix reverse direction of synced lyrics for persian or other rtl languages [`#2940`](https://github.com/th-ch/youtube-music/pull/2940)
- chore(deps): update dependency electron to v34.0.2 [`#2942`](https://github.com/th-ch/youtube-music/pull/2942)
- chore(deps): update dependency discord-api-types to v0.37.119 [`#2941`](https://github.com/th-ch/youtube-music/pull/2941)
- fix(deps): update dependency hono to v4.6.20 [`#2932`](https://github.com/th-ch/youtube-music/pull/2932)
- chore(deps): update eslint monorepo to v9.19.0 [`#2935`](https://github.com/th-ch/youtube-music/pull/2935)
- fix(deps): update dependency bgutils-js to v3.1.3 [`#2934`](https://github.com/th-ch/youtube-music/pull/2934)
- fix(deps): update dependency i18next to v24.2.2 [`#2933`](https://github.com/th-ch/youtube-music/pull/2933)
- fix(deps): update dependency happy-dom to v16.8.1 [`#2936`](https://github.com/th-ch/youtube-music/pull/2936)
- chore(deps): update dependency @babel/runtime to v7.26.7 [`#2924`](https://github.com/th-ch/youtube-music/pull/2924)
- chore(config): migrate renovate config [`#2925`](https://github.com/th-ch/youtube-music/pull/2925)
- fix(deps): update dependency @ghostery/adblocker-electron-preload to v2.5.0 [`#2923`](https://github.com/th-ch/youtube-music/pull/2923)
- fix(deps): update dependency @ghostery/adblocker-electron to v2.5.0 [`#2922`](https://github.com/th-ch/youtube-music/pull/2922)
- chore(deps): update playwright monorepo to v1.50.0 [`#2921`](https://github.com/th-ch/youtube-music/pull/2921)
- chore(deps): update dependency vite-plugin-inspect to v10.1.0 [`#2920`](https://github.com/th-ch/youtube-music/pull/2920)
- chore(deps): update dependency rollup to v4.32.0 [`#2919`](https://github.com/th-ch/youtube-music/pull/2919)
- fix(deps): update dependency hono to v4.6.18 [`#2918`](https://github.com/th-ch/youtube-music/pull/2918)
- fix(deps): update dependency deepmerge-ts to v7.1.4 [`#2917`](https://github.com/th-ch/youtube-music/pull/2917)
- chore(deps): update dependency vite to v6.0.11 [`#2894`](https://github.com/th-ch/youtube-music/pull/2894)
- chore(deps): update dependency electron to v34.0.1 [`#2916`](https://github.com/th-ch/youtube-music/pull/2916)
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.0-alpha.10 [`#2899`](https://github.com/th-ch/youtube-music/pull/2899)
- chore(deps): update dependency electron-builder to v26.0.0-alpha.10 [`#2898`](https://github.com/th-ch/youtube-music/pull/2898)
- chore(deps): update dependency typescript-eslint to v8.21.0 [`#2901`](https://github.com/th-ch/youtube-music/pull/2901)
- chore(deps): update dependency discord-api-types to v0.37.117 [`#2895`](https://github.com/th-ch/youtube-music/pull/2895)
- fix(deps): update dependency youtubei.js to v13 [`#2904`](https://github.com/th-ch/youtube-music/pull/2904)
- chore(deps): update dependency vite to v6.0.9 [security] [`#2907`](https://github.com/th-ch/youtube-music/pull/2907)
- fix(deps): update dependency happy-dom to v16.7.2 [`#2902`](https://github.com/th-ch/youtube-music/pull/2902)
- fix(discord-plugin): handle album name padding if length &lt; 2 [`#2903`](https://github.com/th-ch/youtube-music/pull/2903)
- feat(navigation): added nav icon padding [`#2905`](https://github.com/th-ch/youtube-music/pull/2905)
- chore(deps): update dependency rollup to v4.31.0 [`#2891`](https://github.com/th-ch/youtube-music/pull/2891)
- chore(deps): update dependency eslint-plugin-prettier to v5.2.3 [`#2889`](https://github.com/th-ch/youtube-music/pull/2889)
- chore(deps): update dependency vite-plugin-inspect to v10.0.7 [`#2882`](https://github.com/th-ch/youtube-music/pull/2882)
- fix(deps): update dependency hono to v4.6.17 [`#2883`](https://github.com/th-ch/youtube-music/pull/2883)
- fix: bump deps [`e9184e5`](https://github.com/th-ch/youtube-music/commit/e9184e5d60c2495473a7c3226ce9748ba89fceb3)
- fix(deps): fix pnpm [`040db75`](https://github.com/th-ch/youtube-music/commit/040db7539ccd1ae40f2632fdf38168cdaa26f112)
- chore(i18n): Translated using Weblate (Persian) [`9d18587`](https://github.com/th-ch/youtube-music/commit/9d185872dba5b56dabc691e56eafb13dc192b9cd)
#### [v3.7.2](https://github.com/th-ch/youtube-music/compare/v3.7.1...v3.7.2)
> 18 January 2025
- feat(api-server): add endpoint to get shuffle state [`#2792`](https://github.com/th-ch/youtube-music/pull/2792)
- chore(deps): update dependency discord-api-types to v0.37.116 [`#2877`](https://github.com/th-ch/youtube-music/pull/2877)
- chore(deps): update dependency eslint-plugin-prettier to v5.2.2 [`#2875`](https://github.com/th-ch/youtube-music/pull/2875)
- chore(deps): update eslint monorepo to v9.18.0 [`#2858`](https://github.com/th-ch/youtube-music/pull/2858)
- chore(deps): update dependency glob to v11.0.1 [`#2857`](https://github.com/th-ch/youtube-music/pull/2857)
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.0-alpha.9 [`#2874`](https://github.com/th-ch/youtube-music/pull/2874)
- chore(deps): update dependency electron to v34 [`#2867`](https://github.com/th-ch/youtube-music/pull/2867)
- chore(deps): update dependency eslint-config-prettier to v10 [`#2866`](https://github.com/th-ch/youtube-music/pull/2866)
- chore(deps): update dependency @stylistic/eslint-plugin-js to v2.13.0 [`#2864`](https://github.com/th-ch/youtube-music/pull/2864)
- chore(deps): update dependency typescript-eslint to v8.20.0 [`#2865`](https://github.com/th-ch/youtube-music/pull/2865)
- chore(deps): update dependency electron-builder to v26.0.0-alpha.9 [`#2869`](https://github.com/th-ch/youtube-music/pull/2869)
- fix: fix build.linux.desktop.entry [`#2859`](https://github.com/th-ch/youtube-music/pull/2859)
- feat(api-server): add endpoint to get volume state [`#2813`](https://github.com/th-ch/youtube-music/pull/2813)
- chore(deps): update dependency vite-plugin-inspect to v10 [`#2856`](https://github.com/th-ch/youtube-music/pull/2856)
- chore(deps): update dependency typescript to v5.7.3 [`#2855`](https://github.com/th-ch/youtube-music/pull/2855)
- fix(deps): update dependency @floating-ui/dom to v1.6.13 [`#2846`](https://github.com/th-ch/youtube-music/pull/2846)
- chore(deps): bump nanoid from 3.3.7 to 3.3.8 [`#2854`](https://github.com/th-ch/youtube-music/pull/2854)
- chore(deps): update dependency electron to v33.3.1 [`#2841`](https://github.com/th-ch/youtube-music/pull/2841)
- fix(deps): update dependency i18next to v24.2.1 [`#2840`](https://github.com/th-ch/youtube-music/pull/2840)
- chore(deps): update dependency typescript-eslint to v8.19.1 [`#2836`](https://github.com/th-ch/youtube-music/pull/2836)
- chore(deps): update dependency rollup to v4.30.1 [`#2833`](https://github.com/th-ch/youtube-music/pull/2833)
- fix(deps): update dependency solid-js to v1.9.4 [`#2849`](https://github.com/th-ch/youtube-music/pull/2849)
- fix(deps): update dependency fast-equals to v5.2.2 [`#2842`](https://github.com/th-ch/youtube-music/pull/2842)
- chore: Update README.md [`#2845`](https://github.com/th-ch/youtube-music/pull/2845)
- chore: Fixing the Content section in the README-ru.md file. [`#2847`](https://github.com/th-ch/youtube-music/pull/2847)
- chore: Create youtube-music-hu.svg [`#2844`](https://github.com/th-ch/youtube-music/pull/2844)
- chore: Create Transalated README-hu.md [`#2843`](https://github.com/th-ch/youtube-music/pull/2843)
- chore(deps): update dependency vite to v6.0.7 [`#2819`](https://github.com/th-ch/youtube-music/pull/2819)
- chore(deps): update dependency discord-api-types to v0.37.115 [`#2818`](https://github.com/th-ch/youtube-music/pull/2818)
- fix(deps): update dependency hono to v4.6.16 [`#2829`](https://github.com/th-ch/youtube-music/pull/2829)
- chore(deps): update dependency rollup to v4.29.2 [`#2832`](https://github.com/th-ch/youtube-music/pull/2832)
- fix(deps): update dependency fast-equals to v5.2.0 [`#2822`](https://github.com/th-ch/youtube-music/pull/2822)
- feat(api-server): add `insertPosition` for `addSongToQueue` [`#2808`](https://github.com/th-ch/youtube-music/pull/2808)
- chore(deps): update dependency typescript-eslint to v8.19.0 [`#2812`](https://github.com/th-ch/youtube-music/pull/2812)
- fix(deps): update dependency ts-morph to v25 [`#2810`](https://github.com/th-ch/youtube-music/pull/2810)
- fix(renderer): update event handler from onVolumeTap to onVolumeClick [`#2791`](https://github.com/th-ch/youtube-music/pull/2791)
- fix(deps): update dependency hono to v4.6.15 [`#2796`](https://github.com/th-ch/youtube-music/pull/2796)
- chore(deps): update dependency bufferutil to v4.0.9 [`#2787`](https://github.com/th-ch/youtube-music/pull/2787)
- feat: Refactor Menu Navigation and Update Media Control Icons [`#2783`](https://github.com/th-ch/youtube-music/pull/2783)
- fix(synced-lyrics): Revert font-size behavior for non-fancy modes [`#2788`](https://github.com/th-ch/youtube-music/pull/2788)
- fix(downloader): apply poToken [`#2863`](https://github.com/th-ch/youtube-music/issues/2863) [`#2780`](https://github.com/th-ch/youtube-music/issues/2780)
- chore(deps): update dependency electron-builder to v26 [`67fc0a4`](https://github.com/th-ch/youtube-music/commit/67fc0a415cae231a11f2846aadf01edb04f5c677)
- fix: fix lock file [`3339f99`](https://github.com/th-ch/youtube-music/commit/3339f997e3c2d4d2c32b3aee95c65d561f123fcb)
- chore(i18n): Translated using Weblate (Romanian) [`845dac3`](https://github.com/th-ch/youtube-music/commit/845dac3c0393dadea8efdd03ba1f41b1b36e6191)
#### [v3.7.1](https://github.com/th-ch/youtube-music/compare/v3.7.0...v3.7.1)
> 27 December 2024
- fix(deps): update dependency node-html-parser to v7 [`#2776`](https://github.com/th-ch/youtube-music/pull/2776)
- chore(deps): update dependency vite to v6.0.6 [`#2774`](https://github.com/th-ch/youtube-music/pull/2774)
- feat(api-server): Add queue api [`#2767`](https://github.com/th-ch/youtube-music/pull/2767)

View File

@ -147,6 +147,11 @@ export default defineConfig({
resolve: {
alias: resolveAlias,
},
server: {
cors: {
origin: 'https://music.youtube.com',
},
},
};
if (mode === 'development') {

View File

@ -2,7 +2,7 @@
"name": "youtube-music",
"desktopName": "com.github.th_ch.youtube_music",
"productName": "YouTube Music",
"version": "3.7.2",
"version": "3.7.4",
"description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js",
"license": "MIT",
@ -222,18 +222,19 @@
},
"pnpm": {
"overrides": {
"vite": "6.0.7",
"node-gyp": "11.0.0",
"vite": "6.1.0",
"node-gyp": "11.1.0",
"xml2js": "0.6.2",
"node-fetch": "3.3.2",
"@electron/universal": "2.0.1",
"@babel/runtime": "7.26.0"
"@babel/runtime": "7.26.9"
},
"patchedDependencies": {
"vudio@2.1.1": "patches/vudio@2.1.1.patch",
"app-builder-lib@26.0.0-alpha.9": "patches/app-builder-lib@26.0.0-alpha.9.patch",
"app-builder-lib@26.0.6": "patches/app-builder-lib@26.0.6.patch",
"@malept/flatpak-bundler": "patches/@malept__flatpak-bundler.patch"
}
},
"neverBuiltDependencies": []
},
"dependencies": {
"@electron-toolkit/tsconfig": "1.0.1",
@ -242,12 +243,12 @@
"@ffmpeg.wasm/main": "0.12.0",
"@floating-ui/dom": "1.6.13",
"@foobar404/wave": "2.0.5",
"@ghostery/adblocker-electron": "2.3.1",
"@ghostery/adblocker-electron-preload": "2.3.1",
"@hono/node-server": "1.13.7",
"@ghostery/adblocker-electron": "2.5.0",
"@ghostery/adblocker-electron-preload": "2.5.0",
"@hono/node-server": "1.13.8",
"@hono/swagger-ui": "0.5.0",
"@hono/zod-openapi": "0.18.3",
"@hono/zod-validator": "0.4.2",
"@hono/zod-openapi": "0.18.4",
"@hono/zod-validator": "0.4.3",
"@jellybrick/dbus-next": "0.10.3",
"@jellybrick/electron-better-web-request": "1.0.4",
"@jellybrick/mpris-service": "2.1.5",
@ -255,52 +256,51 @@
"@skyra/jaro-winkler": "1.1.1",
"@xhayper/discord-rpc": "1.2.0",
"async-mutex": "0.5.0",
"bgutils-js": "3.1.2",
"bgutils-js": "3.1.3",
"butterchurn": "3.0.0-beta.4",
"butterchurn-presets": "3.0.0-beta.4",
"color": "4.2.3",
"color": "5.0.0",
"conf": "13.1.0",
"custom-electron-prompt": "1.5.8",
"deepmerge-ts": "7.1.3",
"deepmerge-ts": "7.1.4",
"electron-debug": "4.1.0",
"electron-is": "3.0.0",
"electron-localshortcut": "3.2.1",
"electron-store": "10.0.0",
"electron-store": "10.0.1",
"electron-unhandled": "4.0.1",
"electron-updater": "6.3.9",
"fast-average-color": "9.4.0",
"fast-equals": "5.2.2",
"filenamify": "6.0.0",
"happy-dom": "16.6.0",
"hono": "4.6.16",
"happy-dom": "17.1.0",
"hono": "4.7.1",
"howler": "2.2.4",
"html-to-text": "9.0.5",
"i18next": "24.2.1",
"i18next": "24.2.2",
"jimp": "1.6.0",
"keyboardevent-from-electron-accelerator": "2.0.0",
"keyboardevents-areequal": "0.2.2",
"node-html-parser": "7.0.1",
"node-id3": "0.2.6",
"node-id3": "0.2.7",
"peerjs": "1.5.4",
"semver": "7.6.3",
"semver": "7.7.1",
"serve": "14.2.4",
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
"solid-floating-ui": "0.3.1",
"solid-js": "1.9.4",
"solid-styled-components": "0.28.5",
"solid-transition-group": "0.2.3",
"ts-morph": "25.0.0",
"solid-transition-group": "0.3.0",
"ts-morph": "25.0.1",
"vudio": "2.1.1",
"x11": "2.3.0",
"youtubei.js": "12.2.0",
"zod": "3.24.1"
"youtubei.js": "13.0.0",
"zod": "3.24.2"
},
"devDependencies": {
"@eslint/js": "9.18.0",
"@playwright/test": "1.49.1",
"@stylistic/eslint-plugin-js": "2.13.0",
"@eslint/js": "9.20.0",
"@playwright/test": "1.50.1",
"@stylistic/eslint-plugin-js": "3.1.0",
"@total-typescript/ts-reset": "0.6.1",
"@types/color": "4.2.0",
"@types/electron-localshortcut": "3.1.3",
"@types/eslint__js": "8.42.3",
"@types/howler": "2.2.12",
@ -311,30 +311,30 @@
"builtin-modules": "4.0.0",
"cross-env": "7.0.3",
"del-cli": "6.0.0",
"discord-api-types": "0.37.116",
"electron": "34.0.0",
"electron-builder": "26.0.0-alpha.9",
"electron-builder-squirrel-windows": "26.0.0-alpha.9",
"discord-api-types": "0.37.119",
"electron": "34.2.0",
"electron-builder": "26.0.6",
"electron-builder-squirrel-windows": "26.0.6",
"electron-devtools-installer": "4.0.0",
"electron-vite": "2.3.0",
"esbuild": "0.24.2",
"eslint": "9.18.0",
"electron-vite": "3.0.0",
"esbuild": "0.25.0",
"eslint": "9.20.1",
"eslint-config-prettier": "10.0.1",
"eslint-import-resolver-exports": "1.0.0-beta.5",
"eslint-import-resolver-typescript": "3.7.0",
"eslint-import-resolver-typescript": "3.8.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-prettier": "5.2.2",
"eslint-plugin-prettier": "5.2.3",
"glob": "11.0.1",
"node-gyp": "11.0.0",
"playwright": "1.49.1",
"rollup": "4.30.1",
"node-gyp": "11.1.0",
"playwright": "1.50.1",
"rollup": "4.34.8",
"typescript": "5.7.3",
"typescript-eslint": "8.20.0",
"typescript-eslint": "8.24.0",
"utf-8-validate": "6.0.5",
"vite": "6.0.7",
"vite-plugin-inspect": "10.0.6",
"vite": "6.1.0",
"vite-plugin-inspect": "10.2.1",
"vite-plugin-resolve": "2.5.2",
"vite-plugin-solid": "2.11.0",
"vite-plugin-solid": "2.11.1",
"ws": "8.18.0"
},
"auto-changelog": {

3399
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
"extends": ["config:recommended"],
"labels": ["dependencies"],
"postUpdateOptions": ["pnpmDedupe"]
}

View File

@ -745,7 +745,8 @@
"label": "Efecto de la línea",
"submenu": {
"fancy": {
"label": "Elegante"
"label": "Elegante",
"tooltip": "Usar efectos grandes, similares a los de una aplicación, en la línea actual"
},
"focus": {
"label": "Enfoque",

View File

@ -81,12 +81,12 @@
"menu": {
"about": "درباره",
"navigation": {
"label": "ناوبری",
"label": "کنترل‌های رابط",
"submenu": {
"copy-current-url": "کپی کردن URL فعلی",
"go-back": "بازگشت",
"go-forward": "حرکت به جلو",
"quit": "خروجی",
"copy-current-url": "کپی کردن لینک صفحه فعلی",
"go-back": "صفحه قبل",
"go-forward": "صفحه بعدی",
"quit": "خروج از برنامه",
"restart": "راه‌اندازی مجدد برنامه"
}
},
@ -98,8 +98,8 @@
"submenu": {
"auto-reset-app-cache": "ریست کردن حافظه کش برنامه هنگام شروع",
"disable-hardware-acceleration": "غیرفعال کردن شتاب سخت‌افزاری",
"edit-config-json": "ویرایش config.json",
"override-user-agent": "تغییر User-Agent",
"edit-config-json": "config.json ویرایش",
"override-user-agent": "User-Agent تغییر",
"restart-on-config-changes": "راه‌اندازی مجدد در صورت تغییرات در پیکربندی",
"set-proxy": {
"label": "تنظیم پراکسی",
@ -109,7 +109,7 @@
"title": "تنظیم پراکسی"
}
},
"toggle-dev-tools": "باز کردن DevTools"
"toggle-dev-tools": "DevTools باز کردن"
}
},
"always-on-top": "همیشه در بالا",
@ -168,7 +168,7 @@
},
"label": "تم",
"submenu": {
"import-css-file": "وارد کردن فایل CSS سفارشی",
"import-css-file": "سفارشی CSS وارد کردن فایل",
"no-theme": "بدون تم"
}
}
@ -177,7 +177,7 @@
}
},
"plugins": {
"enabled": "فعال",
"enabled": "فعال/غیرفعال کردن",
"label": "افزونه‌ها",
"new": "جدید"
},
@ -187,7 +187,7 @@
"force-reload": "اجبار به بارگذاری مجدد",
"reload": "بارگذاری مجدد",
"reset-zoom": "اندازه واقعی",
"toggle-fullscreen": "تغییر به تمام‌صفحه",
"toggle-fullscreen": "تغییر به تمام‌ صفحه",
"zoom-in": "بزرگنمایی",
"zoom-out": "کوچکنمایی"
}
@ -219,7 +219,7 @@
"name": "مسدودکننده تبلیغات"
},
"album-actions": {
"description": "افزودن دکمه‌های \"برگرفتن ناپسند\"، \"ناپسند\"، \"پسند\"، و \"حذف پسند\" برای اعمال آنها روی همه آهنگ‌ها در یک فهرست پخش یا آلبوم",
"description": "اضافه کردن دکمه‌های عدم پسندیدن، پسندیدن و لغو پسندیدن برای اعمال این تغییرات به تمامی آهنگ‌های یک فهرست پخش یا آلبوم",
"name": "عملیات آلبوم"
},
"album-color-theme": {
@ -250,7 +250,10 @@
}
},
"opacity": {
"label": "شفافیت"
"label": "شفافیت",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "کیفیت",
@ -259,7 +262,10 @@
}
},
"size": {
"label": "اندازه"
"label": "اندازه",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "انتقال نرمی",
@ -273,8 +279,15 @@
},
"name": "حالت محیطی"
},
"amuse": {
"description": "حالا ویجت Amuse از YouTube Music هم پشتیبانی می‌کنه! (توسط 6K Labs)",
"name": "Amuse",
"response": {
"query": "سرور Amuse فعال است. برای دریافت اطلاعات آهنگ، از آدرس /query استفاده کنید."
}
},
"api-server": {
"description": "افزودن یک سرور API برای کنترل پخش‌کننده",
"description": "برای کنترل پخش‌کننده API افزودن یک سرور",
"dialog": {
"request": {
"buttons": {
@ -304,14 +317,14 @@
"label": "پورت"
}
},
"name": "سرور API [بتا]",
"name": "[بتا]API سرور",
"prompt": {
"hostname": {
"label": "نام میزبان را برای سرور API وارد کنید (مثل 0.0.0.0):",
"label": "وارد کنید (مثل 0.0.0.0): API نام میزبان را برای سرور",
"title": "نام میزبان"
},
"port": {
"label": "پورت را برای سرور API وارد کنید:",
"label": "وارد کنید: API پورت را برای سرور",
"title": "پورت"
}
}
@ -321,8 +334,8 @@
"name": "فشرده‌ساز صدا"
},
"blur-nav-bar": {
"description": "شفاف و محو کردن نوار ناوبری",
"name": "محو کردن نوار ناوبری"
"description": "شفاف و محو کردن نوار کنترل",
"name": "محو کردن نوار کنترل"
},
"bypass-age-restrictions": {
"description": "دور زدن تأیید سن یوتیوب",
@ -381,27 +394,27 @@
},
"discord": {
"backend": {
"already-connected": "تلاش برای اتصال با اتصال فعال",
"connected": "متصل به Discord",
"disconnected": "قطع اتصال از Discord"
"already-connected": "تلاش برای برقراری ارتباط با اتصال فعال",
"connected": "متصل به دیسکورد",
"disconnected": "ارتباط با دیسکورد قطع شد"
},
"description": "نمایش آنچه گوش می‌دهید به دوستان با Rich Presence",
"description": "Rich Presence نمایش آنچه گوش می‌دهید به دوستان با",
"menu": {
"auto-reconnect": "اتصال خودکار مجدد",
"auto-reconnect": "اتصال خودکار",
"clear-activity": "پاک کردن فعالیت",
"clear-activity-after-timeout": "پاک کردن فعالیت پس از تایم‌اوت",
"connected": "متصل",
"disconnected": "قطع شده",
"clear-activity-after-timeout": "حذف فعالیت پس از اتمام زمان تعیین‌شده",
"connected": "اتصال برقرار شد",
"disconnected": "اتصال قطع شد",
"hide-duration-left": "مخفی کردن مدت زمان باقی‌مانده",
"hide-github-button": "مخفی کردن دکمه لینک GitHub",
"play-on-youtube-music": "پخش در یوتیوب موسیقی",
"set-inactivity-timeout": "تنظیم تایم‌اوت عدم فعالیت"
"hide-github-button": "مخفی کردن دکمه لینک گیت هاب",
"play-on-youtube-music": "پخش در یوتیوب موزیک",
"set-inactivity-timeout": "تنظیم زمان عدم فعالیت"
},
"name": "Rich Presence در Discord",
"name": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "ورود تایم‌اوت عدم فعالیت به ثانیه:",
"title": "تنظیم تایم‌اوت عدم فعالیت"
"label": "محدودیت زمان عدم فعالیت را به ثانیه وارد کنید:",
"title": "تنظیم زمان عدم فعالیت"
}
}
},
@ -478,6 +491,18 @@
"button": "دانلود"
}
},
"equalizer": {
"description": "اضافه کردن یک اکولایزر به پخش‌کننده",
"menu": {
"presets": {
"label": "تنظیمات از پیش تعیین شده",
"list": {
"bass-booster": "تقویت‌کننده باس صدا"
}
}
},
"name": "اکولایزر"
},
"exponential-volume": {
"description": "نوار لغزنده حجم را به صورت نمایی می‌سازد تا انتخاب حجم‌های پایین‌تر آسان‌تر شود.",
"name": "حجم نمایی"
@ -490,17 +515,17 @@
"name": "منوی داخل برنامه"
},
"lumiastream": {
"description": "افزودن پشتیبانی از Lumia Stream",
"description": "Lumia Stream افزودن پشتیبانی از",
"name": "Lumia Stream [بتا]"
},
"lyrics-genius": {
"description": "افزودن پشتیبانی از متن آهنگ برای بیشتر آهنگ‌ها",
"description": "افزودن متن ترانه پشتیبان برای اکثر ترانه ها",
"menu": {
"romanized-lyrics": "متن رومی‌شده"
"romanized-lyrics": "الفبای لاتین برای آهنگ‌هایی با الفبای شرقی (فینگلیش)"
},
"name": "متن آهنگ Genius",
"name": "Genius متن آهنگ",
"renderer": {
"fetched-lyrics": "متن آهنگ از Genius بازیابی شد"
"fetched-lyrics": "بازیابی شد Genius متن ترانه توسط"
}
},
"music-together": {
@ -536,13 +561,13 @@
"name": "Music Together [بتا]",
"toast": {
"add-song-failed": "افزودن آهنگ با شکست مواجه شد",
"closed": "Music Together بسته شد",
"disconnected": "قطع اتصال Music Together",
"host-failed": "میزبانی Music Together با شکست مواجه شد",
"closed": "بسته شد Music Together",
"disconnected": "Music Together قطع اتصال",
"host-failed": "با شکست مواجه شد Music Together میزبانی",
"id-copied": "شناسه میزبان به کلیپ‌بورد کپی شد",
"id-copy-failed": "کپی شناسه میزبان به کلیپ‌بورد با شکست مواجه شد",
"join-failed": "پیوستن به Music Together با شکست مواجه شد",
"joined": "به Music Together پیوست",
"join-failed": "با شکست مواجه شد Music Together پیوستن به",
"joined": "پیوست Music Together به",
"permission-changed": "مجوز Music Together به \"{{permission}}\" تغییر یافت",
"remove-song-failed": "حذف آهنگ با شکست مواجه شد",
"user-connected": "{{name}} به Music Together پیوست",
@ -551,11 +576,11 @@
},
"navigation": {
"description": "بعدی/قبلی به طور مستقیم در رابط یکپارچه شده‌اند، مانند مرورگر مورد علاقه شما",
"name": "ناوبری"
"name": "کنترل های رابط"
},
"no-google-login": {
"description": "حذف دکمه‌های ورود به سیستم Google و لینک‌ها از رابط",
"name": "بدون ورود به Google"
"description": "حذف دکمه‌ها و لینک‌های ورود به گوگل از رابط کاربری",
"name": "بدون ورود به گوگل"
},
"notifications": {
"description": "نمایش اعلان هنگامی که آهنگی شروع به پخش می‌کند (اعلان‌های تعاملی در ویندوز در دسترس هستند)",
@ -566,11 +591,11 @@
"submenu": {
"hide-button-text": "مخفی کردن متن دکمه",
"refresh-on-play-pause": "تازه‌سازی در پخش/توقف",
"tray-controls": "باز/بسته شدن با کلیک روی سینی"
"tray-controls": "باز/بسته شدن با کلیک روی آیکون در نوار وظیفه"
}
},
"priority": "اولویت اعلان",
"toast-style": "سبک Toast",
"toast-style": "Toast سبک",
"unpause-notification": "نمایش اعلان هنگام از سرگیری پخش"
},
"name": "اعلان‌ها"
@ -578,8 +603,234 @@
"picture-in-picture": {
"description": "اجازه می‌دهد تا برنامه به حالت تصویر در تصویر تغییر کند",
"menu": {
"always-on-top": "همیشه در بالا"
"always-on-top": "همیشه در بالا",
"hotkey": {
"label": "کلید میانبر",
"prompt": {
"keybind-options": {
"hotkey": "کلید میانبر"
},
"label": "یک کلید میانبر انتخاب کنید برای فعال/غیرفعال کردن حالت تصویر در تصویر",
"title": "کلید میانبر برای حالت تصویر در تصویر"
}
},
"save-window-position": "ذخیره موقعیت پنجره",
"save-window-size": "ذخیره اندازه پنجره",
"use-native-pip": "استفاده از حالت تصویر در تصویر اصلی مرورگر"
},
"name": "تصویر در تصویر",
"templates": {
"button": "تصویر در تصویر"
}
},
"playback-speed": {
"description": "به سرعت گوش بده، به آرامی گوش بده! یک دکمه کشویی برای تنظیم سرعت آهنگ اضافه شد",
"name": "سرعت پخش",
"templates": {
"button": "سرعت"
}
},
"precise-volume": {
"description": "کنترل دقیق صدا با استفاده از چرخ موس/میانبرها، همراه با HUD سفارشی و مراحل تنظیم حجم قابل تنظیم",
"menu": {
"arrows-shortcuts": "میانبرهای کلیدهای فلشی",
"custom-volume-steps": "مراحل تنظیم صدای دلخواه",
"global-shortcuts": "کلید های میانبر جهانی"
},
"name": "صدای دقیق",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "کاهش صدا",
"increase": "افزایش صدا"
},
"label": "انتخاب کلیدهای میانبر سراسری صدا:",
"title": "میانبرهای کلید سراسری صدا"
},
"volume-steps": {
"label": "مراحل انتخاب افزایش/کاهش صدا",
"title": "سطح صدا"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "کیفیت کنونی: {{quality}}",
"message": "انتخاب کیفیت ویدیو:",
"title": "انتخاب کیفیت ویدیو"
}
}
},
"description": "امکان تغییر کیفیت ویدیو با استفاده از دکمه در رابط پخش ویدیو",
"name": "تغییر دهنده کیفیت ویدیو"
},
"scrobbler": {
"description": "اضافه کردن پشتیبانی از اسکرابلینگ (etc. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "احراز هویت با Last.fm ناموفق بود\nپنجره شناور را تا راه‌اندازی مجدد بعدی مخفی کن.",
"title": "احراز هویت ناموفق بود"
}
}
},
"menu": {
"lastfm": {
"api-settings": "تنظیمات \"Last.fm \"API"
},
"listenbrainz": {
"token": "توکن کاربری ListenBrainz را وارد کنید"
},
"scrobble-other-media": "ردیابی رسانه‌های دیگر"
},
"name": "ابزار ثبت‌کننده‌ی آهنگ",
"prompt": {
"lastfm": {
"api-key": "کلید Last.fm API",
"api-secret": "API مخفی Last.fm"
},
"listenbrainz": {
"token": {
"label": "توکن کاربری ListenBrainz خود را وارد کنید:",
"title": "توکن ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "امکان تنظیم میانبرهای سراسری برای کنترل (پخش/توقف/بعدی/قبلی) و خاموش کردن OSD رسانه با بازنویسی کلیدهای رسانه‌ای، فعال‌سازی Ctrl/CMD + F برای جستجو، فعال‌سازی پشتیبانی MPRIS در لینوکس برای کلیدهای رسانه‌ای، و میانبرهای سفارشی برای کاربران پیشرفته",
"menu": {
"override-media-keys": "تغییر عملکرد کلیدهای رسانه‌",
"set-keybinds": "تنظیم کنترل‌های سراسری آهنگ"
},
"name": "میانبرها (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "بعدی",
"play-pause": "پخش / توقف",
"previous": "قبلی"
},
"label": "انتخاب میانبرهای سراسری برای کنترل آهنگ‌ها:",
"title": "میانبرهای کلیدی سراسری"
}
}
},
"skip-disliked-songs": {
"description": "خودکار آهنگ های غیر موردعلاقه رد میشن",
"name": "رد آهنگ‌های غیر مورد علاقه"
},
"skip-silences": {
"description": "رد خودکار بخش‌های بی صدا آهنگ ها",
"name": "رد بخش‌های بی‌صدا"
},
"sponsorblock": {
"description": "به‌طور خودکار بخش‌های غیرموسیقی مانند مقدمه/پایان یا قسمت‌هایی از ویدیوهای موسیقی که آهنگ در آن پخش نمی‌شود را رد می‌کند",
"name": "مسدودکننده اسپانسر"
},
"synced-lyrics": {
"description": "ارائه متن ترانه‌ها به صورت هماهنگ با آهنگ‌ها، با استفاده از ارائه‌دهندگانی مانند LRClib.",
"errors": {
"fetch": "⚠️هنگام بارگیری متن ترانه خطایی رخ داده است.\n\tلطفاً بعداً دوباره تلاش کنید.",
"not-found": "⚠️ متنی برای این ترانه پیدا نشد."
},
"menu": {
"default-text-string": {
"label": "حرف/کاراکتر پیش‌فرض بین متن‌های ترانه",
"tooltip": "حرف/کاراکتر پیش‌فرض را برای فاصله بین متن‌های ترانه انتخاب کنید"
},
"line-effect": {
"label": "افکت خط متن",
"submenu": {
"fancy": {
"label": "شیک",
"tooltip": "استفاده از افکت‌های بزرگ و شبیه به اپلیکیشن‌ها برای خط فعلی"
},
"focus": {
"label": "تمرکز",
"tooltip": "فقط خط فعلی رو سفید کن"
},
"offset": {
"label": "جابجایی",
"tooltip": "جابجایی خط فعلی به سمت راست"
},
"scale": {
"label": "مقیاس",
"tooltip": "تغییر اندازه خط فعلی"
}
},
"tooltip": "افکت مورد نظر را برای خط فعلی انتخاب کنید"
},
"precise-timing": {
"label": "هماهنگ‌سازی کامل متن ترانه‌",
"tooltip": "محاسبه دقیق نمایش خط بعدی تا میلی‌ثانیه (ممکن است تاثیر کمی بر عملکرد داشته باشد)"
},
"show-lyrics-even-if-inexact": {
"label": "نمایش متن ترانه ها حتی اگر دقیق نباشد",
"tooltip": "اگر آهنگ پیدا نشد، افزونه دوباره با یک جستجوی متفاوت امتحان می‌کند.\nنتیجهی این تلاش ممکن است دقیق نباشد."
},
"show-time-codes": {
"label": "نمایش زمان‌بندی‌ها",
"tooltip": "نمایش زمان‌بندی‌ها کنار متن ترانه‌"
}
},
"name": "متن ترانه هماهنگ شد",
"refetch-btn": {
"fetching": "در حال بارگذاری...",
"normal": "دریافت مجدد متن ترانه"
},
"warnings": {
"duration-mismatch": "⚠️ - ممکن است متن ترانه به دلیل عدم تطابق زمان با مشکل هماهنگی مواجه شود.",
"inexact": "⚠️ - ممکن است متن ترانه برای این آهنگ دقیق نباشد",
"instrumental": "⚠️ - این آهنگ بی کلام است"
}
},
"taskbar-mediacontrol": {
"description": "کنترل پخش از نوار وظیفه ویندوز(taskbar)",
"name": "کنترل رسانه از نوار وظیفه (taskbar)"
},
"touchbar": {
"description": "افزودن ویجت TouchBar برای کاربران macOS",
"name": "نوار لمسی"
},
"tuna-obs": {
"description": "ادغام با پلاگین Tuna در OBS",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "دکمه‌ای اضافه می‌کند برای جابجایی بین حالت ویدیو/آهنگ. همچنین به صورت اختیاری می‌تواند تب ویدیو را حذف کند",
"menu": {
"align": {
"label": "چینش",
"submenu": {
"left": "چپ",
"middle": "میانه",
"right": "راست"
}
},
"force-hide": "حذف اجباری تب ویدیو",
"mode": {
"label": "حالت",
"submenu": {
"custom": "حالت شخصی‌سازی شده",
"disabled": "غیرفعال",
"native": "حالت پیشفرض"
}
}
},
"name": "ویدیو به آهنگ",
"templates": {
"button": "ترانه"
}
},
"visualizer": {
"description": "اضافه کردن نمایش‌دهنده تصویری به پخش‌کننده",
"menu": {
"visualizer-type": "نوع نمایش‌دهنده تصویری"
},
"name": "نمایش‌دهنده تصویری"
}
}
}

View File

@ -279,6 +279,12 @@
},
"name": "Ambient Mode"
},
"amuse": {
"description": "Nagdaragdag ng suporta sa YouTube Music para sa Amuse now playing widget ng 6K Labs",
"response": {
"query": "Tumatakbo ang Amuse API server. Gamitin ang GET /query para makuha ang impo ng kanta."
}
},
"api-server": {
"description": "Nagdadagdag ng API Server upang kontrolin ang player",
"dialog": {
@ -468,6 +474,14 @@
"button": "Mag-download"
}
},
"equalizer": {
"description": "Nagdaragdag ng equalizer sa player",
"menu": {
"presets": {
"label": "Mga Preset"
}
}
},
"exponential-volume": {
"description": "Ginagawang exponential ang volume slider para mas madaling pumili ng mas mababang volume."
},
@ -674,8 +688,8 @@
"synced-lyrics": {
"description": "Nagbibigay ng naka-sync na lyrics sa mga kanta, gamit ang mga provider tulad ng LRClib.",
"errors": {
"fetch": "⚠️ - Nagkaroon ng error habang kinukuha ang lyrics. Subukang muli mamaya.",
"not-found": "⚠️ - Walang nakitang lyrics para sa kantang ito."
"fetch": "⚠️\t Nagkaroon ng error habang kinukuha ang lyrics.\n\t Subukang muli mamaya.",
"not-found": "⚠️ Walang nakitang lyrics para sa kantang ito."
},
"menu": {
"default-text-string": {
@ -685,6 +699,10 @@
"line-effect": {
"label": "Effect ng Linya",
"submenu": {
"fancy": {
"label": "Magarbo",
"tooltip": "Gumamit ng malaki, mala-app na effect sa kasalukuyang linya"
},
"focus": {
"tooltip": "Gawing puti lamang ang kasalukuyang linya"
},

View File

@ -53,7 +53,8 @@
"later": "אחר כך",
"restart-now": "מתחיל את התוכנה מחדש עכשיו"
},
"message": "נדרש אתחול",
"detail": "\"{{pluginName}}\" מצריך אתחול",
"message": "\"{{pluginName}}\" דורש אתחול",
"title": "נדרשת הפעלה מחדש"
},
"unresponsive": {
@ -70,9 +71,10 @@
"buttons": {
"disable": "בטל עדכונים",
"download": "הורדה",
"ok": "אוקי"
"ok": "אוקיי"
},
"message": ירסא חדשה זמינה כעת",
"detail": "גרסה חדשה זמינה, ניתן להוריד אותה ב-{{downloadLink}}",
"message": "גירסה חדשה זמינה כעת",
"title": "קיים עדכון חדש"
}
},

View File

@ -226,10 +226,50 @@
"description": "एल्बम रंग पैलेट के आधार पर एक गतिशील थीम और दृश्य प्रभाव लागू करता है",
"menu": {
"color-mix-ratio": {
"label": "रंग मिश्रण अनुपात",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "एल्बम रंग थीम"
},
"ambient-mode": {
"description": "वीडियो से हल्के रंगों को आपकी स्क्रीन की पृष्ठभूमि में डालकर एक प्रकाश प्रभाव लागू करता है",
"menu": {
"blur-amount": {
"label": "धुंधलापन मात्रा",
"submenu": {
"pixels": "{{blurAmount}} पिक्सल"
}
},
"buffer": {
"label": "बफर",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "अस्पष्टता",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "गुणवत्ता",
"submenu": {
"pixels": "{{quality}} पिक्सल"
}
},
"size": {
"label": "माप",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "चिकनाई संक्रमण"
}
}
},
"video-toggle": {

View File

@ -279,6 +279,13 @@
},
"name": "Mode ambient"
},
"amuse": {
"description": "Menambahkan dukungan YouTube Music untuk widget Amuse yang sedang diputar oleh 6K Labs",
"name": "Amuse",
"response": {
"query": "Server API Amuse sedang berjalan. GET /query untuk mendapatkan info lagu."
}
},
"api-server": {
"description": "Menambahkan server API untuk mengontrol pemutar",
"dialog": {
@ -726,8 +733,8 @@
"synced-lyrics": {
"description": "Menyediakan lirik lagu yang disinkronkan, menggunakan penyedia seperti LRClib.",
"errors": {
"fetch": "⚠️ - Terjadi kesalahan saat mengambil lirik. Coba lagi nanti.",
"not-found": "⚠️ - Tidak ada lirik yang ditemukan untuk lagu ini."
"fetch": "⚠️\tTerjadi kesalahan saat mengambil lirik.\n\tSilakan coba lagi nanti.",
"not-found": "⚠️ Tidak ada lirik yang ditemukan untuk lagu ini."
},
"menu": {
"default-text-string": {
@ -737,6 +744,10 @@
"line-effect": {
"label": "Efek garis",
"submenu": {
"fancy": {
"label": "Mewah",
"tooltip": "Gunakan efek besar seperti aplikasi pada baris saat ini"
},
"focus": {
"label": "Fokus",
"tooltip": "Jadikan hanya baris saat ini berwarna putih"

View File

@ -279,6 +279,12 @@
},
"name": "Chế độ Môi trường xung quanh"
},
"amuse": {
"name": "Amuse",
"response": {
"query": "Máy chủ API của Amuse đang chạy. GET /query để lấy thông tin về bài hát."
}
},
"api-server": {
"description": "Thêm máy chủ API để điều khiển trình phát",
"dialog": {
@ -299,7 +305,7 @@
"label": "Xác thực ngay yêu cầu đầu tiên"
},
"none": {
"label": "Không/Chưa xác thực (Need context)"
"label": "Không xác thực"
}
}
},

View File

@ -134,14 +134,6 @@ if (is.linux()) {
// Overrides WM_CLASS for X11 to correspond to icon filename
app.setName('com.github.th_ch.youtube_music');
// Workaround for issue #2248
if (
process.env.XDG_SESSION_TYPE === 'wayland' ||
process.env.WAYLAND_DISPLAY
) {
app.commandLine.appendSwitch('disable-gpu-memory-buffer-video-frames');
}
// Stops chromium from launching its own MPRIS service
if (config.plugins.isEnabled('shortcuts')) {
app.commandLine.appendSwitch('disable-features', 'MediaSessionService');

View File

@ -1,5 +1,5 @@
import { FastAverageColor } from 'fast-average-color';
import Color from 'color';
import Color, { ColorInstance } from 'color';
import style from './style.css?inline';
@ -14,8 +14,8 @@ export default createPlugin<
unknown,
unknown,
{
color?: Color;
darkColor?: Color;
color?: ColorInstance;
darkColor?: ColorInstance;
playerPage: HTMLElement | null;
navBarBackground: HTMLElement | null;

View File

@ -154,15 +154,14 @@ export const backend = createBackend<
// @see https://discord.com/developers/docs/topics/gateway#activity-object
// not all options are transfered through https://github.com/discordjs/RPC/blob/6f83d8d812c87cb7ae22064acd132600407d7d05/src/client.js#L518-530
const hangulFillerUnicodeCharacter = '\u3164'; // This is an empty character
if (songInfo.title.length < 2) {
songInfo.title += hangulFillerUnicodeCharacter.repeat(
2 - songInfo.title.length,
);
}
if (songInfo.artist.length < 2) {
songInfo.artist += hangulFillerUnicodeCharacter.repeat(
2 - songInfo.title.length,
);
const paddedInfoKeys: (keyof SongInfo)[] = ['title', 'artist', 'album'];
for (const key of paddedInfoKeys) {
const keyLength = (songInfo[key] as string)?.length;
if (keyLength < 2) {
(songInfo[key] as string) += hangulFillerUnicodeCharacter.repeat(
2 - keyLength,
);
}
}
// see https://github.com/th-ch/youtube-music/issues/1664

View File

@ -55,10 +55,20 @@ let yt: Innertube;
let win: BrowserWindow;
let playingUrl: string;
const isYouTubePremium = () =>
win.webContents.executeJavaScript(
'!document.querySelector(\'#endpoint[href="/music_premium"]\')',
) as Promise<boolean>;
const isYouTubeMusicPremium = async () => {
const upgradeBtnIconPathData = (await win.webContents.executeJavaScript(
'document.querySelector(\'iron-iconset-svg[name="yt-sys-icons"] #youtube_music_monochrome\')?.firstChild?.getAttribute("d")?.substring(0, 15)',
)) as string | null;
// Fallback to non-premium if the icon is not found
if (!upgradeBtnIconPathData) return false;
const selector = `ytmusic-guide-entry-renderer:has(> tp-yt-paper-item > yt-icon path[d^="${upgradeBtnIconPathData}"])`;
return (await win.webContents.executeJavaScript(
`!document.querySelector('${selector}')`,
)) as boolean;
};
const sendError = (error: Error, source?: string) => {
win.setProgressBar(-1); // Close progress bar
@ -116,6 +126,11 @@ export const onMainLoad = async ({
const visitorData = yt.session.context.client.visitorData;
if (visitorData) {
const cleanUp = (context: Partial<typeof globalThis>) => {
delete context.window;
delete context.document;
};
try {
const [width, height] = win.getSize();
// emulate jsdom using linkedom
@ -153,16 +168,16 @@ export const onMainLoad = async ({
program: bgChallenge.program,
globalName: bgChallenge.globalName,
bgConfig,
}).finally(() => {
cleanUp(globalThis);
});
yt.session.po_token = poTokenResult.poToken;
} else {
cleanUp(globalThis);
}
} finally {
// Bypass TypeScript checks
((x: Partial<typeof globalThis>) => {
delete x.window;
delete x.document;
})(globalThis);
} catch {
cleanUp(globalThis);
}
}
@ -365,7 +380,7 @@ async function downloadSongUnsafe(
}
const downloadOptions: FormatOptions = {
type: (await isYouTubePremium()) ? 'audio' : 'video+audio', // Audio, video or video+audio
type: (await isYouTubeMusicPremium()) ? 'audio' : 'video+audio', // Audio, video or video+audio
quality: 'best', // Best, bestefficiency, 144p, 240p, 480p, 720p and so on.
format: 'any', // Media container format
};

View File

@ -14,7 +14,7 @@
align-items: center;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
margin: 0 var(--ytd-rich-grid-item-margin);
margin: 0 var(--ytd-margin-2x, 8px);
}
.navigation-item:hover {
@ -32,4 +32,5 @@
width: var(--iron-icon-width, 24px);
height: var(--iron-icon-height, 24px);
animation: var(--iron-icon_-_animation);
padding: var(--ytd-margin-base, 4px) var(--ytd-margin-2x, 8px);
}

View File

@ -50,7 +50,7 @@ export const SyncedLine = ({ line }: SyncedLineProps) => {
_ytAPI?.seekTo(line.timeInMs / 1000);
}}
>
<div class="text-lyrics description ytmusic-description-shelf-renderer">
<div dir="auto" class="text-lyrics description ytmusic-description-shelf-renderer">
<yt-formatted-string
text={{
runs: [{ text: config()?.showTimeCodes ? `[${line.time}] ` : '' }],

View File

@ -71,7 +71,7 @@ export function throttle<T extends (...params: unknown[]) => unknown>(
}) as T;
}
function memoize<T extends (...params: unknown[]) => unknown>(fn: T): T {
export function memoize<T extends (...params: unknown[]) => unknown>(fn: T): T {
const cache = new Map();
return ((...args) => {
@ -84,7 +84,7 @@ function memoize<T extends (...params: unknown[]) => unknown>(fn: T): T {
}) as T;
}
function retry<T extends (...params: unknown[]) => Promise<unknown>>(
export function retry<T extends (...params: unknown[]) => Promise<unknown>>(
fn: T,
{ retries = 3, delay = 1000 } = {},
) {
@ -102,12 +102,3 @@ function retry<T extends (...params: unknown[]) => Promise<unknown>>(
throw latestError;
};
}
export default {
singleton,
debounce,
cache,
throttle,
memoize,
retry,
};

View File

@ -7,15 +7,15 @@ import { Project } from 'ts-morph';
const snakeToCamel = (text: string) =>
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase());
export const i18nImporter = () => {
const __dirname = dirname(fileURLToPath(import.meta.url));
const project = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
const __dirname = dirname(fileURLToPath(import.meta.url));
const globalProject = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
export const i18nImporter = () => {
const srcPath = resolve(__dirname, '..', 'src');
const plugins = globSync(['src/i18n/resources/*.json']).map((path) => {
const nameWithExt = basename(path);
@ -24,24 +24,28 @@ export const i18nImporter = () => {
return { name, path };
});
const src = project.createSourceFile('vm:i18n', (writer) => {
// prettier-ignore
for (const { name, path } of plugins) {
const src = globalProject.createSourceFile(
'vm:i18n',
(writer) => {
// prettier-ignore
for (const { name, path } of plugins) {
const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/');
writer.writeLine(`import ${snakeToCamel(name)}Json from "./${relativePath}";`);
}
writer.blankLine();
writer.blankLine();
writer.writeLine('export const languageResources = {');
for (const { name } of plugins) {
writer.writeLine(` "${name}": {`);
writer.writeLine(` translation: ${snakeToCamel(name)}Json,`);
writer.writeLine(' },');
}
writer.writeLine('};');
writer.blankLine();
});
writer.writeLine('export const languageResources = {');
for (const { name } of plugins) {
writer.writeLine(` "${name}": {`);
writer.writeLine(` translation: ${snakeToCamel(name)}Json,`);
writer.writeLine(' },');
}
writer.writeLine('};');
writer.blankLine();
},
{ overwrite: true },
);
return src.getText();
};

View File

@ -7,17 +7,17 @@ import { Project } from 'ts-morph';
const snakeToCamel = (text: string) =>
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase());
const __dirname = dirname(fileURLToPath(import.meta.url));
const globalProject = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
export const pluginVirtualModuleGenerator = (
mode: 'main' | 'preload' | 'renderer',
) => {
const __dirname = dirname(fileURLToPath(import.meta.url));
const project = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
const srcPath = resolve(__dirname, '..', 'src');
const plugins = globSync([
'src/plugins/*/index.{js,ts}',
@ -35,35 +35,39 @@ export const pluginVirtualModuleGenerator = (
return { name, path };
});
const src = project.createSourceFile('vm:pluginIndexes', (writer) => {
// prettier-ignore
for (const { name, path } of plugins) {
const src = globalProject.createSourceFile(
'vm:pluginIndexes',
(writer) => {
// prettier-ignore
for (const { name, path } of plugins) {
const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/');
writer.writeLine(`import ${snakeToCamel(name)}Plugin, { pluginStub as ${snakeToCamel(name)}PluginStub } from "./${relativePath}";`);
}
writer.blankLine();
writer.blankLine();
// Context-specific exports
writer.writeLine(`export const ${mode}Plugins = {`);
for (const { name } of plugins) {
const checkMode = mode === 'main' ? 'backend' : mode;
// HACK: To avoid situation like importing renderer plugins in main
writer.writeLine(
` ...(${snakeToCamel(name)}Plugin['${checkMode}'] ? { "${name}": ${snakeToCamel(name)}Plugin } : {}),`,
);
}
writer.writeLine('};');
writer.blankLine();
// Context-specific exports
writer.writeLine(`export const ${mode}Plugins = {`);
for (const { name } of plugins) {
const checkMode = mode === 'main' ? 'backend' : mode;
// HACK: To avoid situation like importing renderer plugins in main
writer.writeLine(
` ...(${snakeToCamel(name)}Plugin['${checkMode}'] ? { "${name}": ${snakeToCamel(name)}Plugin } : {}),`,
);
}
writer.writeLine('};');
writer.blankLine();
// All plugins export (stub only) // Omit<Plugin, 'backend' | 'preload' | 'renderer'>
writer.writeLine('export const allPlugins = {');
for (const { name } of plugins) {
writer.writeLine(` "${name}": ${snakeToCamel(name)}PluginStub,`);
}
writer.writeLine('};');
writer.blankLine();
});
// All plugins export (stub only) // Omit<Plugin, 'backend' | 'preload' | 'renderer'>
writer.writeLine('export const allPlugins = {');
for (const { name } of plugins) {
writer.writeLine(` "${name}": ${snakeToCamel(name)}PluginStub,`);
}
writer.writeLine('};');
writer.blankLine();
},
{ overwrite: true },
);
return src.getText();
};

View File

@ -1,4 +1,4 @@
import { readFile } from 'node:fs/promises';
import { readFileSync } from 'node:fs';
import { resolve, basename, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
@ -8,10 +8,34 @@ import {
ts,
ObjectLiteralExpression,
VariableDeclarationKind,
Node,
type ObjectLiteralElementLike,
} from 'ts-morph';
import type { PluginOption } from 'vite';
// Initialize a global project instance to reuse across load calls
const __dirname = dirname(fileURLToPath(import.meta.url));
const globalProject = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
// Helper to extract a propertys name from its node
const getPropertyName = (prop: Node): string | null => {
const kind = prop.getKind();
if (
kind === ts.SyntaxKind.PropertyAssignment ||
kind === ts.SyntaxKind.ShorthandPropertyAssignment ||
kind === ts.SyntaxKind.MethodDeclaration
) {
return prop.getFirstChildByKindOrThrow(ts.SyntaxKind.Identifier).getText();
}
return null;
};
export default function (
mode: 'backend' | 'preload' | 'renderer' | 'none',
): PluginOption {
@ -22,131 +46,96 @@ export default function (
return {
name: 'ytm-plugin-loader',
async load(id) {
load(id) {
if (!pluginFilter(id)) return null;
const __dirname = dirname(fileURLToPath(import.meta.url));
const project = new Project({
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'),
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
const src = project.createSourceFile(
// Read file asynchronously
const fileContent = readFileSync(id, 'utf8');
// Create or update source file in the global project instance
const src = globalProject.createSourceFile(
'_pf' + basename(id),
await readFile(id, 'utf8'),
fileContent,
{ overwrite: true },
);
const exports = src.getExportedDeclarations();
let objExpr: ObjectLiteralExpression | undefined = undefined;
let objExpr: ObjectLiteralExpression | undefined;
for (const [name, [expr]] of exports) {
if (name !== 'default') continue;
switch (expr.getKind()) {
case ts.SyntaxKind.ObjectLiteralExpression: {
objExpr = expr.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
break;
}
case ts.SyntaxKind.CallExpression: {
const callExpr = expr.asKindOrThrow(ts.SyntaxKind.CallExpression);
if (callExpr.getArguments().length !== 1) continue;
const name = callExpr.getExpression().getText();
if (name !== 'createPlugin') continue;
// Identify the default export as an object literal, or via a 'createPlugin' call
for (const [exportName, declarations] of exports) {
if (exportName !== 'default') continue;
const expr = declarations[0];
const exprKind = expr.getKind();
if (exprKind === ts.SyntaxKind.ObjectLiteralExpression) {
objExpr = expr.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
break;
} else if (exprKind === ts.SyntaxKind.CallExpression) {
const callExpr = expr.asKindOrThrow(ts.SyntaxKind.CallExpression);
if (
callExpr.getArguments().length === 1 &&
callExpr.getExpression().getText() === 'createPlugin'
) {
const arg = callExpr.getArguments()[0];
if (arg.getKind() !== ts.SyntaxKind.ObjectLiteralExpression)
continue;
objExpr = arg.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
break;
if (arg.getKind() === ts.SyntaxKind.ObjectLiteralExpression) {
objExpr = arg.asKindOrThrow(
ts.SyntaxKind.ObjectLiteralExpression,
);
break;
}
}
}
}
if (!objExpr) return null;
const properties = objExpr.getProperties();
const propertyNames = properties.map((prop) => {
switch (prop.getKind()) {
case ts.SyntaxKind.PropertyAssignment:
return prop
.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
.getName();
case ts.SyntaxKind.ShorthandPropertyAssignment:
return prop
.asKindOrThrow(ts.SyntaxKind.ShorthandPropertyAssignment)
.getName();
case ts.SyntaxKind.MethodDeclaration:
return prop
.asKindOrThrow(ts.SyntaxKind.MethodDeclaration)
.getName();
default:
throw new Error('Not implemented');
}
});
// Build a map of property names to their AST nodes for fast lookup
const propMap = new Map<string, ObjectLiteralElementLike>();
for (const prop of objExpr.getProperties()) {
const name = getPropertyName(prop);
if (name) propMap.set(name, prop);
}
const contexts = ['backend', 'preload', 'renderer', 'menu'];
for (const ctx of contexts) {
if (mode === 'none') {
const index = propertyNames.indexOf(ctx);
if (index === -1) continue;
objExpr.getProperty(propertyNames[index])?.remove();
if (mode === 'none' && propMap.has(ctx)) {
propMap.get(ctx)?.remove();
continue;
}
if (ctx === mode) continue;
if (ctx === 'menu' && mode === 'backend') continue;
const index = propertyNames.indexOf(ctx);
if (index === -1) continue;
objExpr.getProperty(propertyNames[index])?.remove();
if (ctx === mode || (ctx === 'menu' && mode === 'backend')) continue;
if (propMap.has(ctx)) propMap.get(ctx)?.remove();
}
const stubObjExpr = src
.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'pluginStub',
initializer: (writer) => writer.write(objExpr.getText()),
},
],
})
.getDeclarations()[0]
.getInitializer() as ObjectLiteralExpression;
const stubProperties = stubObjExpr.getProperties();
const stubPropertyNames = stubProperties.map((prop) => {
switch (prop.getKind()) {
case ts.SyntaxKind.PropertyAssignment:
return prop
.asKindOrThrow(ts.SyntaxKind.PropertyAssignment)
.getName();
case ts.SyntaxKind.ShorthandPropertyAssignment:
return prop
.asKindOrThrow(ts.SyntaxKind.ShorthandPropertyAssignment)
.getName();
case ts.SyntaxKind.MethodDeclaration:
return prop
.asKindOrThrow(ts.SyntaxKind.MethodDeclaration)
.getName();
default:
throw new Error('Not implemented');
}
// Add an exported variable 'pluginStub' with the modified object literal's text
const varStmt = src.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: 'pluginStub',
initializer: (writer) => writer.write(objExpr.getText()),
},
],
});
const stubObjExpr = varStmt
.getDeclarations()[0]
.getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
if (mode === 'backend') contexts.pop();
for (const ctx of contexts) {
const index = stubPropertyNames.indexOf(ctx);
if (index === -1) continue;
// Similarly build a map for the stub properties
const stubMap = new Map<string, ObjectLiteralElementLike>();
for (const prop of stubObjExpr.getProperties()) {
const name = getPropertyName(prop);
if (name) stubMap.set(name, prop);
}
stubObjExpr.getProperty(stubPropertyNames[index])?.remove();
const stubContexts =
mode === 'backend'
? contexts.filter((ctx) => ctx !== 'menu')
: contexts;
for (const ctx of stubContexts) {
if (stubMap.has(ctx)) {
stubMap.get(ctx)?.remove();
}
}
return {