Compare commits

...

267 Commits

Author SHA1 Message Date
8e21a10214 Bump version to 3.8.0 2025-03-26 20:51:20 +09:00
f787c2cc80 chore(deps): update dependency typescript-eslint to v8.28.0 (#3128)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:47:08 +09:00
ebf91f0977 chore(deps): update dependency eslint-plugin-prettier to v5.2.5 (#3123)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:45:53 +09:00
cae6d858fa fix(deps): update dependency @hono/node-server to v1.14.0 (#3131)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:45:09 +09:00
37f3e9ce89 chore(deps): update dependency electron to v35.1.0 (#3136)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:44:36 +09:00
f350fd7aae fix(deps): update dependency es-hangul to v2.3.2 (#3138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:44:23 +09:00
67b001c6a0 chore(deps): update dependency eslint-import-resolver-typescript to v4.2.4 (#3135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:44:10 +09:00
ccbe5da684 chore(deps): update eslint monorepo to v9.23.0 (#3130)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:41:07 +09:00
e3e5ae3a7f chore(deps): update dependency electron-vite to v3.1.0 (#3137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:40:43 +09:00
972c3dba2f chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (411 of 411 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2025-03-26 12:37:47 +01:00
b61151b2bd chore(deps): update dependency @babel/runtime to v7.27.0 (#3127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 20:34:32 +09:00
4b35a96778 feat(synced-lyrics): romanization (#2790)
* feat(synced-lyrics): init romanization!

* remove debug logs and add TODO

* feat(synced-lyrics/romanization): Mandarin!

* feat(synced-lyrics/romanization): improve japanese detection

* feat(synced-lyrics/romanization): Korean!

* qol(synced-lyrics/romanization): canonicalize punctuation and symbols

* feat(synced-lyrics/romanization): handle japanese+korean and korean+chinese lyrics

* revert formatting on electron.vite.config.mts

* feat(synced-lyrics/romanization): romanize plain lyrics

* apply fix by @kimjammer

* fix lockfile due to rebase

* feat(synced-lyrics): improve lyric processing and formatting;

* feat(synced-lyrics/romanization): add option to enable/disable romanization

* chore: move default value for --lyrics-duration to the declaration

* update lockfile

* fix: improvement

1. improved language detection logic
2. changed code to work in the renderer process

* fix: fix regression (canonicalize)

---------

Co-authored-by: JellyBrick <shlee1503@naver.com>
2025-03-26 20:29:43 +09:00
19fd0d61c6 feat(plugin): add unobtrusive player plugin (#3104)
* feat(plugin): add unobtrusive player plugin

* fix(plugin): add removeEventListener once unobtrusive-player is disabled

* feat(plugin): prevent player page button animation when changing song

* fix(plugin): add removeEventListener for videodatachange once unobtrusive-player is disabled
2025-03-26 19:36:42 +09:00
77779938b9 chore(deps): update dependency vite to v6.2.3 [security] (#3134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 13:24:04 +09:00
bb06d71fbb fix(deps): update dependency youtubei.js to v13.3.0 (#3133)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-26 13:22:11 +09:00
3cf955179d chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (407 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2025-03-25 13:11:19 +01:00
606dd5a679 chore(deps): update dependency electron-builder-squirrel-windows to v26.0.12 (#3122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:26:42 +09:00
31fe07ebd4 chore(deps): update dependency eslint-import-resolver-typescript to v4.2.2 (#3106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:23:50 +09:00
d456d0db89 chore(deps): update dependency electron-builder to v26.0.12 (#3121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:23:30 +09:00
Tix
e00c357fae fix: Discord Rich Presence Fix (#3074)
* discord presence fix

* Update src/plugins/discord/main.ts

Co-authored-by: JellyBrick <shlee1503@naver.com>

* variable length support

---------

Co-authored-by: JellyBrick <shlee1503@naver.com>
2025-03-24 13:20:50 +09:00
21b54ef6ff fix(deps): update dependency @xhayper/discord-rpc to v1.2.1 (#3107)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:20:21 +09:00
f96b650787 chore(deps): update dependency typescript-eslint to v8.27.0 (#3111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:19:01 +09:00
ebbbf2a6b9 chore(deps): update dependency electron to v35.0.3 (#3112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:18:54 +09:00
610ad59fdc fix(deps): update dependency hono to v4.7.5 (#3113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:18:46 +09:00
4fe302d753 fix(deps): update dependency fast-average-color to v9.5.0 (#3114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:18:38 +09:00
5983ae47bb chore(deps): update dependency rollup to v4.37.0 (#3103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-24 13:18:28 +09:00
4442fc12ec chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 22.3% (91 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-03-23 21:15:39 +01:00
b42de1c458 chore(i18n): Translated using Weblate (Swedish)
Currently translated at 19.9% (81 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sv/
2025-03-22 16:28:39 +01:00
eec5a2352e chore(i18n): Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (407 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2025-03-22 16:28:38 +01:00
303de7c0aa chore(i18n): Translated using Weblate (Italian)
Currently translated at 99.5% (405 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2025-03-22 04:41:58 +01:00
4bc57c2628 chore(i18n): Translated using Weblate (German)
Currently translated at 100.0% (407 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2025-03-19 17:35:05 +01:00
c74505ac90 chore(deps): update playwright monorepo to v1.51.1 (#3105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 13:19:35 +09:00
7a3a803d72 chore(deps): update dependency eslint-import-resolver-typescript to v4 (#3102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-18 13:19:18 +09:00
fec010c73f chore(i18n): Translated using Weblate (Georgian)
Currently translated at 20.1% (82 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ka/
2025-03-18 04:51:11 +01:00
b093cc2c08 chore(deps): update dependency electron to v35.0.2 (#3099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:16:38 +09:00
cb3cd74e9e fix(deps): update dependency i18next to v24.2.3 (#3100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:14:01 +09:00
ae5b8038b2 chore(deps): update dependency electron-builder to v26.0.11 (#3095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:13:28 +09:00
5f93c96901 chore(deps): update dependency @babel/runtime to v7.26.10 [security] (#3094)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:04:02 +09:00
ec81ac5e40 chore(deps): update dependency eslint-config-prettier to v10.1.1 (#3069)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:03:52 +09:00
8901a7768d chore(deps): update playwright monorepo to v1.51.0 (#3065)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:03:43 +09:00
22f14cce3e chore(deps): update dependency electron-builder-squirrel-windows to v26.0.11 (#3096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:03:32 +09:00
4afb2276c1 chore(deps): update dependency esbuild to v0.25.1 (#3097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:03:23 +09:00
77658035f5 chore(deps): update dependency typescript-eslint to v8.26.1 (#3098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 03:03:12 +09:00
07aa9d5811 chore(i18n): Translated using Weblate (Russian)
Currently translated at 100.0% (407 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2025-03-16 02:48:57 +01:00
7764bcabde chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 100.0% (407 of 407 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2025-03-15 23:23:53 +01:00
69058a52ed chore(deps): update eslint monorepo to v9.22.0 (#3070)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-16 02:49:55 +09:00
1f7acbd219 chore(deps): update dependency rollup to v4.35.0 (#3071)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-16 02:49:41 +09:00
88dfaa98f3 chore(deps): update dependency electron to v35.0.1 (#3075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-16 02:49:05 +09:00
504829f065 fix(deps): update dependency happy-dom to v17.4.4 (#3068)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-16 02:48:49 +09:00
e4e6dcb0cd chore(deps): update dependency vite to v6.2.2 (#3067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-16 02:48:34 +09:00
78010793fb fix: Update winget-releaser version to main (#3091) 2025-03-16 02:45:10 +09:00
bcdd24d74b feat: Allow scrobbling using alternative song titles (#3093) 2025-03-16 02:42:58 +09:00
2d86d26701 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-03-14 06:19:21 +01:00
77ca2b483f chore(i18n): Translated using Weblate (Portuguese)
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/pt/
2025-03-14 06:19:21 +01:00
13c71e8904 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-14 01:14:08 +01:00
3bfb853414 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-13 23:53:15 +01:00
25454689c0 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-13 20:14:57 +01:00
Tux
dd3e42c41e chore(i18n): Translated using Weblate (Swedish)
Currently translated at 14.2% (58 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sv/
2025-03-13 12:27:52 +01:00
499ae2422c chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-13 12:27:52 +01:00
a3601cece6 chore(i18n): Translated using Weblate (Tamil)
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/ta/
2025-03-13 05:49:12 +01:00
8168666720 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-13 03:08:32 +01:00
9f580a1d7d chore(i18n): Translated using Weblate (Bulgarian)
Currently translated at 25.8% (105 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/bg/
2025-03-12 18:59:47 +01:00
f8765fbdbb chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 98.0% (398 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-12 18:59:47 +01:00
2922a457cd chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 95.3% (387 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-12 09:50:43 +01:00
c2e4c32745 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 95.3% (387 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2025-03-12 03:04:16 +01:00
5071183550 chore(i18n): Translated using Weblate (Nepali)
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/ne/
2025-03-11 09:51:11 +01:00
db736bcb23 chore(i18n): Translated using Weblate (Finnish)
Currently translated at 72.4% (294 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fi/
2025-03-10 15:36:08 +01:00
fb29d62cf1 chore(i18n): Added translation using Weblate (Tamil) 2025-03-09 15:41:59 +01:00
28f5185d38 chore(i18n): Translated using Weblate (French)
Currently translated at 99.7% (405 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2025-03-07 21:51:42 +01:00
c9178985f2 chore(i18n): Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/
2025-03-07 08:00:03 +01:00
297b94bdab chore(i18n): Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.5% (400 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2025-03-07 08:00:02 +01:00
dbf8b1c5c5 chore(i18n): Translated using Weblate (Spanish)
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/es/
2025-03-06 23:04:01 +01:00
cec6339f9a chore(i18n): Translated using Weblate (Hindi)
Currently translated at 33.9% (138 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hi/
2025-03-06 14:02:43 +01:00
e7edf30717 chore(deps): update dependency electron-builder-squirrel-windows to v26.0.10 (#3054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 11:37:54 +09:00
441be69ca5 chore(deps): update dependency typescript-eslint to v8.26.0 (#3056)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 07:12:00 +09:00
2199391ec1 fix(deps): update dependency hono to v4.7.4 (#3062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 07:11:51 +09:00
f43daa3805 chore(deps): update dependency electron-builder to v26.0.10 (#3053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 07:11:24 +09:00
b4dc2ca88f chore(deps): update dependency electron to v35 (#3058)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 08:55:02 +09:00
4aae0d89cd fix(deps): update dependency happy-dom to v17.2.2 (#3060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 08:53:38 +09:00
7c1eec03a5 fix(deps): update dependency happy-dom to v17.1.13 (#3057)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 08:50:09 +09:00
06aaba0c7f chore(i18n): Translated using Weblate (Arabic)
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/ar/
2025-03-04 17:02:32 +01:00
766268d9e4 chore(deps): update dependency typescript to v5.8.2 (#3040)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 22:48:37 +09:00
a7f47001c6 chore(deps): update dependency rollup to v4.34.9 (#3043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 22:42:29 +09:00
104850e9b0 fix(deps): update dependency @hono/swagger-ui to v0.5.1 (#3045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 22:42:15 +09:00
3139beec91 fix: added French link in general README file (#3047)
* fix: updated readme with fr link in general readme

* fix: updated all the other README files
2025-03-03 22:42:00 +09:00
30bc676fd2 fix(deps): update dependency @hono/zod-openapi to v0.19.2 (#3046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 22:34:33 +09:00
c2cf5992f8 chore(deps): update dependency @stylistic/eslint-plugin-js to v4.2.0 (#3050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 22:34:06 +09:00
50b265c3ea fix(deps): update dependency bgutils-js to v3.2.0 (#3049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-03 18:04:16 +09:00
b6cf7070bf chore(i18n): Translated using Weblate (Arabic)
Currently translated at 72.1% (293 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ar/
2025-03-03 08:06:51 +01:00
06f20cc84c chore(i18n): Translated using Weblate (French)
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/fr/
2025-03-03 08:06:50 +01:00
7453a5a06c chore(i18n): Translated using Weblate (French)
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/fr/
2025-03-03 08:06:50 +01:00
de1ccd80fc chore(i18n): Translated using Weblate (Arabic)
Currently translated at 57.3% (233 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ar/
2025-03-02 16:34:17 +01:00
d1ee480452 chore(i18n): Translated using Weblate (Sinhala)
Currently translated at 12.0% (49 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/si/
2025-03-02 03:05:01 +01:00
c8397e4fb4 Update changelog for v3.7.5 2025-02-28 15:29:05 +00:00
65bcf20f97 Bump version to 3.7.5 2025-03-01 00:13:14 +09:00
1a214140fb chore(deps): update dependency builtin-modules to v5 (#3038)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-01 00:12:42 +09:00
ffdf7ac5a8 fix: remove unused deps (@types/eslint__js) 2025-03-01 00:07:08 +09:00
c8bb1f386d chore(deps): update deps 2025-03-01 00:04:00 +09:00
457e1bb48e chore(deps): update dependency electron-builder to v26.0.9 2025-03-01 00:01:57 +09:00
c1177adc08 Update package.json 2025-02-28 23:55:40 +09:00
cd976ee500 Delete patches/app-builder-lib@26.0.6.patch 2025-02-28 23:55:11 +09:00
b856884bba chore(deps): update dependency typescript-eslint to v8.25.0 (#2953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:45:25 +09:00
2df8e58773 fix(deps): update dependency happy-dom to v17.1.8 (#3001)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:44:58 +09:00
da8e0106f6 chore(deps): update dependency eslint-config-prettier to v10.0.2 (#3035)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:44:43 +09:00
b0b2005e1c chore(deps): update dependency @electron/universal to v2.0.2 (#3034)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:44:24 +09:00
5817d9c3ae chore(deps): update dependency @stylistic/eslint-plugin-js to v4 (#2950)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:43:13 +09:00
08f9187cdf chore(deps): update dependency electron-builder-squirrel-windows to v26.0.9 (#2930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:42:38 +09:00
49ac17a40e fix(no-google-login): Remove Library icon removal code (#3010) 2025-02-28 23:42:05 +09:00
Dvd
b1c4b04ebf fix: Updated tray pause icon for consistency (#3025) 2025-02-28 23:41:43 +09:00
10b8066126 chore(deps): update dependency eslint-import-resolver-typescript to v3.8.3 (#2992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:31:55 +09:00
d86e454d3f fix(deps): update dependency hono to v4.7.2 (#2999)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-28 23:31:40 +09:00
4ea8fa2561 fix: Filter for only MusicResponsiveListItem in playlist items (#3022) 2025-02-28 23:25:01 +09:00
dbea4c5884 fix(deps): update dependency youtubei.js to v13.1.0 (#3015) 2025-02-28 23:20:46 +09:00
7d4e949f0c chore(i18n): Translated using Weblate (Danish)
Currently translated at 32.5% (132 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/da/
2025-02-27 10:03:56 +00:00
82917e7748 chore(i18n): Added translation using Weblate (Danish) 2025-02-26 10:15:21 +01:00
7c9544a528 chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 16.0% (65 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-02-26 09:04:34 +01:00
960a20e899 chore(i18n): Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (403 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2025-02-22 14:28:49 +01:00
c9b7901681 chore(i18n): Translated using Weblate (Thai)
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/th/
2025-02-19 18:02:02 +01:00
95698aaf35 chore(i18n): Translated using Weblate (Italian)
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/it/
2025-02-19 18:02:00 +01:00
4dc87417ff chore(i18n): Translated using Weblate (Thai)
Currently translated at 69.4% (282 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2025-02-18 17:47:14 +01:00
7510f8eb08 chore(i18n): Translated using Weblate (Arabic)
Currently translated at 39.1% (159 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ar/
2025-02-18 13:51:53 +01:00
59103df665 fix: Match engines.pnpm with the pnpm version used to create the lock files (#2995) 2025-02-18 12:14:53 +09:00
258d35e48d chore(i18n): Translated using Weblate (Czech)
Currently translated at 92.8% (377 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2025-02-17 20:29:57 +01:00
5e419489d5 Update changelog for v3.7.4 2025-02-17 15:54:12 +00:00
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
2c48a0f6f4 Bump version to 3.7.2 2025-01-18 14:27:58 +09:00
368b251e3f feat(api-server): add endpoint to get shuffle state (#2792) 2025-01-18 14:23:17 +09:00
3339f997e3 fix: fix lock file 2025-01-18 14:14:18 +09:00
76e8e7aa7a fix(downloader): apply poToken
- fix #2863
- fix #2780
2025-01-18 14:12:31 +09:00
8c325b17f8 chore(deps): update dependency discord-api-types to v0.37.116 (#2877)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-18 11:50:43 +09:00
494bc0ccc7 chore(deps): update dependency eslint-plugin-prettier to v5.2.2 (#2875)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:41:33 +09:00
f14333d07a fix: fix pnpm 2025-01-16 11:39:14 +09:00
268ffe2d4c chore(deps): update eslint monorepo to v9.18.0 (#2858)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:36:27 +09:00
831eb63ace chore(deps): update dependency glob to v11.0.1 (#2857)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:34:08 +09:00
345f235117 chore(deps): update dependency electron-builder-squirrel-windows to v26.0.0-alpha.9 (#2874)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:33:49 +09:00
c6422d5d9c chore(deps): update dependency electron to v34 (#2867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:33:20 +09:00
f90384386c chore(deps): update dependency eslint-config-prettier to v10 (#2866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:33:01 +09:00
9213fdd4f7 chore(deps): update dependency @stylistic/eslint-plugin-js to v2.13.0 (#2864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:30:54 +09:00
787c8cdceb chore(deps): update dependency typescript-eslint to v8.20.0 (#2865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:30:34 +09:00
ace48bc79b chore(deps): update dependency electron-builder to v26.0.0-alpha.9 (#2869)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-16 11:29:54 +09:00
e5a8b7431f chore(i18n): Translated using Weblate (Hungarian)
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/hu/
2025-01-14 02:00:41 +00:00
e37f22503b fix: fix build.linux.desktop.entry (#2859)
Co-authored-by: h-banii <h-banii@users.noreply.github.com>
2025-01-11 17:40:27 +09:00
e61757a7fc feat(api-server): add endpoint to get volume state (#2813)
* add volume getter

* format

* add volume route
2025-01-10 12:25:32 +09:00
fdc798ad87 chore(deps): update dependency vite-plugin-inspect to v10 (#2856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:19:54 +09:00
6393e6348c chore(deps): update dependency typescript to v5.7.3 (#2855)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:17:15 +09:00
ce6e115783 fix(deps): update dependency @floating-ui/dom to v1.6.13 (#2846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:14:27 +09:00
68cbaabc0c chore(deps): bump nanoid from 3.3.7 to 3.3.8 (#2854)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 12:14:05 +09:00
9911bbf509 chore(deps): update dependency electron to v33.3.1 (#2841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:13:32 +09:00
553c2c1096 fix(deps): update dependency i18next to v24.2.1 (#2840)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:13:21 +09:00
dde57e3eb0 chore(deps): update dependency typescript-eslint to v8.19.1 (#2836)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:13:11 +09:00
935461f610 chore(deps): update dependency rollup to v4.30.1 (#2833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:12:49 +09:00
b95da863c6 fix(deps): update dependency solid-js to v1.9.4 (#2849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:12:32 +09:00
92316a999c fix(deps): update dependency fast-equals to v5.2.2 (#2842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-10 12:12:21 +09:00
0ec038342c chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 11.3% (46 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-01-08 21:00:54 +01:00
4649c3bfaf chore(i18n): Translated using Weblate (Spanish)
Currently translated at 99.2% (403 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2025-01-08 21:00:54 +01:00
8441af2483 chore: Update README.md (#2845)
Hungarian has been added as a selectable option under [Read this in other languages].
2025-01-08 20:08:38 +09:00
63c4a9cfa7 chore: Fixing the Content section in the README-ru.md file. (#2847)
* Fixing the Content section in the README-ru.md file.

EN: I have corrected the Содержание (Content) hyperlinks, so now it is possible to jump between the main headings with a single click. The issue was that the content hyperlinks corresponded to the original language headings in the README file, so clicking on them did not lead anywhere within the README file.

RU: Я исправил гиперссылки Содержание (Content), так что теперь можно переходить между основными заголовками одним кликом. Проблема заключалась в том, что гиперссылки содержания соответствовали заголовкам README на оригинальном языке, поэтому при нажатии на них переход внутри файла README не осуществлялся.

* Fixing the Content section in the README-ru.md file.

EN: In this version, I fixed the SVG file path so that it displays properly; previously, it did not appear.

RU: В этой версии я исправил путь к файлу SVG, чтобы он отображался правильно; ранее он не отображался.

EN: I have corrected the Содержание (Content) hyperlinks, so now it is possible to jump between the main headings with a single click. The issue was that the content hyperlinks corresponded to the original language headings in the README file, so clicking on them did not lead anywhere within the README file.

RU: Я исправил гиперссылки Содержание (Content), так что теперь можно переходить между основными заголовками одним кликом. Проблема заключалась в том, что гиперссылки содержания соответствовали заголовкам README на оригинальном языке, поэтому при нажатии на них переход внутри файла README не осуществлялся.
2025-01-08 20:07:46 +09:00
4e8173360e chore: Create youtube-music-hu.svg (#2844)
HU: Az eredeti youtube-music.svg magyar változata.

EN: The Hungarian version of the original youtube-music.svg
2025-01-08 20:06:48 +09:00
4f37377d64 chore: Create Transalated README-hu.md (#2843)
* Create README-hu.md

HU: Elkészítettem a README angol változatának magyar fordítását, hogy a projekt könnyebben elérhető legyen a magyar felhasználók számára.

EN: I have created the Hungarian translation of the README's English version to make the project more accessible to Hungarian users.

* Create Transalated README-hu.md

EN: I have created the Hungarian translation of the README's English version to make the project more accessible to Hungarian users. In this version, I fixed the SVG file path so that it displays properly. (previously, it did not appear.)


HU: Elkészítettem a README angol változatának magyar fordítását, hogy a projekt könnyebben elérhető legyen a magyar felhasználók számára. Ebben a verzióban javítottam az SVG fájl elérési útját, hogy megjelenjen normálisan. (eddig nem jelent meg.)
2025-01-08 20:06:26 +09:00
0e886c0890 chore(i18n): Translated using Weblate (Hungarian)
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/hu/
2025-01-07 18:03:50 +00:00
cb0719ecf4 chore(deps): update dependency vite to v6.0.7 (#2819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 23:45:48 +09:00
d24b31cf74 chore(deps): update dependency discord-api-types to v0.37.115 (#2818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 23:42:34 +09:00
610073b982 fix(deps): update dependency hono to v4.6.16 (#2829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 23:42:16 +09:00
493b65bb11 chore(deps): update dependency rollup to v4.29.2 (#2832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 23:42:07 +09:00
e4e7ef3b52 fix(deps): update dependency fast-equals to v5.2.0 (#2822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 23:41:50 +09:00
e1dc19e9eb chore(i18n): Translated using Weblate (Hungarian)
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/hu/
2025-01-04 11:07:48 +01:00
4b9f92ed2d chore(i18n): Translated using Weblate (Ukrainian)
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/uk/
2025-01-04 11:07:48 +01:00
622beccd95 chore(i18n): Translated using Weblate (Dutch)
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/nl/
2025-01-02 23:00:48 +00:00
8678fca9c0 chore(i18n): Translated using Weblate (Georgian)
Currently translated at 18.7% (76 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ka/
2025-01-01 23:22:07 +01:00
4dcb9b5995 chore(i18n): Translated using Weblate (Dutch)
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/nl/
2025-01-01 23:22:07 +01:00
718025445c chore(i18n): Translated using Weblate (Dutch)
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/nl/
2025-01-01 23:22:07 +01:00
845dac3c03 chore(i18n): Translated using Weblate (Romanian)
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/ro/
2025-01-01 23:22:06 +01:00
a1ac3d1359 feat(api-server): add insertPosition for addSongToQueue (#2808) 2025-01-02 00:19:12 +09:00
c21dd08a40 fix: fix deps 2025-01-02 00:09:34 +09:00
8de27358d3 fix: fix invalid property name 2025-01-01 15:40:19 +09:00
c4910af494 fix: remove farm config 2025-01-01 15:34:41 +09:00
67fc0a415c chore(deps): update dependency electron-builder to v26 2025-01-01 15:32:56 +09:00
7d145cbca1 chore(i18n): Added translation using Weblate (Georgian) 2025-01-01 02:54:17 +01:00
a565d9fc0f chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 93.8% (381 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-12-31 19:00:28 +01:00
71a9ed5d65 chore(i18n): Translated using Weblate (Turkish)
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/tr/
2024-12-31 19:00:28 +01:00
fc16a325f7 chore(i18n): Translated using Weblate (German)
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/de/
2024-12-31 19:00:27 +01:00
c52d96dcbd chore(deps): update dependency typescript-eslint to v8.19.0 (#2812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-31 12:36:23 +09:00
d2c681a047 fix(deps): update dependency ts-morph to v25 (#2810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-31 12:36:13 +09:00
Adi
8e75df42bf chore(i18n): Translated using Weblate (French)
Currently translated at 98.5% (400 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-12-30 00:25:43 +01:00
85d1dc46d1 chore(i18n): Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.0% (402 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-12-29 18:19:09 +01:00
84f5e265f2 chore(i18n): Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.5% (400 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-12-29 17:35:25 +01:00
0d261a8e44 fix(renderer): update event handler from onVolumeTap to onVolumeClick (#2791) 2024-12-28 23:29:22 +09:00
3c228ede48 fix(deps): update dependency hono to v4.6.15 (#2796)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-28 23:28:37 +09:00
8b971d2263 chore(deps): update dependency bufferutil to v4.0.9 (#2787)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-28 23:27:32 +09:00
6b8fed3fc2 feat: Refactor Menu Navigation and Update Media Control Icons (#2783)
* chore: update media control icons

Updated "next," "pause," "play," and "previous" icons in the media-icons-black folder. This improves visual consistency and ensures the latest icon designs are applied.

* refactor(menu): migrate to `navigationHistory` API

- Replaced deprecated `webContents` navigation methods (`canGoBack`, `goBack`, `canGoForward`, `goForward`) with `navigationHistory` API.
- Updated `mainMenuTemplate` to use the new `navigationHistory` destructured from `win.webContents`.
2024-12-28 23:27:07 +09:00
f15c51f3d7 fix(synced-lyrics): Revert font-size behavior for non-fancy modes (#2788) 2024-12-28 23:26:34 +09:00
fa3e146ef7 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 99.7% (405 of 406 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-12-27 22:00:38 +01:00
4baec1560c chore(i18n): Translated using Weblate (Polish)
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/pl/
2024-12-27 22:00:37 +01:00
0e0230b995 Update changelog for v3.7.1 2024-12-26 17:01:22 +00:00
96 changed files with 9782 additions and 3570 deletions

View File

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

View File

@ -20,7 +20,7 @@ jobs:
TAG_NAME: ${{ inputs.tag_name || github.event.release.tag_name }} TAG_NAME: ${{ inputs.tag_name || github.event.release.tag_name }}
run: echo "WINGET_TAG_NAME=$(echo ${TAG_NAME#v})" >> $GITHUB_ENV run: echo "WINGET_TAG_NAME=$(echo ${TAG_NAME#v})" >> $GITHUB_ENV
- name: Submit package to Windows Package Manager Community Repository - name: Submit package to Windows Package Manager Community Repository
uses: vedantmgoyal2009/winget-releaser@v2 uses: vedantmgoyal2009/winget-releaser@main
with: with:
identifier: th-ch.YouTubeMusic identifier: th-ch.YouTubeMusic
installers-regex: '^YouTube-Music-Web-Setup-[\d\.]+\.exe$' installers-regex: '^YouTube-Music-Web-Setup-[\d\.]+\.exe$'

View File

@ -21,7 +21,7 @@
</a> </a>
</div> </div>
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md), [🇷🇺](./docs/readme/README-ru.md) Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇫🇷](./docs/readme/README-fr.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md), [🇷🇺](./docs/readme/README-ru.md), [🇭🇺](./docs/readme/README-hu.md)
**Electron wrapper around YouTube Music featuring:** **Electron wrapper around YouTube Music featuring:**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -2,8 +2,155 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v3.7.5](https://github.com/th-ch/youtube-music/compare/v3.7.4...v3.7.5)
- chore(deps): update dependency builtin-modules to v5 [`#3038`](https://github.com/th-ch/youtube-music/pull/3038)
- chore(deps): update dependency typescript-eslint to v8.25.0 [`#2953`](https://github.com/th-ch/youtube-music/pull/2953)
- fix(deps): update dependency happy-dom to v17.1.8 [`#3001`](https://github.com/th-ch/youtube-music/pull/3001)
- chore(deps): update dependency eslint-config-prettier to v10.0.2 [`#3035`](https://github.com/th-ch/youtube-music/pull/3035)
- chore(deps): update dependency @electron/universal to v2.0.2 [`#3034`](https://github.com/th-ch/youtube-music/pull/3034)
- chore(deps): update dependency @stylistic/eslint-plugin-js to v4 [`#2950`](https://github.com/th-ch/youtube-music/pull/2950)
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.9 [`#2930`](https://github.com/th-ch/youtube-music/pull/2930)
- fix(no-google-login): Remove Library icon removal code [`#3010`](https://github.com/th-ch/youtube-music/pull/3010)
- fix: Updated tray pause icon for consistency [`#3025`](https://github.com/th-ch/youtube-music/pull/3025)
- chore(deps): update dependency eslint-import-resolver-typescript to v3.8.3 [`#2992`](https://github.com/th-ch/youtube-music/pull/2992)
- fix(deps): update dependency hono to v4.7.2 [`#2999`](https://github.com/th-ch/youtube-music/pull/2999)
- fix: Filter for only `MusicResponsiveListItem` in playlist items [`#3022`](https://github.com/th-ch/youtube-music/pull/3022)
- fix(deps): update dependency youtubei.js to v13.1.0 [`#3015`](https://github.com/th-ch/youtube-music/pull/3015)
- fix: Match engines.pnpm with the pnpm version used to create the lock files [`#2995`](https://github.com/th-ch/youtube-music/pull/2995)
- chore(deps): update dependency electron-builder to v26.0.9 [`457e1bb`](https://github.com/th-ch/youtube-music/commit/457e1bb48e2bcc742680d22b7d34ffdbe7f33eae)
- chore(deps): update deps [`c8bb1f3`](https://github.com/th-ch/youtube-music/commit/c8bb1f386d7053d755c38ca2cac8708af7af1fb9)
- chore(i18n): Translated using Weblate (Thai) [`c9b7901`](https://github.com/th-ch/youtube-music/commit/c9b790168130d0cfc9b2ff23cdcb56ab082a4b66)
#### [v3.7.4](https://github.com/th-ch/youtube-music/compare/v3.7.3...v3.7.4)
> 18 February 2025
- chore(deps): update dependency rollup to v4.34.8 [`#2982`](https://github.com/th-ch/youtube-music/pull/2982)
- fix(plugin-loader): update context filtering logic for backend mode [`#2990`](https://github.com/th-ch/youtube-music/pull/2990)
- Update changelog for v3.7.3 [`86c77d1`](https://github.com/th-ch/youtube-music/commit/86c77d141f2bec62a4a578fff96d51ed388c05a5)
- HOTFIX: Bump version to 3.7.4 [`0d462ac`](https://github.com/th-ch/youtube-music/commit/0d462ac3a26caee23854014cbf5e4b91e2d385e2)
#### [v3.7.3](https://github.com/th-ch/youtube-music/compare/v3.7.2...v3.7.3)
> 17 February 2025
- 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)
- fix(downloader): fix #2234 [`#2234`](https://github.com/th-ch/youtube-music/issues/2234)
- fix(downloader): fix #2769 [`#2769`](https://github.com/th-ch/youtube-music/issues/2769)
- fix: fix #2645, fix #2741 [`#2645`](https://github.com/th-ch/youtube-music/issues/2645) [`#2741`](https://github.com/th-ch/youtube-music/issues/2741)
- Update changelog for v3.7.0 [`1cc1530`](https://github.com/th-ch/youtube-music/commit/1cc153084d5f354ea928fcde50207f8f6b14ea4c)
- fix: use networkManager.fetch instead of fetch [`80471b0`](https://github.com/th-ch/youtube-music/commit/80471b0ca4b3d3efc9e3db87d434290c9ebc79f6)
- chore(i18n): Translated using Weblate (Hindi) [`6d1237c`](https://github.com/th-ch/youtube-music/commit/6d1237c2a2ad2408a738e00992ae5ed8a1e900da)
#### [v3.7.0](https://github.com/th-ch/youtube-music/compare/v3.6.2...v3.7.0) #### [v3.7.0](https://github.com/th-ch/youtube-music/compare/v3.6.2...v3.7.0)
> 25 December 2024
- feat(amuse): song query api (add amuse plugin) [`#2723`](https://github.com/th-ch/youtube-music/pull/2723) - feat(amuse): song query api (add amuse plugin) [`#2723`](https://github.com/th-ch/youtube-music/pull/2723)
- feat(api-server): add absolute seek endpoint [`#2748`](https://github.com/th-ch/youtube-music/pull/2748) - feat(api-server): add absolute seek endpoint [`#2748`](https://github.com/th-ch/youtube-music/pull/2748)
- feat(api-server): Add repeat mode and seek time API [`#2630`](https://github.com/th-ch/youtube-music/pull/2630) - feat(api-server): Add repeat mode and seek time API [`#2630`](https://github.com/th-ch/youtube-music/pull/2630)

View File

@ -21,6 +21,8 @@
</a> </a>
</div> </div>
Lee esto en otros idiomas: [🏴 Inglés](../../README.md), [🇰🇷 Coreano](./README-ko.md), [🇫🇷 Francés](./README-fr.md), [🇮🇸 Islandés](./README-is.md), [🇪🇸 Español](./README-es.md), [🇷🇺 Ruso](./README-ru.md)
**Electron wrapper de YouTube Music con las siguientes características:** **Electron wrapper de YouTube Music con las siguientes características:**
- Apariencia y sensación nativa, tiene como objetivo mantener la interfaz original - Apariencia y sensación nativa, tiene como objetivo mantener la interfaz original

View File

@ -21,6 +21,7 @@
</a> </a>
</div> </div>
Lisez ceci dans d'autres langues: [🏴 Anglais](../../README.md), [🇰🇷 Coréen](./README-ko.md), [🇫🇷 Français](./README-fr.md), [🇮🇸 Islandais](./README-is.md), [🇪🇸 Espagnol](./README-es.md), [🇷🇺 Russe](./README-ru.md)
**Enveloppe Electron autour de YouTube Music offrant :** **Enveloppe Electron autour de YouTube Music offrant :**

374
docs/readme/README-hu.md Normal file
View File

@ -0,0 +1,374 @@
<div align="center">
# YouTube Music
[![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/)
[![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/eslint.config.mjs)
[![Build status](https://img.shields.io/github/actions/workflow/status/th-ch/youtube-music/build.yml?branch=master&style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/)
[![GitHub All Releases](https://img.shields.io/github/downloads/th-ch/youtube-music/total?style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/)
[![AUR](https://img.shields.io/aur/version/youtube-music-bin?color=blueviolet&style=for-the-badge&logo=youtube-music)](https://aur.archlinux.org/packages/youtube-music-bin)
[![Known Vulnerabilities](https://snyk.io/test/github/th-ch/youtube-music/badge.svg)](https://snyk.io/test/github/th-ch/youtube-music)
</div>
![Bannerkep](https://i.imgur.com/UaZPHqX.png)
<div align="center">
<a href="https://github.com/th-ch/youtube-music/releases/latest">
<img src="../../web/youtube-music-hu.svg" width="400" height="100" alt="YouTube Music SVG">
</a>
</div>
Olvasd el más nyelveken: [🏴 Angol](../../README.md), [🇰🇷 Korea](./README-ko.md), [🇫🇷 Francia](./README-fr.md), [🇮🇸 Izland](./README-is.md), [🇪🇸 Spanyol](./README-es.md), [🇷🇺 Orosz](./README-ru.md)
**Electron keretrendszerre épülő alkalmazás a YouTube Music számára, amely a következőket kínálja:**
- Natív megjelenés és élmény, amely az eredeti felület megtartására törekszik
- Egyedi bővítmények keretrendszere: alakítsd át a YouTube Music-ot igényeid szerint (stílus, tartalom, funkciók), engedélyezd/tiltsd le a bővítményeket egy kattintással
## Bemutató kép
| Lejátszó ablak (album színtéma és környezeti fény) |
|:---------------------------------------------------------------------------------------------------------:|
|![Bemutatókép1](https://i.imgur.com/Tj4LBwf.png)|
## Tartalom
- [Funkciók](#Funkciók)
- [Elérhető bővítmények](#Elérhető-bővítmények)
- [Fordítás](#Fordítás)
- [Letöltés](#Letöltés)
- [Arch Linux](#arch-linux)
- [MacOS](#macos)
- [Windows](#windows)
- [Hogyan telepítsük hálózati kapcsolat nélkül? (Windows alatt)](#Hogyan-telepítsd-hálózati-kapcsolat-nélkül-Windows)
- [Témák](#Témák)
- [Fejlesztés](#Fejlesztés)
- [Saját bővítmények készítése](#Saját-bővítmények-készítése)
- [Bővítmény létrehozása](#Bővítmény-létrehozása)
- [Gyakori használati esetek](#Gyakori-használati-esetek)
- [Build](#build)
- [Gyártás előnézete](#Gyártás-előnézete)
- [Tesztelés](#Tesztelés)
- [Licenc](#Licenc)
- [GYIK](#GYIK)
## Funkciók:
- **Automatikus megerősítés a lejátszás szüneteltetésekor** (Alapból engedélyezve): Kikapcsolja a ["Folytatja a nézést?"](https://i.imgur.com/z2mG0QN.png)
felugró ablakot, amely bizonyos idő után leállítja a zenét.
- És még sok más ...
## Elérhető bővítmények:
- **Reklámblokkoló**: Blokkolja az összes hirdetést és nyomkövetőt.
- **Album műveletek**: Dislike, Undislike, Like, Unlike gombok hozzáadása, amivel ezt a lejátszási listán vagy albumban lévő összes dalra alkalmazza.
- **Album színtéma**: Dinamikus téma és vizuális effektek alkalmazása az album színpalettája alapján.
- **Ambient mód**: Fényhatás alkalmazása a videóból származó lágy színek vetítésével a képernyő hátterére.
- **Hangtömörítő**: Hang tömörítés alkalmazása. (csökkenti a jel legzajosabb részeinek hangerősségét, és emeli a legcsendesebb részek hangerősségét)
- **Navigációs sáv elmosása**: Átlátszóvá és elmosódottá teszi a navigációs sávot.
- **Korellenőrzés kihagyása**: A YouTube korellenőrzését kihagyja, ezáltal nem kel meg erősíteni a zene meghallgatása elött. (automatikusan megerősítve lesz)
- **Feliratválasztó**: Felirat választó a YouTube Music zenékhez.
- **Kompakt oldalsáv**: Mindig becsukva tartja a bal oldali sávot, ahol a Kezdőlap, Felfedezés, Könyvtár és egyebek láthatók. (amit bármikor ki lehet nyitni)
- **Áttünés**: Áttünést biztosít a dalok között, ami folytonossá teszi a zenehallgatást anélkül, hogy érezhető lenne a váltás.
- **Automatikus lejátszás letiltása**: Ez a funkció kikapcsolja az automatikus lejátszást, így a zenék nem indulnak el maguktól. Amikor egy album vagy egy dal lejátszása véget ér, a következő szám nem kezdődik el automatikusan. (a bővítmény használata során minden zenét manuálisan kell elindítani)
- **[Discord](https://discord.com/) Rich Presence**: Mutassa meg barátainak, hogy mit hallgat a [Rich Presence](https://i.imgur.com/nCeVQB2.png) segítségével. (Ehez a Discord-on is engedélyezve kel lennie a Tevékenységállapot megosztásának [DC Beállítások -> Tevékenyég-adatvédelem -> Megoszthatod az észlelt tevékenységeidet másokkal])
- **Letöltő**: MP3/forrás hanganyag letöltése [közvetlenül az interfészről](https://i.imgur.com/ghqBNVe.png). [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
- **Hangszínszabályzó**: Szűrőket ad hozzá, hogy erősítsd vagy csökkentsd bizonyos frekvenciatartományokat. (pl. basszuskiemelés)
- **Exponenciális hangerő**: A hangerő csúszka [exponenciálissá](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) tételével könnyebbé válik az alacsony hangerő kiválasztása.
- **Alkalmazáson belüli menü**: [A Menüsáv stílusos, sötét vagy album-színű megjelenítése](https://i.imgur.com/vWvO7Xt.png).
> (Lásd ezt a [bejegyzést](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709), ha problémád van a menü elérésével, miután engedélyezted ezt a bővítményt és a "menü elrejtése" opciót.
- **Scrobbler**: Scrobbling támogatást biztosít [Last.fm](https://www.last.fm/) és [ListenBrainz](https://listenbrainz.org/) számára.
- **Lumia Stream**: [Lumia Stream](https://lumiastream.com/) támogatás hozzáadása.
- **Lyrics Genius**: Dalszöveg támogatást nyújt a legtöbb dalhoz.
- **Zene együtt**: Lehetővé teszi a lejátszási listák, dalok megosztását másokkal. Amikor a házigazda lejátszik egy dalt, mindenki ugyanazt a dalt fogja hallani.
- **Navigáció**: Következő/Vissza navigációs nyilak közvetlenül az interfészbe integrálva, mint a kedvenc böngésződben.
- **Nincs Google bejelentkezés**: A Bejelentkezés gomb eltávolítása az interfészről (Jobb fentről eltünik a bejelentkezés gomb.)
- **Értesítések**: Értesítés megjelenítése, amikor egy dal elindul. ([interaktív értesítések](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) elérhetők Windows-on)
- **Kép a képben**: Lehetővé teszi az alkalmazás kép a képben módra váltását.
- **Lejátszás sebessége**: Hallgassd gyorsan, hallgassd lassan! [Hozzáad egy csúszkát, amely szabályozza a dal sebességét](https://i.imgur.com/uaNOWOt.png)
- **Precíz hangerő**: A hangerő precíz szabályozása egérgörgővel/gyorsbillentyűkkel, egy egyedi HUD és testreszabható hangerő csuszka segítségével.
- **Gyorsbillentyűk (& MPRIS)**: Lehetővé teszi globális gyorsbillentyűk beállítását a lejátszáshoz (lejátszás/szünet/következő/előző), valamint a [média OSD](https://i.imgur.com/o13SpAE.png) kikapcsolását a médiagombok felülírásával. Bekapcsolja a Ctrl/CMD + F billentyűkombinációt a kereséshez, a Linux MPRIS támogatását a médiagombokhoz, és [egyedi gyorsbillentyűket](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50) a [haladó felhasználók](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902) számára.
- **Nem kedvelt dal kihagyása**: Kihagyja a nem kedvelt dalokat.
- **Csend kihagyása**: Automatikusan átugorja a csendes szakaszokat.
- [**SzponzorBlokk**](https://github.com/ajayyy/SponsorBlock): Automatikusan átugorja a nem zenei részeket, például az intrókat/outrokat vagy a zenei videók azon részeit, ahol a dal nem szól.
- **Szinkronizált dalszövegek**: Szinkronizált dalszövegeket biztosít dalokhoz, [LRClib](https://lrclib.net)-hez hasonló szolgáltatókat használva.
- **Médiavezérlés a tálcán**: Lejátszás vezérlése a [Windows tálcáról](https://i.imgur.com/eolQfnA.png).
- **TouchBar**: Egyedi TouchBar elrendezés macOS-hoz.
- **Tuna OBS**: Integráció az [OBS](https://obsproject.com/) [Tuna](https://obsproject.com/forum/resources/tuna.843/) pluginjával.
- **Videóminőség modosító**: Lehetővé teszi a videó minőségének megváltoztatását egy [gombbal](https://i.imgur.com/UgpgtHL.png) a videó fedvényen.
- **Videó váltó**: Hozzáad egy [gombot](https://i.imgur.com/288QE1k.png) a Videó/Dal mód közötti váltáshoz. (opcionálisan teljesen eltávolíthatja a videó fület is)
- **Vizualizáció**: Különböző zenei vizualizációk.
## Fordítás
Segíthetsz a fordításban a [Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/) oldalán.
<a href="https://hosted.weblate.org/engage/youtube-music/">
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/multi-auto.svg" alt="Fordítás állapota" />
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="Fordítás állapota" />
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/hu/287x66-white.png" alt="Fordítás állapota" />
</a>
## Letöltés
A [legfrissebb kiadás](https://github.com/th-ch/youtube-music/releases/latest) megtekintésével gyorsan megtalálhatod a legújabb verziót.
### Arch Linux
Telepítsd a [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) csomagot az AUR-ból. Az AUR telepítési útmutatóját megtalálod ezen a [wiki oldalon](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
### macOS
Telepítheted az alkalmazást Homebrew segítségével (lásd a [cask definíciót](https://github.com/th-ch/homebrew-youtube-music)):
```bash
brew install th-ch/youtube-music/youtube-music
```
Ha manuálisan telepítetted az alkalmazást, és a következő hibát kapod indításkor: "sérült, és nem nyitható meg./is damaged and cant be opened.", futtasd az alábbi parancsot a Terminálban:
```bash
/usr/bin/xattr -cr /Applications/YouTube\ Music.app
```
### Windows
A [Scoop csomagkezelő](https://scoop.sh) segítségével telepítheted a `youtube-music` csomagot az [`extras` tárolóból](https://github.com/ScoopInstaller/Extras).
```bash
scoop bucket add extras
scoop install extras/youtube-music
```
Alternatívaként használhatod a [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/) eszközt, a Windows 11 hivatalos CLI csomagkezelőjét, hogy telepítsd a `th-ch.YouTubeMusic` csomagot.
*Megjegyzés: A Microsoft Defender SmartScreen figyelmeztethet vagy blokkolhatja a telepítést, mivel az alkalmazás "ismeretlen kiadótól" származik. Ez a figyelmeztetés akkor is megjelenhet, ha manuálisan töltöd le és próbálod futtatni a GitHubról letöltött (.exe) fájlt. Ebben az esetben kattints a "További információ" gombra, majd válaszd a "Futtatás mindenképp" opciót a telepítés folytatásához.*
```bash
winget install th-ch.YouTubeMusic
```
#### Hogyan telepítsd hálózati kapcsolat nélkül? (Windows)
- Töltsd le a `*.nsis.7z` fájlt a [kiadás oldal](https://github.com/th-ch/youtube-music/releases/latest)ról, amely megfelel az eszközöd architektúrájának:
- `x64` 64 bites Windows-hoz
- `ia32` 32 bites Windows-hoz
- `arm64` ARM64 Windows-hoz
- Töltsd le a telepítőt a [kiadás oldal](https://github.com/th-ch/youtube-music/releases/latest)ról. (`*-Setup.exe`)
- Helyezd mindkét fájlt **ugyanabba a könyvtárba**.
- Futtasd a telepítőt.
## Témák
CSS fájlokat tölthetsz be az alkalmazás megjelenésének megváltoztatásához. (Beállítások > Kinézeti beállítások > Téma)
Néhány előre definiált téma elérhető itt: https://github.com/kerichdev/themes-for-ytmdesktop-player.
## Fejlesztés
```bash
git clone https://github.com/th-ch/youtube-music
cd youtube-music
pnpm install --frozen-lockfile
pnpm dev
```
## Saját bővítmények készítése
A bővítmények segítségével a következőket teheted:
- Az alkalmazás manipulálása: Az Electron `BrowserWindow` objektuma átadásra kerül a bővítménykezelőnek.
- Az interfész módosítása: HTML és CSS manipulációval megváltoztathatod az alkalmazás kinézetét.
### Bővítmény létrehozása
Hozz létre egy mappát a `src/plugins/YOUR-PLUGIN-NAME` útvonalon:
- `index.ts`: a bővítmény fő fájlja
```typescript
import style from './style.css?inline'; // import style as inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic show restart dialog
config: {
enabled: false,
}, // your custom config
stylesheets: [style], // your custom style,
menu: async ({ getConfig, setConfig }) => {
// All *Config methods are wrapped Promise<T>
const config = await getConfig();
return [
{
label: 'menu',
submenu: [1, 2, 3].map((value) => ({
label: `value ${value}`,
type: 'radio',
checked: config.value === value,
click() {
setConfig({ value });
},
})),
},
];
},
backend: {
start({ window, ipc }) {
window.maximize();
// you can communicate with renderer plugin
ipc.handle('some-event', () => {
return 'hello';
});
},
// it fired when config changed
onConfigChange(newConfig) { /* ... */ },
// it fired when plugin disabled
stop(context) { /* ... */ },
},
renderer: {
async start(context) {
console.log(await context.ipc.invoke('some-event'));
},
// Only renderer available hook
onPlayerApiReady(api: YoutubePlayer, context: RendererContext) {
// set plugin config easily
context.setConfig({ myConfig: api.getVolume() });
},
onConfigChange(newConfig) { /* ... */ },
stop(_context) { /* ... */ },
},
preload: {
async start({ getConfig }) {
const config = await getConfig();
},
onConfigChange(newConfig) {},
stop(_context) {},
},
});
```
### Gyakori használati esetek
- Egyedi CSS injektálása: hozz létre egy `style.css` fájlt ugyanabban a mappában, majd:
```typescript
// index.ts
import style from './style.css?inline'; // import style as inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic will show a restart dialog
config: {
enabled: false,
}, // your custom config
stylesheets: [style], // your custom style
renderer() {} // define renderer hook
});
```
- Ha módosítani szeretnéd a HTML-t:
```typescript
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic will show the restart dialog
config: {
enabled: false,
}, // your custom config
renderer() {
// Remove the login button
document.querySelector(".sign-in-link.ytmusic-nav-bar").remove();
} // define renderer hook
});
```
- Az elülső és hátsó rész közötti kommunikáció: Az Electron ipcMain moduljának használatával valósítható meg. Lásd az `index.ts` fájlt és a `sponsorblock` bővítmény példáját.
## Build
1. Klónozd a repót
2. Kövesd ezt az [útmutatót](https://pnpm.io/installation), hogy telepítsd a `pnpm` csomagkezelőt.
3. Futtasd a következő parancsot `pnpm install --frozen-lockfile` a kellékek telepítéséhez.
4. Építsd meg az alkalmazást az operációs rendszerednek megfelelő paranccsal: `pnpm build:OS`
- `pnpm dist:win` - Windows
- `pnpm dist:linux` - Linux (amd64)
- `pnpm dist:linux:deb-arm64` - Linux (arm64 Debiánhoz)
- `pnpm dist:linux:rpm-arm64` - Linux (arm64 Fedorához)
- `pnpm dist:mac` - macOS (amd64)
- `pnpm dist:mac:arm64` - macOS (arm64)
Az alkalmazás építéséhez a [electron-builder](https://github.com/electron-userland/electron-builder) eszközt használáld, amely támogatja a macOS, Linux és Windows platformokat.
## Gyártás előnézete
```bash
pnpm start
```
## Tesztelés
```bash
pnpm test
```
A [Playwright](https://playwright.dev/) tesztelési keretrendszert használd az alkalmazás teszteléséhez.
## Licenc
MIT © [th-ch](https://github.com/th-ch/youtube-music)
## GYIK
### Miért nem jelenik meg az alkalmazás menüje?
Ha a `menü elrejtése` opció be van kapcsolva, a menüt az <kbd>alt</kbd> billentyűvel jelenítheted meg (vagy az <kbd>`</kbd> [fordított idézőjel] billentyűvel, ha az alkalmazáson belüli menü bővítményt használod).

View File

@ -21,6 +21,8 @@
</a> </a>
</div> </div>
Lestu þetta á öðrum tungumálum: [🏴 Ensku](../../README.md), [🇰🇷 Kóreska](./README-ko.md), [🇫🇷 Franska](./README-fr.md), [🇮🇸 Íslenskur](./README-is.md), [🇪🇸 Spænska](./README-es.md), [🇷🇺 Rússneska](./README-ru.md)
**Electron umbúðir utan um YouTube Tónlist sem inniheldur:** **Electron umbúðir utan um YouTube Tónlist sem inniheldur:**
- Innfæddur útlit og tilfinning, miðar að því að halda upprunalegu viðmótinu - Innfæddur útlit og tilfinning, miðar að því að halda upprunalegu viðmótinu

View File

@ -20,6 +20,8 @@
</a> </a>
</div> </div>
다른 언어로 읽어보세요: [🏴 영어](../../README.md), [🇰🇷 한국인](./README-ko.md), [🇫🇷 프랑스 국민](./README-fr.md), [🇮🇸 아이슬란드어](./README-is.md), [🇪🇸 스페인 사람](./README-es.md), [🇷🇺 러시아인](./README-ru.md)
**유튜브 뮤직의 Electron 래퍼; 기능:** **유튜브 뮤직의 Electron 래퍼; 기능:**
- 원래의 인터페이스를 유지하는 것을 목표로 하는 네이티브 디자인 및 느낌 - 원래의 인터페이스를 유지하는 것을 목표로 하는 네이티브 디자인 및 느낌

View File

@ -17,11 +17,11 @@
<div align="center"> <div align="center">
<a href="https://github.com/th-ch/youtube-music/releases/latest"> <a href="https://github.com/th-ch/youtube-music/releases/latest">
<img src="web/youtube-music.svg" width="400" height="100" alt="YouTube Music SVG"> <img src="../../web/youtube-music.svg" width="400" height="100" alt="YouTube Music SVG">
</a> </a>
</div> </div>
Прочтите это на других языках: [🏴 Английский](../../README.md), [🇰🇷 корейский](./README-ko.md), [🇫🇷 Французский](./README-fr.md), [🇮🇸 исландский](./README-is.md), [🇪🇸 испанский](./README-es.md), [🇷🇺 Русский](./README-ru.md)
**Клиент для YouTube Music основанный на Electron с поддержкой:** **Клиент для YouTube Music основанный на Electron с поддержкой:**
@ -36,24 +36,24 @@
## Содержание ## Содержание
- [Возможности](#features) - [Возможности](#Возможности)
- [Доступные плагины](#available-plugins) - [Доступные плагины](#Доступные-плагины)
- [Перевод](#translation) - [Перевод](#Перевод)
- [Скачать](#download) - [Скачать](#Скачать)
- [Arch Linux](#arch-linux) - [Arch Linux](#arch-linux)
- [MacOS](#macos) - [MacOS](#macos)
- [Windows](#windows) - [Windows](#windows)
- [Как установить без подключения к интернету? (в Windows)](#how-to-install-without-a-network-connection-in-windows) - [Как установить без подключения к интернету? (в Windows)](#Установка-без-подключения-к-Интернету-в-Windows)
- [Темы](#themes) - [Темы](#Темы)
- [Для разработчиков](#dev) - [Для разработчиков](#Для-разработчиков)
- [Создайте свои собственные плагины](#build-your-own-plugins) - [Создайте свои собственные плагины](#Создайте-свои-собственные-плагины)
- [Создание плагина](#creating-a-plugin) - [Создание плагина](#Создание-плагина)
- [Примеры использования](#common-use-cases) - [Примеры использования](#Примеры-использования)
- [Сборка](#build) - [Сборка](#Сборка)
- [Предварительный просмотр](#production-preview) - [Предварительный просмотр](#Предварительный-просмотр)
- [Тестирование](#tests) - [Тестирование](#Тестирование)
- [Лицензия](#license) - [Лицензия](#Лицензия)
- [Часто задаваемые вопросы](#faq) - [Часто задаваемые вопросы](#Часто-задаваемые-вопросы)
## Возможности: ## Возможности:

View File

@ -1,4 +1,4 @@
import { resolve, dirname, join } from 'node:path'; import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import { UserConfig } from 'vite'; import { UserConfig } from 'vite';
@ -147,6 +147,11 @@ export default defineConfig({
resolve: { resolve: {
alias: resolveAlias, alias: resolveAlias,
}, },
server: {
cors: {
origin: 'https://music.youtube.com',
},
},
}; };
if (mode === 'development') { if (mode === 'development') {

View File

@ -2,7 +2,7 @@
"name": "youtube-music", "name": "youtube-music",
"desktopName": "com.github.th_ch.youtube_music", "desktopName": "com.github.th_ch.youtube_music",
"productName": "YouTube Music", "productName": "YouTube Music",
"version": "3.7.1", "version": "3.8.0",
"description": "YouTube Music Desktop App - including custom plugins", "description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js", "main": "./dist/main/index.js",
"license": "MIT", "license": "MIT",
@ -73,7 +73,9 @@
"icon": "assets/generated/icons/png", "icon": "assets/generated/icons/png",
"category": "AudioVideo", "category": "AudioVideo",
"desktop": { "desktop": {
"StartupWMClass": "com.github.th_ch.youtube_music" "entry": {
"StartupWMClass": "com.github.th_ch.youtube_music"
}
}, },
"target": [ "target": [
{ {
@ -216,121 +218,132 @@
}, },
"engines": { "engines": {
"node": ">=18", "node": ">=18",
"pnpm": ">=8" "pnpm": ">=10"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"usocket": "1.0.1", "vite": "6.2.3",
"node-gyp": "11.0.0", "node-gyp": "11.1.0",
"xml2js": "0.6.2", "xml2js": "0.6.2",
"node-fetch": "3.3.2", "node-fetch": "3.3.2",
"@electron/universal": "2.0.1", "@electron/universal": "2.0.2",
"@babel/runtime": "7.26.0" "@babel/runtime": "7.27.0"
}, },
"patchedDependencies": { "patchedDependencies": {
"vudio@2.1.1": "patches/vudio@2.1.1.patch", "vudio@2.1.1": "patches/vudio@2.1.1.patch",
"app-builder-lib@24.13.3": "patches/app-builder-lib@24.13.3.patch", "@malept/flatpak-bundler@0.4.0": "patches/@malept__flatpak-bundler@0.4.0.patch",
"@malept/flatpak-bundler": "patches/@malept__flatpak-bundler.patch" "kuromoji@0.1.2": "patches/kuromoji@0.1.2.patch"
} },
"neverBuiltDependencies": []
}, },
"dependencies": { "dependencies": {
"@electron-toolkit/tsconfig": "1.0.1", "@electron-toolkit/tsconfig": "1.0.1",
"@electron/remote": "2.1.2", "@electron/remote": "2.1.2",
"@ffmpeg.wasm/core-mt": "0.12.0", "@ffmpeg.wasm/core-mt": "0.12.0",
"@ffmpeg.wasm/main": "0.12.0", "@ffmpeg.wasm/main": "0.12.0",
"@floating-ui/dom": "1.6.12", "@floating-ui/dom": "1.6.13",
"@foobar404/wave": "2.0.5", "@foobar404/wave": "2.0.5",
"@ghostery/adblocker-electron": "2.3.1", "@ghostery/adblocker-electron": "2.5.0",
"@ghostery/adblocker-electron-preload": "2.3.1", "@ghostery/adblocker-electron-preload": "2.5.0",
"@hono/node-server": "1.13.7", "@hono/node-server": "1.14.0",
"@hono/swagger-ui": "0.5.0", "@hono/swagger-ui": "0.5.1",
"@hono/zod-openapi": "0.18.3", "@hono/zod-openapi": "0.19.2",
"@hono/zod-validator": "0.4.2", "@hono/zod-validator": "0.4.3",
"@jellybrick/dbus-next": "0.10.3",
"@jellybrick/electron-better-web-request": "1.0.4", "@jellybrick/electron-better-web-request": "1.0.4",
"@jellybrick/mpris-service": "2.1.4", "@jellybrick/mpris-service": "2.1.5",
"@jimp/plugin-invert": "0.22.12", "@jimp/plugin-color": "1.6.0",
"@skyra/jaro-winkler": "1.1.1", "@skyra/jaro-winkler": "1.1.1",
"@xhayper/discord-rpc": "1.2.0", "@xhayper/discord-rpc": "1.2.1",
"async-mutex": "0.5.0", "async-mutex": "0.5.0",
"bgutils-js": "3.2.0",
"butterchurn": "3.0.0-beta.4", "butterchurn": "3.0.0-beta.4",
"butterchurn-presets": "3.0.0-beta.4", "butterchurn-presets": "3.0.0-beta.4",
"color": "4.2.3", "color": "5.0.0",
"conf": "13.1.0", "conf": "13.1.0",
"custom-electron-prompt": "1.5.8", "custom-electron-prompt": "1.5.8",
"dbus-next": "0.10.2", "deepmerge-ts": "7.1.5",
"deepmerge-ts": "7.1.3",
"electron-debug": "4.1.0", "electron-debug": "4.1.0",
"electron-is": "3.0.0", "electron-is": "3.0.0",
"electron-localshortcut": "3.2.1", "electron-localshortcut": "3.2.1",
"electron-store": "10.0.0", "electron-store": "10.0.1",
"electron-unhandled": "4.0.1", "electron-unhandled": "4.0.1",
"electron-updater": "6.3.9", "electron-updater": "6.3.9",
"fast-average-color": "9.4.0", "es-hangul": "2.3.2",
"fast-equals": "5.0.1", "fast-average-color": "9.5.0",
"fast-equals": "5.2.2",
"filenamify": "6.0.0", "filenamify": "6.0.0",
"hono": "4.6.14", "hanja": "1.1.4",
"happy-dom": "17.4.4",
"hono": "4.7.5",
"howler": "2.2.4", "howler": "2.2.4",
"html-to-text": "9.0.5", "html-to-text": "9.0.5",
"i18next": "24.2.0", "i18next": "24.2.3",
"jimp": "1.6.0", "jimp": "1.6.0",
"keyboardevent-from-electron-accelerator": "2.0.0", "keyboardevent-from-electron-accelerator": "2.0.0",
"keyboardevents-areequal": "0.2.2", "keyboardevents-areequal": "0.2.2",
"kuromoji": "0.1.2",
"kuroshiro": "1.2.0",
"kuroshiro-analyzer-kuromoji": "1.1.0",
"lazy-var": "2.2.2",
"node-html-parser": "7.0.1", "node-html-parser": "7.0.1",
"node-id3": "0.2.6", "node-id3": "0.2.8",
"peerjs": "1.5.4", "peerjs": "1.5.4",
"semver": "7.6.3", "pinyin": "4.0.0-alpha.2",
"segmentit": "2.0.3",
"semver": "7.7.1",
"serve": "14.2.4", "serve": "14.2.4",
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9", "simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
"solid-floating-ui": "0.3.1", "solid-floating-ui": "0.3.1",
"solid-js": "1.9.3", "solid-js": "1.9.5",
"solid-styled-components": "0.28.5", "solid-styled-components": "0.28.5",
"solid-transition-group": "0.2.3", "solid-transition-group": "0.3.0",
"ts-morph": "24.0.0", "ts-morph": "25.0.1",
"vudio": "2.1.1", "vudio": "2.1.1",
"x11": "2.3.0", "x11": "2.3.0",
"youtubei.js": "12.2.0", "youtubei.js": "13.3.0",
"zod": "3.24.1" "zod": "3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.17.0", "@eslint/js": "9.23.0",
"@playwright/test": "1.49.1", "@malept/flatpak-bundler": "0.4.0",
"@stylistic/eslint-plugin-js": "2.12.1", "@playwright/test": "1.51.1",
"@stylistic/eslint-plugin-js": "4.2.0",
"@total-typescript/ts-reset": "0.6.1", "@total-typescript/ts-reset": "0.6.1",
"@types/color": "4.2.0",
"@types/electron-localshortcut": "3.1.3", "@types/electron-localshortcut": "3.1.3",
"@types/eslint__js": "8.42.3",
"@types/howler": "2.2.12", "@types/howler": "2.2.12",
"@types/html-to-text": "9.0.4", "@types/html-to-text": "9.0.4",
"@types/semver": "7.5.8", "@types/semver": "7.5.8",
"@types/trusted-types": "2.0.7", "@types/trusted-types": "2.0.7",
"bufferutil": "4.0.8", "bufferutil": "4.0.9",
"builtin-modules": "4.0.0", "builtin-modules": "5.0.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"del-cli": "6.0.0", "del-cli": "6.0.0",
"discord-api-types": "0.37.114", "discord-api-types": "0.37.119",
"electron": "33.2.1", "electron": "35.1.0",
"electron-builder": "24.13.3", "electron-builder": "26.0.12",
"electron-builder-squirrel-windows": "26.0.12",
"electron-devtools-installer": "4.0.0", "electron-devtools-installer": "4.0.0",
"electron-vite": "2.3.0", "electron-vite": "3.1.0",
"esbuild": "0.24.2", "esbuild": "0.25.1",
"eslint": "9.17.0", "eslint": "9.23.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "10.1.1",
"eslint-import-resolver-exports": "1.0.0-beta.5", "eslint-import-resolver-exports": "1.0.0-beta.5",
"eslint-import-resolver-typescript": "3.7.0", "eslint-import-resolver-typescript": "4.2.4",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-prettier": "5.2.1", "eslint-plugin-prettier": "5.2.5",
"glob": "11.0.0", "glob": "11.0.1",
"node-gyp": "11.0.0", "node-gyp": "11.1.0",
"playwright": "1.49.1", "playwright": "1.51.1",
"rollup": "4.29.1", "rollup": "4.37.0",
"typescript": "5.7.2", "typescript": "5.8.2",
"typescript-eslint": "8.18.2", "typescript-eslint": "8.28.0",
"utf-8-validate": "6.0.5", "utf-8-validate": "6.0.5",
"vite": "6.0.6", "vite": "6.2.3",
"vite-plugin-inspect": "0.10.6", "vite-plugin-inspect": "11.0.0",
"vite-plugin-resolve": "2.5.2", "vite-plugin-resolve": "2.5.2",
"vite-plugin-solid": "2.11.0", "vite-plugin-solid": "2.11.6",
"ws": "8.18.0" "ws": "8.18.1"
}, },
"auto-changelog": { "auto-changelog": {
"hideCredit": true, "hideCredit": true,

View File

@ -1,21 +0,0 @@
diff --git a/out/targets/snap.js b/out/targets/snap.js
index f72c36355d27cd2d69fc5fdf2d8bb2451db0287f..baae112fe25ebb49ab8e25aaa48efd6bc43b598f 100644
--- a/out/targets/snap.js
+++ b/out/targets/snap.js
@@ -212,14 +212,14 @@ class SnapTarget extends core_1.Target {
args.push("--template-url", `electron4:${snapArch}`);
}
await (0, builder_util_1.executeAppBuilder)(args);
- const publishConfig = findSnapPublishConfig(this.packager.config);
+
await packager.info.callArtifactBuildCompleted({
file: artifactPath,
safeArtifactName: packager.computeSafeArtifactName(artifactName, "snap", arch, false),
target: this,
arch,
packager,
- publishConfig: publishConfig == null ? { provider: "snapStore" } : publishConfig,
+ publishConfig: options.publish == null ? { provider: "snapStore" } : null,
});
}
isElectronVersionGreaterOrEqualThan(version) {

View File

@ -1,161 +0,0 @@
diff --git a/lib/importDeclaration.js b/lib/importDeclaration.js
index afb4de779034cfea080825a5f4320661c48bee32..f10b0a11a39577fbd42569e6b0e768255c1ef276 100644
--- a/lib/importDeclaration.js
+++ b/lib/importDeclaration.js
@@ -1,5 +1,5 @@
-"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports["default"] = importDeclaration;function importDeclaration(context) {
- var ancestors = context.getAncestors();
+"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports["default"] = importDeclaration;function importDeclaration(context, node) {
+ var ancestors = context.getSourceCode().getAncestors(node);
return ancestors[ancestors.length - 1];
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbXBvcnREZWNsYXJhdGlvbi5qcyJdLCJuYW1lcyI6WyJpbXBvcnREZWNsYXJhdGlvbiIsImNvbnRleHQiLCJhbmNlc3RvcnMiLCJnZXRBbmNlc3RvcnMiLCJsZW5ndGgiXSwibWFwcGluZ3MiOiJnR0FBd0JBLGlCLENBQVQsU0FBU0EsaUJBQVQsQ0FBMkJDLE9BQTNCLEVBQW9DO0FBQ2pELE1BQU1DLFlBQVlELFFBQVFFLFlBQVIsRUFBbEI7QUFDQSxTQUFPRCxVQUFVQSxVQUFVRSxNQUFWLEdBQW1CLENBQTdCLENBQVA7QUFDRCIsImZpbGUiOiJpbXBvcnREZWNsYXJhdGlvbi5qcyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGltcG9ydERlY2xhcmF0aW9uKGNvbnRleHQpIHtcbiAgY29uc3QgYW5jZXN0b3JzID0gY29udGV4dC5nZXRBbmNlc3RvcnMoKTtcbiAgcmV0dXJuIGFuY2VzdG9yc1thbmNlc3RvcnMubGVuZ3RoIC0gMV07XG59XG4iXX0=
\ No newline at end of file
diff --git a/lib/rules/first.js b/lib/rules/first.js
index a77168660cf32c8c3e96f3ff4b8240a36d7de3a6..c0e00d75f9989916057fef3999eeee8d21820292 100644
--- a/lib/rules/first.js
+++ b/lib/rules/first.js
@@ -66,7 +66,7 @@ module.exports = {
}
}
if (nonImportCount > 0) {var _iteratorNormalCompletion = true;var _didIteratorError = false;var _iteratorError = undefined;try {
- for (var _iterator = context.getDeclaredVariables(node)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {var variable = _step.value;
+ for (var _iterator = sourceCode.getDeclaredVariables(node)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {var variable = _step.value;
if (!shouldSort) {break;}
var references = variable.references;
if (references.length) {var _iteratorNormalCompletion2 = true;var _didIteratorError2 = false;var _iteratorError2 = undefined;try {
diff --git a/lib/rules/namespace.js b/lib/rules/namespace.js
index 574d89a60d15c7e0e712956ea6a3ad2d0eac7f08..82e7cb3cff4246592d762cce86323f2b72de92e4 100644
--- a/lib/rules/namespace.js
+++ b/lib/rules/namespace.js
@@ -86,7 +86,7 @@ module.exports = {
// same as above, but does not add names to local map
ExportNamespaceSpecifier: function () {function ExportNamespaceSpecifier(namespace) {
- var declaration = (0, _importDeclaration2['default'])(context);
+ var declaration = (0, _importDeclaration2['default'])(context, namespace);
var imports = _ExportMap2['default'].get(declaration.source.value, context);
if (imports == null) {return null;}
diff --git a/lib/rules/newline-after-import.js b/lib/rules/newline-after-import.js
index 6cc15686464a17803a0b976c35b99627cdbfabee..520eec6d9a375527ab72c459960fe4416c046c17 100644
--- a/lib/rules/newline-after-import.js
+++ b/lib/rules/newline-after-import.js
@@ -194,7 +194,7 @@ module.exports = {
}return CallExpression;}(),
'Program:exit': function () {function ProgramExit() {
log('exit processing for', context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
- var scopeBody = getScopeBody(context.getScope());
+ var scopeBody = getScopeBody(context.getSourceCode().getScope(node));
log('got scope:', scopeBody);
requireCalls.forEach(function (node, index) {
diff --git a/lib/rules/no-amd.js b/lib/rules/no-amd.js
index 7ac108bf812ca4f78bfa6fe5ae8b9cf38e2ff497..346c3105dc70f72c4d76fcc6b96b946d1d4ec6d5 100644
--- a/lib/rules/no-amd.js
+++ b/lib/rules/no-amd.js
@@ -23,7 +23,7 @@ module.exports = {
create: function () {function create(context) {
return {
CallExpression: function () {function CallExpression(node) {
- if (context.getScope().type !== 'module') {return;}
+ if (context.getSourceCode().getScope(node).type !== 'module') {return;}
if (node.callee.type !== 'Identifier') {return;}
if (node.callee.name !== 'require' && node.callee.name !== 'define') {return;}
diff --git a/lib/rules/no-commonjs.js b/lib/rules/no-commonjs.js
index befeff0026d61d3ac1e6bbcea29f5c471dc1d353..e91c5ed34e968d5867e884ea800e166cda345aef 100644
--- a/lib/rules/no-commonjs.js
+++ b/lib/rules/no-commonjs.js
@@ -107,7 +107,7 @@ module.exports = {
// exports.
if (node.object.name === 'exports') {
- var isInScope = context.getScope().
+ var isInScope = context.getSourceCode().getScope(node).
variables.
some(function (variable) {return variable.name === 'exports';});
if (!isInScope) {
@@ -117,7 +117,7 @@ module.exports = {
}return MemberExpression;}(),
CallExpression: function () {function CallExpression(call) {
- if (!validateScope(context.getScope())) {return;}
+ if (!validateScope(context.getSourceCode().getScope(call))) {return;}
if (call.callee.type !== 'Identifier') {return;}
if (call.callee.name !== 'require') {return;}
diff --git a/lib/rules/no-mutable-exports.js b/lib/rules/no-mutable-exports.js
index 40bd1b4cfa95d41732bb13bba0ed1969a91cc7ff..8a25abfbfadb299204b36a6cbf283259bcc2e790 100644
--- a/lib/rules/no-mutable-exports.js
+++ b/lib/rules/no-mutable-exports.js
@@ -32,7 +32,7 @@ module.exports = {
}
function handleExportDefault(node) {
- var scope = context.getScope();
+ var scope = context.getSourceCode().getScope(node);
if (node.declaration.name) {
checkDeclarationsInScope(scope, node.declaration.name);
@@ -40,7 +40,7 @@ module.exports = {
}
function handleExportNamed(node) {
- var scope = context.getScope();
+ var scope = context.getSourceCode().getScope(node);
if (node.declaration) {
checkDeclaration(node.declaration);
diff --git a/lib/rules/no-named-as-default-member.js b/lib/rules/no-named-as-default-member.js
index 0c15051e027ad7d1d45f1b51c20be1c000b0af01..5b3d6ba415511b7f9f83a52e1acfebe5a1045a7b 100644
--- a/lib/rules/no-named-as-default-member.js
+++ b/lib/rules/no-named-as-default-member.js
@@ -35,7 +35,7 @@ module.exports = {
return {
ImportDefaultSpecifier: function () {function ImportDefaultSpecifier(node) {
- var declaration = (0, _importDeclaration2['default'])(context);
+ var declaration = (0, _importDeclaration2['default'])(context, node);
var exportMap = _ExportMap2['default'].get(declaration.source.value, context);
if (exportMap == null) {return;}
diff --git a/lib/rules/no-named-as-default.js b/lib/rules/no-named-as-default.js
index 63378a33a1c7da004c57a524cec1a1cddf23e210..c81b1f93b11628676158b79f1c4015911943cc7d 100644
--- a/lib/rules/no-named-as-default.js
+++ b/lib/rules/no-named-as-default.js
@@ -18,7 +18,7 @@ module.exports = {
// #566: default is a valid specifier
if (defaultSpecifier[nameKey].name === 'default') {return;}
- var declaration = (0, _importDeclaration2['default'])(context);
+ var declaration = (0, _importDeclaration2['default'])(context, defaultSpecifier);
var imports = _ExportMap2['default'].get(declaration.source.value, context);
if (imports == null) {return;}
diff --git a/lib/rules/no-namespace.js b/lib/rules/no-namespace.js
index 2b0c783adea788101b779b17f977bbcb582cfd3f..a7f7b202ac7c4a342febef2a993586c4cc84fc7a 100644
--- a/lib/rules/no-namespace.js
+++ b/lib/rules/no-namespace.js
@@ -43,7 +43,7 @@ var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_doc
return;
}
- var scopeVariables = context.getScope().variables;
+ var scopeVariables = context.getSourceCode().getScope(node).variables;
var namespaceVariable = scopeVariables.find(function (variable) {return variable.defs[0].node === node;});
var namespaceReferences = namespaceVariable.references;
var namespaceIdentifiers = namespaceReferences.map(function (reference) {return reference.identifier;});
diff --git a/package.json b/package.json
index 5c0af48543483a21791fa23a4a583071d3551772..5deeac3d0accc3878ef0fc93dfb52a8ca7c46e84 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,7 @@
"chai": "^4.3.10",
"cross-env": "^4.0.0",
"escope": "^3.6.0",
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8",
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9",
"eslint-doc-generator": "^1.6.1",
"eslint-import-resolver-node": "file:./resolvers/node",
"eslint-import-resolver-typescript": "^1.0.2 || ^1.1.1",

View File

@ -0,0 +1,580 @@
diff --git a/build/kuromoji.js b/build/kuromoji.js
index f0f4ae9183ff8965fda64a2042f29936f76506d1..8912a754d184742d2768854c7bba83d66f9ff95f 100644
--- a/build/kuromoji.js
+++ b/build/kuromoji.js
@@ -1,5 +1,5 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.kuromoji = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
-(function (process,global){
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.kuromoji = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+(function (process,global,setImmediate){(function (){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -666,10 +666,13 @@ var reIsUint = /^(?:0|[1-9]\d*)$/;
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
+ var type = typeof value;
length = length == null ? MAX_SAFE_INTEGER$1 : length;
+
return !!length &&
- (typeof value == 'number' || reIsUint.test(value)) &&
- (value > -1 && value % 1 == 0 && value < length);
+ (type == 'number' ||
+ (type != 'symbol' && reIsUint.test(value))) &&
+ (value > -1 && value % 1 == 0 && value < length);
}
/** `Object#toString` result references. */
@@ -755,6 +758,14 @@ var freeProcess = moduleExports$1 && freeGlobal.process;
/** Used to access faster Node.js helpers. */
var nodeUtil = (function() {
try {
+ // Use `util.types` for Node.js 10+.
+ var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types;
+
+ if (types) {
+ return types;
+ }
+
+ // Legacy `process.binding('util')` for Node.js < 10.
return freeProcess && freeProcess.binding && freeProcess.binding('util');
} catch (e) {}
}());
@@ -939,6 +950,9 @@ function createObjectIterator(obj) {
var len = okeys.length;
return function next() {
var key = okeys[++i];
+ if (key === '__proto__') {
+ return next();
+ }
return i < len ? {value: obj[key], key: key} : null;
};
}
@@ -970,6 +984,7 @@ function _eachOfLimit(limit) {
var nextElem = iterator(obj);
var done = false;
var running = 0;
+ var looping = false;
function iterateeCallback(err, value) {
running -= 1;
@@ -981,12 +996,13 @@ function _eachOfLimit(limit) {
done = true;
return callback(null);
}
- else {
+ else if (!looping) {
replenish();
}
}
function replenish () {
+ looping = true;
while (running < limit && !done) {
var elem = nextElem();
if (elem === null) {
@@ -999,6 +1015,7 @@ function _eachOfLimit(limit) {
running += 1;
iteratee(elem.value, elem.key, onlyOnce(iterateeCallback));
}
+ looping = false;
}
replenish();
@@ -3819,7 +3836,7 @@ function memoize(fn, hasher) {
/**
* Calls `callback` on a later loop around the event loop. In Node.js this just
- * calls `process.nextTicl`. In the browser it will use `setImmediate` if
+ * calls `process.nextTick`. In the browser it will use `setImmediate` if
* available, otherwise `setTimeout(callback, 0)`, which means other higher
* priority events may precede the execution of `callback`.
*
@@ -5596,8 +5613,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
})));
-}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"_process":4}],2:[function(require,module,exports){
+}).call(this)}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate)
+},{"_process":3,"timers":4}],2:[function(require,module,exports){
// Copyright (c) 2014 Takuya Asano All Rights Reserved.
(function () {
@@ -6391,234 +6408,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
})();
},{}],3:[function(require,module,exports){
-(function (process){
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// resolves . and .. elements in a path array with directory names there
-// must be no slashes, empty elements, or device names (c:\) in the array
-// (so also no leading and trailing slashes - it does not distinguish
-// relative and absolute paths)
-function normalizeArray(parts, allowAboveRoot) {
- // if the path tries to go above the root, `up` ends up > 0
- var up = 0;
- for (var i = parts.length - 1; i >= 0; i--) {
- var last = parts[i];
- if (last === '.') {
- parts.splice(i, 1);
- } else if (last === '..') {
- parts.splice(i, 1);
- up++;
- } else if (up) {
- parts.splice(i, 1);
- up--;
- }
- }
-
- // if the path is allowed to go above the root, restore leading ..s
- if (allowAboveRoot) {
- for (; up--; up) {
- parts.unshift('..');
- }
- }
-
- return parts;
-}
-
-// Split a filename into [root, dir, basename, ext], unix version
-// 'root' is just a slash, or nothing.
-var splitPathRe =
- /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
-var splitPath = function(filename) {
- return splitPathRe.exec(filename).slice(1);
-};
-
-// path.resolve([from ...], to)
-// posix version
-exports.resolve = function() {
- var resolvedPath = '',
- resolvedAbsolute = false;
-
- for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
- var path = (i >= 0) ? arguments[i] : process.cwd();
-
- // Skip empty and invalid entries
- if (typeof path !== 'string') {
- throw new TypeError('Arguments to path.resolve must be strings');
- } else if (!path) {
- continue;
- }
-
- resolvedPath = path + '/' + resolvedPath;
- resolvedAbsolute = path.charAt(0) === '/';
- }
-
- // At this point the path should be resolved to a full absolute path, but
- // handle relative paths to be safe (might happen when process.cwd() fails)
-
- // Normalize the path
- resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
- return !!p;
- }), !resolvedAbsolute).join('/');
-
- return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
-};
-
-// path.normalize(path)
-// posix version
-exports.normalize = function(path) {
- var isAbsolute = exports.isAbsolute(path),
- trailingSlash = substr(path, -1) === '/';
-
- // Normalize the path
- path = normalizeArray(filter(path.split('/'), function(p) {
- return !!p;
- }), !isAbsolute).join('/');
-
- if (!path && !isAbsolute) {
- path = '.';
- }
- if (path && trailingSlash) {
- path += '/';
- }
-
- return (isAbsolute ? '/' : '') + path;
-};
-
-// posix version
-exports.isAbsolute = function(path) {
- return path.charAt(0) === '/';
-};
-
-// posix version
-exports.join = function() {
- var paths = Array.prototype.slice.call(arguments, 0);
- return exports.normalize(filter(paths, function(p, index) {
- if (typeof p !== 'string') {
- throw new TypeError('Arguments to path.join must be strings');
- }
- return p;
- }).join('/'));
-};
-
-
-// path.relative(from, to)
-// posix version
-exports.relative = function(from, to) {
- from = exports.resolve(from).substr(1);
- to = exports.resolve(to).substr(1);
-
- function trim(arr) {
- var start = 0;
- for (; start < arr.length; start++) {
- if (arr[start] !== '') break;
- }
-
- var end = arr.length - 1;
- for (; end >= 0; end--) {
- if (arr[end] !== '') break;
- }
-
- if (start > end) return [];
- return arr.slice(start, end - start + 1);
- }
-
- var fromParts = trim(from.split('/'));
- var toParts = trim(to.split('/'));
-
- var length = Math.min(fromParts.length, toParts.length);
- var samePartsLength = length;
- for (var i = 0; i < length; i++) {
- if (fromParts[i] !== toParts[i]) {
- samePartsLength = i;
- break;
- }
- }
-
- var outputParts = [];
- for (var i = samePartsLength; i < fromParts.length; i++) {
- outputParts.push('..');
- }
-
- outputParts = outputParts.concat(toParts.slice(samePartsLength));
-
- return outputParts.join('/');
-};
-
-exports.sep = '/';
-exports.delimiter = ':';
-
-exports.dirname = function(path) {
- var result = splitPath(path),
- root = result[0],
- dir = result[1];
-
- if (!root && !dir) {
- // No dirname whatsoever
- return '.';
- }
-
- if (dir) {
- // It has a dirname, strip trailing slash
- dir = dir.substr(0, dir.length - 1);
- }
-
- return root + dir;
-};
-
-
-exports.basename = function(path, ext) {
- var f = splitPath(path)[2];
- // TODO: make this comparison case-insensitive on windows?
- if (ext && f.substr(-1 * ext.length) === ext) {
- f = f.substr(0, f.length - ext.length);
- }
- return f;
-};
-
-
-exports.extname = function(path) {
- return splitPath(path)[3];
-};
-
-function filter (xs, f) {
- if (xs.filter) return xs.filter(f);
- var res = [];
- for (var i = 0; i < xs.length; i++) {
- if (f(xs[i], i, xs)) res.push(xs[i]);
- }
- return res;
-}
-
-// String.prototype.substr - negative index don't work in IE8
-var substr = 'ab'.substr(-1) === 'b'
- ? function (str, start, len) { return str.substr(start, len) }
- : function (str, start, len) {
- if (start < 0) start = str.length + start;
- return str.substr(start, len);
- }
-;
-
-}).call(this,require('_process'))
-},{"_process":4}],4:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
@@ -6804,7 +6593,86 @@ process.chdir = function (dir) {
};
process.umask = function() { return 0; };
-},{}],5:[function(require,module,exports){
+},{}],4:[function(require,module,exports){
+(function (setImmediate,clearImmediate){(function (){
+var nextTick = require('process/browser.js').nextTick;
+var apply = Function.prototype.apply;
+var slice = Array.prototype.slice;
+var immediateIds = {};
+var nextImmediateId = 0;
+
+// DOM APIs, for completeness
+
+exports.setTimeout = function() {
+ return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
+};
+exports.setInterval = function() {
+ return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
+};
+exports.clearTimeout =
+exports.clearInterval = function(timeout) { timeout.close(); };
+
+function Timeout(id, clearFn) {
+ this._id = id;
+ this._clearFn = clearFn;
+}
+Timeout.prototype.unref = Timeout.prototype.ref = function() {};
+Timeout.prototype.close = function() {
+ this._clearFn.call(window, this._id);
+};
+
+// Does not start the time, just sets up the members needed.
+exports.enroll = function(item, msecs) {
+ clearTimeout(item._idleTimeoutId);
+ item._idleTimeout = msecs;
+};
+
+exports.unenroll = function(item) {
+ clearTimeout(item._idleTimeoutId);
+ item._idleTimeout = -1;
+};
+
+exports._unrefActive = exports.active = function(item) {
+ clearTimeout(item._idleTimeoutId);
+
+ var msecs = item._idleTimeout;
+ if (msecs >= 0) {
+ item._idleTimeoutId = setTimeout(function onTimeout() {
+ if (item._onTimeout)
+ item._onTimeout();
+ }, msecs);
+ }
+};
+
+// That's not how node.js implements it but the exposed api is the same.
+exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) {
+ var id = nextImmediateId++;
+ var args = arguments.length < 2 ? false : slice.call(arguments, 1);
+
+ immediateIds[id] = true;
+
+ nextTick(function onNextTick() {
+ if (immediateIds[id]) {
+ // fn.call() is faster so we optimize for the common use-case
+ // @see http://jsperf.com/call-apply-segu
+ if (args) {
+ fn.apply(null, args);
+ } else {
+ fn.call(null);
+ }
+ // Prevent ids from leaking
+ exports.clearImmediate(id);
+ }
+ });
+
+ return id;
+};
+
+exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) {
+ delete immediateIds[id];
+};
+}).call(this)}).call(this,require("timers").setImmediate,require("timers").clearImmediate)
+},{"process/browser.js":3,"timers":4}],5:[function(require,module,exports){
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';function n(e){throw e;}var p=void 0,aa=this;function t(e,b){var d=e.split("."),c=aa;!(d[0]in c)&&c.execScript&&c.execScript("var "+d[0]);for(var a;d.length&&(a=d.shift());)!d.length&&b!==p?c[a]=b:c=c[a]?c[a]:c[a]={}};var x="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;new (x?Uint8Array:Array)(256);var y;for(y=0;256>y;++y)for(var A=y,ba=7,A=A>>>1;A;A>>>=1)--ba;function B(e,b,d){var c,a="number"===typeof b?b:b=0,f="number"===typeof d?d:e.length;c=-1;for(a=f&7;a--;++b)c=c>>>8^C[(c^e[b])&255];for(a=f>>3;a--;b+=8)c=c>>>8^C[(c^e[b])&255],c=c>>>8^C[(c^e[b+1])&255],c=c>>>8^C[(c^e[b+2])&255],c=c>>>8^C[(c^e[b+3])&255],c=c>>>8^C[(c^e[b+4])&255],c=c>>>8^C[(c^e[b+5])&255],c=c>>>8^C[(c^e[b+6])&255],c=c>>>8^C[(c^e[b+7])&255];return(c^4294967295)>>>0}
var D=[0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,
2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,
@@ -6984,7 +6852,7 @@ module.exports = Tokenizer;
"use strict";
var Tokenizer = require("./Tokenizer");
-var DictionaryLoader = require("./loader/NodeDictionaryLoader");
+var BrowserDictionaryLoader = require("./loader/BrowserDictionaryLoader");
/**
* TokenizerBuilder create Tokenizer instance.
@@ -7005,7 +6873,7 @@ function TokenizerBuilder(option) {
* @param {TokenizerBuilder~onLoad} callback Callback function
*/
TokenizerBuilder.prototype.build = function (callback) {
- var loader = new DictionaryLoader(this.dic_path);
+ var loader = new BrowserDictionaryLoader(this.dic_path);
loader.load(function (err, dic) {
callback(err, new Tokenizer(dic));
});
@@ -7020,7 +6888,7 @@ TokenizerBuilder.prototype.build = function (callback) {
module.exports = TokenizerBuilder;
-},{"./Tokenizer":6,"./loader/NodeDictionaryLoader":19}],8:[function(require,module,exports){
+},{"./Tokenizer":6,"./loader/BrowserDictionaryLoader":19}],8:[function(require,module,exports){
/*
* Copyright 2014 Takuya Asano
* Copyright 2010-2014 Atilika Inc. and contributors
@@ -8163,7 +8031,6 @@ module.exports = BrowserDictionaryLoader;
"use strict";
-var path = require("path");
var async = require("async");
var DynamicDictionaries = require("../dict/DynamicDictionaries");
@@ -8194,7 +8061,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Trie
function (callback) {
async.map([ "base.dat.gz", "check.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
@@ -8214,7 +8081,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Token info dictionaries
function (callback) {
async.map([ "tid.dat.gz", "tid_pos.dat.gz", "tid_map.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
@@ -8234,7 +8101,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
},
// Connection cost matrix
function (callback) {
- loadArrayBuffer(path.join(dic_path, "cc.dat.gz"), function (err, buffer) {
+ loadArrayBuffer(dic_path + "cc.dat.gz", function (err, buffer) {
if(err) {
return callback(err);
}
@@ -8246,7 +8113,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Unknown dictionaries
function (callback) {
async.map([ "unk.dat.gz", "unk_pos.dat.gz", "unk_map.dat.gz", "unk_char.dat.gz", "unk_compat.dat.gz", "unk_invoke.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
@@ -8282,7 +8149,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
module.exports = DictionaryLoader;
-},{"../dict/DynamicDictionaries":11,"async":1,"path":3}],21:[function(require,module,exports){
+},{"../dict/DynamicDictionaries":11,"async":1}],21:[function(require,module,exports){
/*
* Copyright 2014 Takuya Asano
* Copyright 2010-2014 Atilika Inc. and contributors
diff --git a/src/TokenizerBuilder.js b/src/TokenizerBuilder.js
index 9ef5c6a2efc63e8b12735a8a9f1cb08d6c52c20c..98881e9fd731047c3fca848a71ede7e381e74f51 100644
--- a/src/TokenizerBuilder.js
+++ b/src/TokenizerBuilder.js
@@ -18,7 +18,7 @@
"use strict";
var Tokenizer = require("./Tokenizer");
-var DictionaryLoader = require("./loader/NodeDictionaryLoader");
+var BrowserDictionaryLoader = require("./loader/BrowserDictionaryLoader");
/**
* TokenizerBuilder create Tokenizer instance.
@@ -39,7 +39,7 @@ function TokenizerBuilder(option) {
* @param {TokenizerBuilder~onLoad} callback Callback function
*/
TokenizerBuilder.prototype.build = function (callback) {
- var loader = new DictionaryLoader(this.dic_path);
+ var loader = new BrowserDictionaryLoader(this.dic_path);
loader.load(function (err, dic) {
callback(err, new Tokenizer(dic));
});
diff --git a/src/loader/DictionaryLoader.js b/src/loader/DictionaryLoader.js
index 5f88c0b7f9a786dd8c072a7b84ae86a6f31412cb..3d6f8a67e16d251b3e4ba4dbbbc947679c364382 100644
--- a/src/loader/DictionaryLoader.js
+++ b/src/loader/DictionaryLoader.js
@@ -17,7 +17,6 @@
"use strict";
-var path = require("path");
var async = require("async");
var DynamicDictionaries = require("../dict/DynamicDictionaries");
@@ -48,7 +47,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Trie
function (callback) {
async.map([ "base.dat.gz", "check.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
@@ -68,7 +67,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Token info dictionaries
function (callback) {
async.map([ "tid.dat.gz", "tid_pos.dat.gz", "tid_map.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
@@ -88,7 +87,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
},
// Connection cost matrix
function (callback) {
- loadArrayBuffer(path.join(dic_path, "cc.dat.gz"), function (err, buffer) {
+ loadArrayBuffer(dic_path + "cc.dat.gz", function (err, buffer) {
if(err) {
return callback(err);
}
@@ -100,7 +99,7 @@ DictionaryLoader.prototype.load = function (load_callback) {
// Unknown dictionaries
function (callback) {
async.map([ "unk.dat.gz", "unk_pos.dat.gz", "unk_map.dat.gz", "unk_char.dat.gz", "unk_compat.dat.gz", "unk_invoke.dat.gz" ], function (filename, _callback) {
- loadArrayBuffer(path.join(dic_path, filename), function (err, buffer) {
+ loadArrayBuffer(dic_path + filename, function (err, buffer) {
if(err) {
return _callback(err);
}
diff --git a/src/loader/NodeDictionaryLoader.js b/src/loader/NodeDictionaryLoader.js
deleted file mode 100644
index 26eb79249121efe39bd5ae77c17e1caa197fb4ce..0000000000000000000000000000000000000000

5107
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", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends": ["config:recommended"],
"config:base"
],
"labels": ["dependencies"], "labels": ["dependencies"],
"postUpdateOptions": ["pnpmDedupe"] "postUpdateOptions": ["pnpmDedupe"]
} }

View File

@ -202,7 +202,7 @@
"show": "عرض النافدة", "show": "عرض النافدة",
"tooltip": { "tooltip": {
"default": "يوتيوب اغاني", "default": "يوتيوب اغاني",
"with-song-info": "يوتيوب أغاني: {{الفنان}}-{{العنوان}}" "with-song-info": "أغاني يوتيوب: {{artist}} - {{title}}"
} }
} }
}, },
@ -219,7 +219,7 @@
"name": "حاجب الإعلانات" "name": "حاجب الإعلانات"
}, },
"album-actions": { "album-actions": {
"description": "يضيف أزرار \"إلغاء عدم الإعجاب\"، \"عدم الإعجاب\"، \"الإعجاب\"، و\"إلغاء الإعجاب\" لتطبيقها على جميع الأغاني في قائمة التشغيل أو الألبوم", "description": "يضيف أزرار \"إلغاء عدم الاعجاب\" و\"عدم الاعجاب\" و\"الإعجاب\" و\"إلغاء الإعجاب\" لتطبيق ذلك على جميع الأغاني في قائمة تشغيل أو ألبوم",
"name": "إجراءات الألبوم" "name": "إجراءات الألبوم"
}, },
"album-color-theme": { "album-color-theme": {
@ -279,6 +279,13 @@
}, },
"name": "الوضع المحيطي" "name": "الوضع المحيطي"
}, },
"amuse": {
"description": "تكامل دعم YouTube Music مع ويدجت Amuse لعرض الأغنية قيد التشغيل، من إنتاج 6K Labs",
"name": "تلسيه",
"response": {
"query": "خادم Amuse API قيد التشغيل. استخدم GET /query للحصول على معلومات الأغنية."
}
},
"api-server": { "api-server": {
"description": "يضيف خادم للتحكم في المشغل", "description": "يضيف خادم للتحكم في المشغل",
"dialog": { "dialog": {
@ -286,41 +293,544 @@
"buttons": { "buttons": {
"allow": "سماح", "allow": "سماح",
"deny": "رفض" "deny": "رفض"
} },
"message": "السماح لـ {{ID}} ({{origin}}) بالوصول إلى واجهة برمجة التطبيقات (API)؟",
"title": "طلب السماح بالوصول إلى واجهة برمجة التطبيقات(API)"
} }
}, },
"menu": { "menu": {
"auth-strategy": {
"label": "نهج التفويض",
"submenu": {
"auth-at-first": {
"label": "التفويض المبدئي عند الطلب الأول"
},
"none": {
"label": "بدون تفويض"
}
}
},
"hostname": { "hostname": {
"label": "اسم المضيف" "label": "اسم المضيف"
},
"port": {
"label": "المنفذ"
} }
}, },
"name": "خادم API [تجريبي]",
"prompt": { "prompt": {
"hostname": { "hostname": {
"label": "أدخل اسم المضيف (مثل 0.0.0.0) لخادم API:",
"title": "اسم الخادم" "title": "اسم الخادم"
},
"port": {
"label": "أدخل المنفذ لخادم API:",
"title": "منفذ"
} }
} }
}, },
"audio-compressor": {
"description": "تطبيق الضغط على الصوت (يخفض مستوى صوت الأجزاء الأعلى من الإشارة ويرفع مستوى صوت الأجزاء الأكثر نعومة)",
"name": "ضاغط الصوت"
},
"blur-nav-bar": { "blur-nav-bar": {
"description": "يجعل شريط التنقل شفاف و ضبابي" "description": "يجعل شريط التنقل شفاف و ضبابي",
"name": "تغبيش شريط التنقل"
}, },
"bypass-age-restrictions": { "bypass-age-restrictions": {
"description": "تجاوز تَحَقّق اليوتيوب من السن", "description": "تجاوز تَحَقّق اليوتيوب من السن",
"name": "تجاوز التحقق من السن" "name": "تجاوز التحقق من السن"
}, },
"captions-selector": {
"description": "محدد ترجمات المقاطع الصوتية لYoutube Music",
"menu": {
"autoload": "اختار اخر ترجمة مستخدمة تلقائيا",
"disable-captions": "لا توجد ترجمات بشكل افتراضي"
},
"name": "محدد الترجمة",
"prompt": {
"selector": {
"label": "لغة الترجمة الحالية: {{language}}",
"none": "لا شيء",
"title": "اختار لغة الترجمة"
}
},
"templates": {
"title": "فتح محدد الترجمة"
}
},
"compact-sidebar": {
"description": "قم دائمًا بتعيين الشريط الجانبي في الوضع الملموم",
"name": "شريط جانبي ملموم"
},
"crossfade": {
"description": "التداخل بين الأغاني",
"menu": {
"advanced": "متقدم"
},
"name": "التداخل بين الأغاني [تجريبي]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "مدة التداخل (بأجزاء الثانية)",
"fade-out-duration": "مدة التلاشي (جزء ثانية)",
"fade-scaling": {
"label": "توسيع التداخل",
"linear": "خطي",
"logarithmic": "لوغاريتمي"
},
"seconds-before-end": "التلاشي قبل النهاية بـ N ثوانٍ"
},
"title": "خيارات التداخل"
}
}
},
"disable-autoplay": {
"description": "يجعل الأغنية تبدأ في وضع \"الإيقاف المؤقت\"",
"menu": {
"apply-once": "ينطبق فقط عند بدء التشغيل"
},
"name": "تعطيل التشغيل التلقائي"
},
"discord": {
"backend": {
"already-connected": "تمت محاولة الاتصال بالاتصال النشط",
"connected": "متصل بDiscord",
"disconnected": "انقطع الاتصال بDiscord"
},
"description": "أظهر لأصدقائك ما تستمع إليه من خلال Rich Presence",
"menu": {
"auto-reconnect": "إعادة اتصال تلقائي",
"clear-activity": "مسح النشاط",
"clear-activity-after-timeout": "مسح النشاط بعد انتهاء المهلة",
"connected": "متصل",
"disconnected": "قطع الاتصال",
"hide-duration-left": "إخفاء المدة المتبقية",
"hide-github-button": "إخفاء زر رابط GitHub",
"play-on-youtube-music": "شغل في YouTube Music",
"set-inactivity-timeout": "ضبط مهلة عدم النشاط"
},
"name": "حالة ديسكورد",
"prompt": {
"set-inactivity-timeout": {
"label": "أدخل مهلة عدم النشاط بالثواني:",
"title": "ضبط مهلة عدم النشاط"
}
}
},
"downloader": { "downloader": {
"backend": { "backend": {
"dialog": {
"error": {
"buttons": {
"ok": "حسنا"
},
"message": "نعتذر، فشل التحميل…",
"title": "خطأ في التحميل!"
},
"start-download-playlist": {
"buttons": {
"ok": "حسنا"
},
"detail": "({{playlistSize}} أغنية)",
"message": "تحميل القائمة {{playlistTitle}}",
"title": "بدأ التحميل"
}
},
"feedback": { "feedback": {
"conversion-progress": "التحويل: {{percent}}%",
"converting": "جارٍ التحويل…",
"done": "تم: {{filePath}}",
"download-info": "تحميل {{artist}} - {{title}} {{videoId}}",
"download-progress": "تحميل: {{percent}}%",
"downloading": "تحميل…",
"downloading-counter": "تنزيل {{current}}/{{total}}…", "downloading-counter": "تنزيل {{current}}/{{total}}…",
"downloading-playlist": "يتم تحميل القائمة \"{{playlistTitle}}\" - {{playlistSize}} أغاني ({{playlistId}})",
"error-while-downloading": "خطأ في تحميل \"{{author}} - {{title}}\": {{error}}", "error-while-downloading": "خطأ في تحميل \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "الملف {{playlistFolder}} موجود بالفعل",
"getting-playlist-info": "الحصول على معلومات القائمة…",
"loading": "جار التحميل…", "loading": "جار التحميل…",
"playlist-has-only-one-song": "تحتوي قائمة التشغيل على عنصر واحد فقط، يتم تحميله الأن",
"playlist-id-not-found": "لم يتم العثور على معرف قائمة التشغيل",
"playlist-is-empty": "قائمة التشغيل فارغة",
"playlist-is-mix-or-private": "حدث خطأ أثناء الحصول على معلومات قائمة التشغيل: تأكد من أنها ليست قائمة تشغيل خاصة أو قائمة تشغيل \"مختلطة لك\"\n\n{{error}}",
"preparing-file": "يتم تجهيز الملف…", "preparing-file": "يتم تجهيز الملف…",
"saving": "يتم الحفظ…", "saving": "يتم الحفظ…",
"video-id-not-found": "لم يتم ايجاد الفيديو" "trying-to-get-playlist-id": "محاولة الحصول على معرف قائمة التشغيل: {{playlistId}}",
"video-id-not-found": "لم يتم ايجاد الفيديو",
"writing-id3": "كتابة علامات ID3…"
}
},
"description": "يقوم بتنزيل ملفات MP3/مصدر الصوت مباشرة من الواجهة",
"menu": {
"choose-download-folder": "اختر مكان التحميل",
"download-finish-settings": {
"label": "تحميل عند الانتهاء",
"prompt": {
"last-percent": "بعد ( عدد مجهول ) بالمئة",
"last-seconds": "آخر (x) ثانية",
"title": "تكوين وقت التحميل"
},
"submenu": {
"advanced": "متقدم",
"enabled": "مفعل",
"mode": "وضع الوقت",
"percent": "النسبة",
"seconds": "ثواني"
}
},
"download-playlist": "تحميل قائمة التشغيل",
"presets": "الإعدادات المسبقة",
"skip-existing": "تخطي الملفات الموجودة"
},
"name": "أداة التنزيل",
"renderer": {
"can-not-update-progress": "لا يمكن تحديث التقدم"
},
"templates": {
"button": "تحميل"
}
},
"equalizer": {
"description": "يضيف معادل صوتي للمشغل",
"menu": {
"presets": {
"label": "إعدادات مسبقة",
"list": {
"bass-booster": "مزود البيس"
}
}
},
"name": "معادل صوتي"
},
"exponential-volume": {
"description": "يجعل شريط تمرير مستوى الصوت أسيًا بحيث يسهل تحديد مستويات الصوت الأقل.",
"name": "الصوت الأسي"
},
"in-app-menu": {
"description": "يعطي أشرطة القوائم مظهرًا أنيقًا و داكنًا أو بلون الألبوم",
"menu": {
"hide-dom-window-controls": "إخفاء عناصر التحكم في نافذة DOM"
},
"name": "قائمة داخل التطبيق"
},
"lumiastream": {
"description": "يضيف دعم Lumia Stream",
"name": "Lumia Stream [بيتا]"
},
"lyrics-genius": {
"description": "يضيف دعم الكلمات لمعظم الأغاني",
"menu": {
"romanized-lyrics": "كلمات مكتوبة بحروف رومانية"
},
"name": "كلمات الأغاني من Genius",
"renderer": {
"fetched-lyrics": "تم جلب الكلمات من Genius"
}
},
"music-together": {
"description": "مشاركة قائمة تشغيل مع الآخرين. عندما يقوم المضيف بتشغيل أغنية، سيسمع الجميع نفس الأغنية",
"dialog": {
"enter-host": "أدخل معرف المضيف"
},
"internal": {
"save": "حفظ",
"track-source": "مصدر الاغنية",
"unknown-user": "مستخدم مجهول"
},
"menu": {
"click-to-copy-id": "نسخ معرف المستضيف",
"close": "إغلاق \"الموسيقى معًا\"",
"connected-users": "المستخدمون المتصلون",
"disconnect": "قطع اتصال من \"الموسيقى معًا\"",
"empty-user": "لا يوجد مستعملون متصلون",
"host": "مضيف \"الموسيقى معًا\"",
"join": "الانضمام إلى \"الموسيقى معا\"",
"permission": {
"all": "السماح للضيوف بالتحكم في قائمة التشغيل والمشغل",
"host-only": "فقط المضيف يستطيع التحكم بالقائمة و المشغل",
"playlist": "السماح للضيوف بالتحكم بقائمة التشغيل"
},
"set-permission": "تغيير إذن التحكم",
"status": {
"disconnected": "قطع الاتصال",
"guest": "متصل كضيف",
"host": "متصل كمضيف"
}
},
"name": "الموسيقى معا [بيتا]",
"toast": {
"add-song-failed": "فشل في إضافة أغنية",
"closed": "تم إغلاق \"الموسيقى معا\"",
"disconnected": "تم قطع اتصال \"الموسيقى معًا\"",
"host-failed": "فشل في استضافة \"الموسيقى معا\"",
"id-copied": "تم نسخ معرف المضيف",
"id-copy-failed": "لم يتم نسخ معرف المضيف",
"join-failed": "فشل الانضمام إلى \"الموسيقى معا\"",
"joined": "تم الانضمام إلى \"الموسيقى معا\"",
"permission-changed": "تم تغيير إذن \"الموسيقى معًا\" إلى \"{{permission}}\"",
"remove-song-failed": "فشل في إزالة الأغنية",
"user-connected": "{{name}} انضم إلى \"الموسيقى معًا\"",
"user-disconnected": "{{name}} غادر \"الموسيقى معًا\""
}
},
"navigation": {
"description": "أسهم التنقل \"التالي/السابق\" مدمجة مباشرة في الواجهة، كما في متصفحك",
"name": "التنقل"
},
"no-google-login": {
"description": "إزالة أزرار وروابط تسجيل الدخول بجوجل من الواجهة",
"name": "لا يوجد تسجيل دخول بجوجل"
},
"notifications": {
"description": "عرض إشعار عندما تبدأ الأغنية بالتشغيل (الإشعارات التفاعلية متوفرة على ويندوز)",
"menu": {
"interactive": "إشعارات تفاعلية",
"interactive-settings": {
"label": "إعدادات تفاعلية",
"submenu": {
"hide-button-text": "إخفاء زر النص",
"refresh-on-play-pause": "تحديث عند التشغيل/الإيقاف المؤقت",
"tray-controls": "فتح/إغلاق عند النقر على علامة الشريط"
}
},
"priority": "أولوية الإشعار",
"toast-style": "تنسيق التوست",
"unpause-notification": "إظهار إشعار عند استئناف التشغيل"
},
"name": "الإشعارات"
},
"picture-in-picture": {
"description": "يسمح بتحويل التطبيق إلى وضع الصورة داخل الصورة",
"menu": {
"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": "التحكم في مستوى الصوت بدقة باستخدام عجلة الفأرة/مفاتيح الاختصار، مع واجهة مستخدم مخصصة وقابلة للتخصيص وخطوات صوتية قابلة للتعديل",
"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": "إضافة دعم Scrobbling (مثل Last.fm، ListenBrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "فشل المصادقة مع Last.fm\nإخفاء النافذة المنبثقة حتى إعادة التشغيل التالية.",
"title": "فشلت المصادقة"
}
} }
}, },
"menu": { "menu": {
"choose-download-folder": "اختر مكان التحميل" "lastfm": {
"api-settings": "إعدادات Last.fm API"
},
"listenbrainz": {
"token": "أدخل رمز مستخدم ListenBrainz"
},
"scrobble-other-media": "Scrobble الوسائط الأخرى"
},
"name": "أداة تتبع الاستماع",
"prompt": {
"lastfm": {
"api-key": "مفتاح Last.fm API",
"api-secret": "الرمز السري لـ Last.fm API"
},
"listenbrainz": {
"token": {
"label": "أدخل رمز مستخدم ListenBrainz الخاص بك:",
"title": "رمز ListenBrainz"
}
}
} }
},
"shortcuts": {
"description": "يسمح بضبط اختصارات لوحة المفاتيح العالمية للتحكم في التشغيل (تشغيل/إيقاف مؤقت/التالي/السابق) وإيقاف تشغيل OSD الوسائط عن طريق تجاوز مفاتيح الوسائط، وتشغيل Ctrl/CMD + F للبحث، وتفعيل دعم Linux 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": "SponsorBlock"
},
"synced-lyrics": {
"description": "يوفر كلمات الأغاني المتزامنة باستخدام مزودين مثل LRClib.",
"errors": {
"fetch": "⚠️ حدث خطأ أثناء جلب كلمات الأغنية.\nيرجى المحاولة مرة أخرى لاحقًا.",
"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": "التحكم في المشغل من شريط المهام ويندوز",
"name": "التحكم بالوسائط من شريط المهام"
},
"touchbar": {
"description": "يضيف أداة TouchBar لمستخدمي macOS",
"name": "شريط اللمس (TouchBar)"
},
"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

@ -158,6 +158,14 @@
}, },
"remove-upgrade-button": "Премахване на \"Ъпгрейд\" бутона", "remove-upgrade-button": "Премахване на \"Ъпгрейд\" бутона",
"theme": { "theme": {
"dialog": {
"button": {
"cancel": "Откажи",
"remove": "Премахни"
},
"remove-theme": "Сигурни ли сте, че искате да премахнете персонализираната тема?",
"remove-theme-message": "Това ще премахне персонализираната тема"
},
"label": "Тема", "label": "Тема",
"submenu": { "submenu": {
"import-css-file": "Импортиране на потребителски CSS файл", "import-css-file": "Импортиране на потребителски CSS файл",
@ -172,7 +180,26 @@
"enabled": "Активирани", "enabled": "Активирани",
"label": "Плъгини", "label": "Плъгини",
"new": "НОВО" "new": "НОВО"
},
"view": {
"label": "Изглед",
"submenu": {
"force-reload": "Презареди принудително",
"reload": "Презареди",
"reset-zoom": "Истински размер",
"toggle-fullscreen": "Превключи на пълен екран",
"zoom-in": "Увеличи",
"zoom-out": "Намали"
}
} }
},
"tray": {
"next": "Следващ",
"play-pause": "Пусни/Паузирай",
"previous": "Предишен",
"quit": "Изход",
"restart": "Рестартирай приложението",
"show": "Покажи прозорец"
} }
} }
} }

View File

@ -279,6 +279,9 @@
}, },
"name": "Ambientní režim" "name": "Ambientní režim"
}, },
"amuse": {
"description": "Přídá YouTube Music podporu pro Amuse právě těď hraje widget od 6k Labs"
},
"api-server": { "api-server": {
"description": "Vlož API server abys mohl ovládat přehrávač", "description": "Vlož API server abys mohl ovládat přehrávač",
"dialog": { "dialog": {

315
src/i18n/resources/da.json Normal file
View File

@ -0,0 +1,315 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Fejl ved udføring af plugin {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} udført på {{ms}}ms",
"initialize-failed": "Fejl ved igangsætning af plugin \"{{pluginName}}\"",
"load-all": "Indlæser alle plugins",
"load-failed": "Fejl ved indlæsning af plugin \"{{pluginName}}\"",
"loaded": "Plugin \"{{pluginName}}\" indlæst",
"unload-failed": "Fejl ved unload af plugin \"{{pluginName}}\""
}
}
},
"language": {
"code": "dk",
"local-name": "Dansk",
"name": "Danish"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Indlæsning færdig. DevTools åbnet"
},
"i18n": {
"loaded": "i18n indlæst"
},
"second-instance": {
"receive-command": "Modtog kommando over protokol: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS fil \"{{cssFile}}\" eksisterer ikke, ignorere"
},
"unresponsive": {
"details": "Uresponsiv fejl!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Rydder op i appens cache"
},
"window": {
"tried-to-render-offscreen": "Windows forsøgte at indlæse uden for skærmen, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menuen er gemt, brug 'Alt' knappen for at vise den igen (eller 'Escape' hvis In-App menuen bruges)",
"message": "Skjul menuen er aktiveret",
"title": "Skjult menu aktiveret"
},
"need-to-restart": {
"buttons": {
"later": "Senere",
"restart-now": "Genstart nu"
},
"detail": "\"{{pluginName}}\" plugin kræver en genstart for at have en effekt",
"message": "\"{{pluginName}}\" skal genstarte",
"title": "Genstart krævet"
},
"unresponsive": {
"buttons": {
"quit": "Afslut",
"relaunch": "Genåben",
"wait": "Vent"
},
"detail": "Vi undskylder for ubelejligheden! Vælg næste handling:",
"message": "Appen svarer ikke",
"title": "Vindue svarer ikke"
},
"update-available": {
"buttons": {
"disable": "Slå opdateringer fra",
"download": "Hent",
"ok": "OK"
},
"detail": "En ny version er tilgængelig og kan downloades her: {{downloadLink}}",
"message": "En ny version er tilgængelig",
"title": "Opdatering tilgængelig"
}
},
"menu": {
"about": "Om",
"navigation": {
"label": "Navigering",
"submenu": {
"copy-current-url": "Kopier nuværende URL",
"go-back": "Tilbage",
"go-forward": "Frem",
"quit": "Afslut",
"restart": "Genstart Appen"
}
},
"options": {
"label": "Indstillinger",
"submenu": {
"advanced-options": {
"label": "Avancerede indstillinger",
"submenu": {
"auto-reset-app-cache": "Nulstil app cache når appen starter",
"disable-hardware-acceleration": "Deaktiver hardware acceleration",
"edit-config-json": "Rediger config.json",
"restart-on-config-changes": "Genstart ved config ændringer",
"set-proxy": {
"label": "Indstil proxy",
"prompt": {
"label": "Skriv proxy adresse: (Efterlad tom for at deaktivere)",
"placeholder": "Eksempel: SOCKS5://127.0.0.1:9999",
"title": "Sæt proxy"
}
},
"toggle-dev-tools": "Skift DevTools"
}
},
"always-on-top": "Altid øverst",
"auto-update": "Automatisk opdatering",
"hide-menu": {
"dialog": {
"message": "Menuen vil være lukket næste gang appen starter. Brug [Alt] for at vise den (Eller backtick [`] hvis in-app-menu bruges)",
"title": "Gemt menu aktiveret"
},
"label": "Skjul menu"
},
"language": {
"dialog": {
"message": "Sproget vil blive ændret efter genstart",
"title": "Sprog ændret"
},
"label": "Sprog",
"submenu": {
"to-help-translate": "Vil du hjælpe med at oversætte? Klik her"
}
},
"resume-on-start": "Genoptag sidste sang når appen starter",
"start-at-login": "Start ved login",
"starting-page": {
"label": "Startside",
"unset": "Ikke valgt"
},
"tray": {
"submenu": {
"disabled": "Deaktiveret",
"enabled-and-show-app": "Aktiver og vis app",
"play-pause-on-click": "Start/Stop ved klik"
}
},
"visual-tweaks": {
"submenu": {
"like-buttons": {
"default": "Standard",
"hide": "Skjul",
"label": "Like knapper"
},
"remove-upgrade-button": "Fjern opgrader knappen",
"theme": {
"dialog": {
"button": {
"remove": "Fjern"
}
},
"label": "Tema",
"submenu": {
"no-theme": "Intet tema"
}
}
}
}
}
},
"plugins": {
"enabled": "Aktiveret",
"label": "Plugins",
"new": "NY"
},
"view": {
"label": "Vis",
"submenu": {
"reload": "Genindlæs",
"zoom-in": "Zoom ind",
"zoom-out": "Zoom ud"
}
}
},
"tray": {
"next": "Næste",
"play-pause": "Afspil",
"previous": "Sidste",
"quit": "Luk",
"restart": "Genstart app",
"show": "Vis vindue",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"ad-speedup": {
"description": "Hvis en reklame afspilles, slår den lyden fra og sætter hastigheden til 16x",
"name": "Spol igennem reklamen"
},
"adblocker": {
"description": "Bloker alle reklamer og sporing fra starten af",
"menu": {
"blocker": "Bloker"
},
"name": "Bloker reklamer"
},
"album-color-theme": {
"menu": {
"color-mix-ratio": {
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Albummets farve tema"
},
"ambient-mode": {
"menu": {
"blur-amount": {
"label": "Sløringsmængde",
"submenu": {
"pixels": "{{blurAmount}} pixel"
}
},
"buffer": {
"label": "Buffer",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Gennemsigtighed",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Kvalitet",
"submenu": {
"pixels": "{{quality}} pixel"
}
},
"size": {
"label": "Størrelse",
"submenu": {
"percent": "{{size}}%"
}
},
"use-fullscreen": {
"label": "Bruger fuldskærm"
}
}
},
"api-server": {
"dialog": {
"request": {
"buttons": {
"allow": "Tillad",
"deny": "Afvis"
},
"message": "Tillad at {{ID}} ({{origin}}) får adgang til API'en?"
}
},
"menu": {
"auth-strategy": {
"label": "Godkendelsesstrategi"
},
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
}
},
"name": "API Server [Beta]",
"prompt": {
"hostname": {
"label": "Skriv API serverens hostname (f. eks. 0.0.0.0):",
"title": "Hostname"
},
"port": {
"label": "Skriv API serverens port:",
"title": "Port"
}
}
},
"audio-compressor": {
"name": "Lyd kompressor"
},
"blur-nav-bar": {
"description": "Gør navigationsbaren gennemsigtig og sløret",
"name": "Slør navigationsbar"
},
"captions-selector": {
"menu": {
"disable-captions": "Ingen undertekster som standard"
},
"name": "Vælg undertekster",
"prompt": {
"selector": {
"label": "Nuværende sprog på undertekster: {{language}}",
"none": "Ingen",
"title": "Vælg underteksternes sprog"
}
}
},
"crossfade": {
"description": "Fade imellem sange",
"menu": {
"advanced": "Avanceret"
},
"name": "Fade [Beta]"
}
}
}

View File

@ -279,6 +279,13 @@
}, },
"name": "Ambiente-Modus" "name": "Ambiente-Modus"
}, },
"amuse": {
"description": "Fügt Unterstützung für das Amuse \"Spielt gerade\"-Widget von 6K Labs hinzu",
"name": "Amuse",
"response": {
"query": "Amuse API-Server läuft. /query für Liedinformationen."
}
},
"api-server": { "api-server": {
"description": "Fügt einen API-Server hinzu, um die Wiedergabe zu steuern", "description": "Fügt einen API-Server hinzu, um die Wiedergabe zu steuern",
"dialog": { "dialog": {
@ -484,6 +491,18 @@
"button": "Herunterladen" "button": "Herunterladen"
} }
}, },
"equalizer": {
"description": "Fügt einen Equalizer zum Player hinzu",
"menu": {
"presets": {
"label": "Vorgaben",
"list": {
"bass-booster": "Bass-Verstärker"
}
}
},
"name": "Equalizer"
},
"exponential-volume": { "exponential-volume": {
"description": "Macht den Lautstärkeregler exponentiell, damit es einfacher ist leise Lautstärken zu wählen.", "description": "Macht den Lautstärkeregler exponentiell, damit es einfacher ist leise Lautstärken zu wählen.",
"name": "Exponentielle Lautstärke" "name": "Exponentielle Lautstärke"
@ -664,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "ListenBrainz-Benutzer-Token eintragen" "token": "ListenBrainz-Benutzer-Token eintragen"
}, },
"scrobble-alternative-title": "Nutze alternative Titel",
"scrobble-other-media": "Andere Medien scrobbeln" "scrobble-other-media": "Andere Medien scrobbeln"
}, },
"name": "Scrobbler", "name": "Scrobbler",
@ -714,8 +734,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Bietet synchronisierte Liedtexte zu Songs, verwendet Anbieter wie LRClib.", "description": "Bietet synchronisierte Liedtexte zu Songs, verwendet Anbieter wie LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - Beim Abrufen des Liedtexts ist ein Fehler aufgetreten. Bitte versuchen Sie es später nochmal.", "fetch": "⚠️ - \tBeim Abrufen des Liedtexts ist ein Fehler aufgetreten. \n\tBitte versuchen Sie es später nochmal.",
"not-found": "⚠️ - Kein Text für diesen Song gefunden." "not-found": "⚠️ Kein Text für diesen Song gefunden."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -725,6 +745,10 @@
"line-effect": { "line-effect": {
"label": "Zeileneffekt", "label": "Zeileneffekt",
"submenu": { "submenu": {
"fancy": {
"label": "schick",
"tooltip": "Verwende große, app-ähnliche Effekte in der aktuellen Zeile"
},
"focus": { "focus": {
"label": "Fokussieren", "label": "Fokussieren",
"tooltip": "Nur aktive Zeile weiß darstellen" "tooltip": "Nur aktive Zeile weiß darstellen"

View File

@ -671,7 +671,8 @@
"listenbrainz": { "listenbrainz": {
"token": "Enter ListenBrainz user token" "token": "Enter ListenBrainz user token"
}, },
"scrobble-other-media": "Scrobble other media" "scrobble-other-media": "Scrobble other media",
"scrobble-alternative-title": "Use alternative titles"
}, },
"name": "Scrobbler", "name": "Scrobbler",
"prompt": { "prompt": {
@ -755,6 +756,10 @@
"label": "Make the lyrics perfectly synced", "label": "Make the lyrics perfectly synced",
"tooltip": "Calculate to the milisecond the display of the next line (can have a small impact on performance)" "tooltip": "Calculate to the milisecond the display of the next line (can have a small impact on performance)"
}, },
"romanization": {
"label": "Romanize lyrics",
"tooltip": "If the lyrics are in a different language, try to display a latin version."
},
"show-lyrics-even-if-inexact": { "show-lyrics-even-if-inexact": {
"label": "Show lyrics even if inexact", "label": "Show lyrics even if inexact",
"tooltip": "If the song is not found, the plugin tries again with a different search query.\nThe result from the second attempt may not be exact." "tooltip": "If the song is not found, the plugin tries again with a different search query.\nThe result from the second attempt may not be exact."
@ -787,6 +792,10 @@
"description": "Integration with OBS's plugin Tuna", "description": "Integration with OBS's plugin Tuna",
"name": "Tuna OBS" "name": "Tuna OBS"
}, },
"unobtrusive-player": {
"description": "Prevents the player from popping up when playing a song",
"name": "Unobtrusive Player"
},
"video-toggle": { "video-toggle": {
"description": "Adds a button to switch between Video/Song mode. can also optionally remove the whole video tab", "description": "Adds a button to switch between Video/Song mode. can also optionally remove the whole video tab",
"menu": { "menu": {

View File

@ -4,7 +4,7 @@
"plugins": { "plugins": {
"execute-failed": "Error al ejecutar el plugin {{pluginName}}::{{contextName}}", "execute-failed": "Error al ejecutar el plugin {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}: {{contextName}} ejecutado en {{ms}}ms", "executed-at-ms": "Plugin {{pluginName}}: {{contextName}} ejecutado en {{ms}}ms",
"initialize-failed": "Error al inicializar plugin \"{{pluginName}}\"", "initialize-failed": "Error al inicializar el plugin \"{{pluginName}}\"",
"load-all": "Cargando todos los plugins", "load-all": "Cargando todos los plugins",
"load-failed": "Error al cargar el plugin \"{{pluginName}}\"", "load-failed": "Error al cargar el plugin \"{{pluginName}}\"",
"loaded": "Plugin \"{{pluginName}}\" cargado", "loaded": "Plugin \"{{pluginName}}\" cargado",
@ -21,7 +21,7 @@
"main": { "main": {
"console": { "console": {
"did-finish-load": { "did-finish-load": {
"dev-tools": "Carga finalizada. DevTools abiertos" "dev-tools": "Carga finalizada. DevTools abierto"
}, },
"i18n": { "i18n": {
"loaded": "i18n cargado" "loaded": "i18n cargado"
@ -36,7 +36,7 @@
"details": "¡Error sin repuesta!\n{{error}}" "details": "¡Error sin repuesta!\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "Borrar caché de la aplicación" "clearing-cache-after-20s": "Borrando caché de la aplicación"
}, },
"window": { "window": {
"tried-to-render-offscreen": "La ventana intentó mostrarse fuera de la pantalla, windowSize={{windowSize}}, displaySize={{displaySize}}, posicion={{position}}" "tried-to-render-offscreen": "La ventana intentó mostrarse fuera de la pantalla, windowSize={{windowSize}}, displaySize={{displaySize}}, posicion={{position}}"
@ -45,21 +45,21 @@
"dialog": { "dialog": {
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "El menú está oculto, utiliza \"Alt\" para mostrarlo (o \"Escape\" si utilizas el menú integrado en la aplicación)", "detail": "El menú está oculto, utiliza \"Alt\" para mostrarlo (o \"Escape\" si utilizas el menú integrado en la aplicación)",
"message": "Menu oculto esta deshabilitado", "message": "Menú Oculto está habilitado",
"title": "Menú oculto activado" "title": "Menú oculto habilitado"
}, },
"need-to-restart": { "need-to-restart": {
"buttons": { "buttons": {
"later": "Más tarde", "later": "Más tarde",
"restart-now": "Reiniciar ahora" "restart-now": "Reiniciar ahora"
}, },
"detail": "\"{{pluginName}}\" se requiere reiniciar para que el plugin tome efecto", "detail": "El plugin \"{{pluginName}}\" requiere reiniciar para tomar efecto",
"message": "\"{{pluginName}}\" necesita reiniciar", "message": "\"{{pluginName}}\" necesita reiniciar",
"title": "Se requiere reinicio" "title": "Se requiere reinicio"
}, },
"unresponsive": { "unresponsive": {
"buttons": { "buttons": {
"quit": "Dejar", "quit": "Salir",
"relaunch": "Volver a abrir", "relaunch": "Volver a abrir",
"wait": "Espera" "wait": "Espera"
}, },
@ -74,7 +74,7 @@
"ok": "OK" "ok": "OK"
}, },
"detail": "Una nueva versión está disponible y puede descargarse en {{downloadLink}}", "detail": "Una nueva versión está disponible y puede descargarse en {{downloadLink}}",
"message": "Ya está disponible una nueva versión", "message": "Hay una nueva versión disponible",
"title": "Actualización disponible" "title": "Actualización disponible"
} }
}, },
@ -84,7 +84,7 @@
"label": "Navegación", "label": "Navegación",
"submenu": { "submenu": {
"copy-current-url": "Copiar la URL actual", "copy-current-url": "Copiar la URL actual",
"go-back": "Regresar", "go-back": "Atrás",
"go-forward": "Adelante", "go-forward": "Adelante",
"quit": "Salir", "quit": "Salir",
"restart": "Reiniciar la aplicación" "restart": "Reiniciar la aplicación"
@ -99,10 +99,10 @@
"auto-reset-app-cache": "Restablecer la caché de la aplicación al iniciarla", "auto-reset-app-cache": "Restablecer la caché de la aplicación al iniciarla",
"disable-hardware-acceleration": "Desactivar la aceleración por hardware", "disable-hardware-acceleration": "Desactivar la aceleración por hardware",
"edit-config-json": "Editar config.json", "edit-config-json": "Editar config.json",
"override-user-agent": "sobrescribir User-Agent", "override-user-agent": "Sobrescribir User-Agent",
"restart-on-config-changes": "Reinicie al cambiar la configuración", "restart-on-config-changes": "Reiniciar al modificar la configuración",
"set-proxy": { "set-proxy": {
"label": "Definir proxy", "label": "Establecer proxy",
"prompt": { "prompt": {
"label": "Introduzca la dirección del proxy: (déjela vacía para desactivarla)", "label": "Introduzca la dirección del proxy: (déjela vacía para desactivarla)",
"placeholder": "Ejemplo: SOCKS5://127.0.0.1:9999", "placeholder": "Ejemplo: SOCKS5://127.0.0.1:9999",
@ -112,28 +112,28 @@
"toggle-dev-tools": "Activar DevTools" "toggle-dev-tools": "Activar DevTools"
} }
}, },
"always-on-top": "Siempre arriba", "always-on-top": "Siempre al frente",
"auto-update": "Actualización automática", "auto-update": "Actualización automática",
"hide-menu": { "hide-menu": {
"dialog": { "dialog": {
"message": "El menú se ocultará la próxima vez que lo inicies, usa [Alt] para mostrarlo (o pulsa [`] si usas el menú dentro de la aplicación)", "message": "El menú se ocultará la próxima vez que inicies la aplicación, usa [Alt] para mostrarlo (o pulsa [`] si usas el menú dentro de la aplicación)",
"title": "Ocultar menú habilitado" "title": "Menú oculto habilitado"
}, },
"label": "Ocultar menú" "label": "Ocultar menú"
}, },
"language": { "language": {
"dialog": { "dialog": {
"message": "El idioma se cambiará después de reiniciar", "message": "El idioma se cambiará después de reiniciar",
"title": "Se cambio el idioma" "title": "Se cambió el idioma"
}, },
"label": "Idioma", "label": "Idioma",
"submenu": { "submenu": {
"to-help-translate": "¿Quieres ayudar a traducir? Haz clic aquí" "to-help-translate": "¿Quieres ayudar a traducir? Haz clic aquí"
} }
}, },
"resume-on-start": "Reanudar la última canción al iniciar la aplicación", "resume-on-start": "Reanudar la última canción reproducida al iniciar la aplicación",
"single-instance-lock": "Bloquear en una instancia unica", "single-instance-lock": "Limitar a una única instancia",
"start-at-login": "Comenzar al iniciar sesión", "start-at-login": "Iniciar al iniciar sesión",
"starting-page": { "starting-page": {
"label": "Página de inicio", "label": "Página de inicio",
"unset": "Sin configurar" "unset": "Sin configurar"
@ -142,8 +142,8 @@
"label": "Bandeja", "label": "Bandeja",
"submenu": { "submenu": {
"disabled": "Desactivado", "disabled": "Desactivado",
"enabled-and-hide-app": "Activar y ocultar la aplicación", "enabled-and-hide-app": "Habilitado y ocultar la aplicación",
"enabled-and-show-app": "Activado y mostrar aplicación", "enabled-and-show-app": "Habilitado y mostrar aplicación",
"play-pause-on-click": "Reproducir/Pausar al hacer clic" "play-pause-on-click": "Reproducir/Pausar al hacer clic"
} }
}, },
@ -156,7 +156,7 @@
"hide": "Ocultar", "hide": "Ocultar",
"label": "Botones de \"Me Gusta\"" "label": "Botones de \"Me Gusta\""
}, },
"remove-upgrade-button": "Remover el botón de Actualización", "remove-upgrade-button": "Eliminar el botón de Actualización",
"theme": { "theme": {
"dialog": { "dialog": {
"button": { "button": {
@ -212,14 +212,14 @@
"name": "Aumento de la velocidad de anuncios" "name": "Aumento de la velocidad de anuncios"
}, },
"adblocker": { "adblocker": {
"description": "Bloquear todos los anuncios y el rastreo", "description": "Bloquear todos los anuncios y el rastreo por defecto",
"menu": { "menu": {
"blocker": "Bloqueador" "blocker": "Bloqueador"
}, },
"name": "Bloqueador de anuncios" "name": "Bloqueador de anuncios"
}, },
"album-actions": { "album-actions": {
"description": "Añade los botones \"No me gusta\", \"No me gusta\", \"Me gusta\" y \"No me gusta\" para aplicarlos a todas las canciones de una lista de reproducción o un álbum", "description": "Añade los botones \"Quitar no me gusta\", \"No me gusta\", \"Me gusta\" y \"Quitar me gusta\" para aplicarlos a todas las canciones de una lista de reproducción o un álbum",
"name": "Acciones en el álbum" "name": "Acciones en el álbum"
}, },
"album-color-theme": { "album-color-theme": {
@ -232,15 +232,15 @@
} }
} }
}, },
"name": "Color del álbum" "name": "Tema de color del álbum"
}, },
"ambient-mode": { "ambient-mode": {
"description": "Aplica un efecto de iluminación mediante la proyección de colores suaves del vídeo en el fondo de la pantalla", "description": "Aplica un efecto de iluminación mediante la proyección de colores suaves extraídos del vídeo sobre el fondo de pantalla",
"menu": { "menu": {
"blur-amount": { "blur-amount": {
"label": "Cantidad de desenfoque", "label": "Cantidad de desenfoque",
"submenu": { "submenu": {
"pixels": "{{blurAmount}} pixeles" "pixels": "{{blurAmount}} píxeles"
} }
}, },
"buffer": { "buffer": {
@ -250,7 +250,7 @@
} }
}, },
"opacity": { "opacity": {
"label": "Transparencia", "label": "Opacidad",
"submenu": { "submenu": {
"percent": "{{opacity}}%" "percent": "{{opacity}}%"
} }
@ -279,6 +279,13 @@
}, },
"name": "Modo ambiente" "name": "Modo ambiente"
}, },
"amuse": {
"description": "Agrega soporte a YouTube Music para el widget \"reproduciendo\" de Amuse por 6K Labs",
"name": "Amuse",
"response": {
"query": "El servidor API de Amuse se está ejecutando. Usa GET /query para obtener información de la canción."
}
},
"api-server": { "api-server": {
"description": "Añade un servidor API para controlar el reproductor", "description": "Añade un servidor API para controlar el reproductor",
"dialog": { "dialog": {
@ -287,7 +294,7 @@
"allow": "Permitir", "allow": "Permitir",
"deny": "Denegar" "deny": "Denegar"
}, },
"message": "¿Permitir {{ID}} ({{origin}}) acceder a la API?", "message": "¿Permitir que {{ID}} ({{origin}}) acceda a la API?",
"title": "Petición de autorización API" "title": "Petición de autorización API"
} }
}, },
@ -296,7 +303,7 @@
"label": "Estrategia de autorización", "label": "Estrategia de autorización",
"submenu": { "submenu": {
"auth-at-first": { "auth-at-first": {
"label": "Autorizar la primera solicitud" "label": "Autorizar a la primera solicitud"
}, },
"none": { "none": {
"label": "Sin autorización" "label": "Sin autorización"
@ -327,12 +334,12 @@
"name": "Compresor de audio" "name": "Compresor de audio"
}, },
"blur-nav-bar": { "blur-nav-bar": {
"description": "Hace que la barra de navegación sea transparente y borrosa", "description": "Hace que la barra de navegación se vea transparente y borrosa",
"name": "Desenfocar barra de navegación" "name": "Desenfocar barra de navegación"
}, },
"bypass-age-restrictions": { "bypass-age-restrictions": {
"description": "Saltar la verificación de edad de YouTube", "description": "Saltarse la verificación de edad de YouTube",
"name": "Saltar las restricciones de edad" "name": "Saltarse las restricciones de edad"
}, },
"captions-selector": { "captions-selector": {
"description": "Selector de subtítulos para pistas de audio de YouTube Music", "description": "Selector de subtítulos para pistas de audio de YouTube Music",
@ -343,17 +350,17 @@
"name": "Selector de subtítulos", "name": "Selector de subtítulos",
"prompt": { "prompt": {
"selector": { "selector": {
"label": "Idioma actual: {{language}}", "label": "Idioma actual de los subtítulos: {{language}}",
"none": "Ninguno", "none": "Ninguno",
"title": "Seleccionar idioma de los subtítulos" "title": "Seleccionar idioma de los subtítulos"
} }
}, },
"templates": { "templates": {
"title": "Abra el selector de subtítulos" "title": "Abrir el selector de subtítulos"
} }
}, },
"compact-sidebar": { "compact-sidebar": {
"description": "Poner siempre la barra lateral en modo compacto", "description": "Establecer siempre la barra lateral en modo compacto",
"name": "Barra lateral compacta" "name": "Barra lateral compacta"
}, },
"crossfade": { "crossfade": {
@ -365,16 +372,16 @@
"prompt": { "prompt": {
"options": { "options": {
"multi-input": { "multi-input": {
"fade-in-duration": "Duración del fundido (ms)", "fade-in-duration": "Duración del fundido de entrada (ms)",
"fade-out-duration": "Duración del fundido de salida (ms)", "fade-out-duration": "Duración del fundido de salida (ms)",
"fade-scaling": { "fade-scaling": {
"label": "Escala de fundido", "label": "Escala del fundido",
"linear": "Lineal", "linear": "Lineal",
"logarithmic": "Logarítmico" "logarithmic": "Logarítmico"
}, },
"seconds-before-end": "Crossfade N segundos antes del final" "seconds-before-end": "Activar Crossfade N segundos antes del final"
}, },
"title": "Opciones de crossfade" "title": "Opciones de Crossfade"
} }
} }
}, },
@ -403,7 +410,7 @@
"play-on-youtube-music": "Reproducir en YouTube Music", "play-on-youtube-music": "Reproducir en YouTube Music",
"set-inactivity-timeout": "Establecer tiempo de inactividad" "set-inactivity-timeout": "Establecer tiempo de inactividad"
}, },
"name": "Estado de actividad de Discord", "name": "Discord Rich Presence",
"prompt": { "prompt": {
"set-inactivity-timeout": { "set-inactivity-timeout": {
"label": "Introduzca el tiempo de inactividad en segundos:", "label": "Introduzca el tiempo de inactividad en segundos:",
@ -426,7 +433,7 @@
"ok": "OK" "ok": "OK"
}, },
"detail": "({{playlistSize}} canciones)", "detail": "({{playlistSize}} canciones)",
"message": "Descargar Playlist {{playlistTitle}}", "message": "Descargando Playlist {{playlistTitle}}",
"title": "Descarga iniciada" "title": "Descarga iniciada"
} }
}, },
@ -438,45 +445,45 @@
"download-progress": "Descarga: {{percent}}%", "download-progress": "Descarga: {{percent}}%",
"downloading": "Descargando…", "downloading": "Descargando…",
"downloading-counter": "Descargando {{current}}/{{total}}…", "downloading-counter": "Descargando {{current}}/{{total}}…",
"downloading-playlist": "Descargar lista de reproducción \"{{playlistTitle}}\" - {{playlistSize}} canciones ({{playlistId}})", "downloading-playlist": "Descargando lista de reproducción \"{{playlistTitle}}\" - {{playlistSize}} canciones ({{playlistId}})",
"error-while-downloading": "Error al descargar \"{{author}} - {{title}}\": {{error}}", "error-while-downloading": "Error al descargar \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "La carpeta {{playlistFolder}} ya existe", "folder-already-exists": "La carpeta {{playlistFolder}} ya existe",
"getting-playlist-info": "Obteniendo información de la lista de reproducción…", "getting-playlist-info": "Obteniendo información de la lista de reproducción…",
"loading": "Cargando…", "loading": "Cargando…",
"playlist-has-only-one-song": "La lista de reproducción sólo tiene un elemento, descárgala directamente", "playlist-has-only-one-song": "La lista de reproducción sólo tiene un elemento, descargándolo directamente",
"playlist-id-not-found": "No se ha encontrado el ID de la lista de reproducción", "playlist-id-not-found": "No se ha encontrado la ID de la lista de reproducción",
"playlist-is-empty": "La lista de reproducción está vacía", "playlist-is-empty": "La lista de reproducción está vacía",
"playlist-is-mix-or-private": "Error obteniendo información de la lista de reproducción: asegúrese de que no es una lista privada o \"Mixed for you\"\n\n{{error}}", "playlist-is-mix-or-private": "Error obteniendo la información de la lista de reproducción: asegúrese de que no es una lista privada o \"Mixed for you\"\n\n{{error}}",
"preparing-file": "Preparando archivo…", "preparing-file": "Preparando archivo…",
"saving": "Guardando…", "saving": "Guardando…",
"trying-to-get-playlist-id": "Intentando obtener el ID de la lista de reproducción: {{playlistId}}", "trying-to-get-playlist-id": "Intentando obtener la ID de la lista de reproducción: {{playlistId}}",
"video-id-not-found": "Video no encontrado", "video-id-not-found": "Video no encontrado",
"writing-id3": "Escribiendo las etiquetas ID3…" "writing-id3": "Escribiendo las etiquetas ID3…"
} }
}, },
"description": "Descarga MP3 / audio fuente directamente desde la interfaz", "description": "Descarga audio MP3 / fuente directamente desde la interfaz",
"menu": { "menu": {
"choose-download-folder": "Elija la carpeta de descarga", "choose-download-folder": "Elija la carpeta de descarga",
"download-finish-settings": { "download-finish-settings": {
"label": "Descargar al finalizar", "label": "Descargar al finalizar",
"prompt": { "prompt": {
"last-percent": "Después del x por ciento", "last-percent": "Después de x porcentaje",
"last-seconds": "Últimos x segundos", "last-seconds": "Últimos x segundos",
"title": "Configurar cuándo descargar" "title": "Configurar cuándo descargar"
}, },
"submenu": { "submenu": {
"advanced": "Avanzado", "advanced": "Avanzado",
"enabled": "Activado", "enabled": "Habilitado",
"mode": "Modo de tiempo", "mode": "Modo de tiempo",
"percent": "Porcentaje", "percent": "Porcentaje",
"seconds": "Segundos" "seconds": "Segundos"
} }
}, },
"download-playlist": "Descargar lista de reproducción", "download-playlist": "Descargar lista de reproducción",
"presets": "Preajustes", "presets": "Ajustes preestablecidos",
"skip-existing": "Saltar archivos existentes" "skip-existing": "Saltar archivos existentes"
}, },
"name": "Descargador", "name": "Gestor de descargas",
"renderer": { "renderer": {
"can-not-update-progress": "No se puede actualizar el progreso" "can-not-update-progress": "No se puede actualizar el progreso"
}, },
@ -497,7 +504,7 @@
"name": "Ecualizador" "name": "Ecualizador"
}, },
"exponential-volume": { "exponential-volume": {
"description": "Hace que el control deslizante de volumen sea exponencial para que sea más fácil seleccionar volúmenes más bajos.", "description": "Hace que la barra de volumen sea exponencial para que sea más fácil seleccionar volúmenes más bajos.",
"name": "Volumen exponencial" "name": "Volumen exponencial"
}, },
"in-app-menu": { "in-app-menu": {
@ -512,19 +519,19 @@
"name": "Lumia Stream [Beta]" "name": "Lumia Stream [Beta]"
}, },
"lyrics-genius": { "lyrics-genius": {
"description": "Añade el soporte para las letras para la mayoría de las canciones", "description": "Añade soporte para letras para la mayoría de las canciones",
"menu": { "menu": {
"romanized-lyrics": "Letras Romanizadas" "romanized-lyrics": "Letras Romanizadas"
}, },
"name": "Letras Genius", "name": "Letras Genius",
"renderer": { "renderer": {
"fetched-lyrics": "Letras recuperadas de Genius" "fetched-lyrics": "Letras obtenidas de Genius"
} }
}, },
"music-together": { "music-together": {
"description": "Comparte una lista de reproducción con los demás. Cuando el anfitrión reproduzca una canción, todos los demás escucharán la misma", "description": "Comparte una lista de reproducción con los demás. Cuando el anfitrión reproduzca una canción, todos los demás escucharán la misma",
"dialog": { "dialog": {
"enter-host": "Introduzca el ID del host" "enter-host": "Introduzca la ID del host"
}, },
"internal": { "internal": {
"save": "Guardar", "save": "Guardar",
@ -532,7 +539,7 @@
"unknown-user": "Usuario desconocido" "unknown-user": "Usuario desconocido"
}, },
"menu": { "menu": {
"click-to-copy-id": "Copiar el ID del host", "click-to-copy-id": "Copiar la ID del host",
"close": "Cerrar Music Together", "close": "Cerrar Music Together",
"connected-users": "Usuarios conectados", "connected-users": "Usuarios conectados",
"disconnect": "Desactivar Music Together", "disconnect": "Desactivar Music Together",
@ -542,7 +549,7 @@
"permission": { "permission": {
"all": "Permite a los invitados controlar la lista de reproducción y el reproductor", "all": "Permite a los invitados controlar la lista de reproducción y el reproductor",
"host-only": "Sólo el anfitrión puede controlar la lista de reproducción y el reproductor", "host-only": "Sólo el anfitrión puede controlar la lista de reproducción y el reproductor",
"playlist": "Permita que los invitados controlen la lista de reproducción" "playlist": "Permitir que los invitados controlen la lista de reproducción"
}, },
"set-permission": "Permiso de control de cambios", "set-permission": "Permiso de control de cambios",
"status": { "status": {
@ -555,11 +562,11 @@
"toast": { "toast": {
"add-song-failed": "No se puede añadir la canción", "add-song-failed": "No se puede añadir la canción",
"closed": "Music Together cerrado", "closed": "Music Together cerrado",
"disconnected": "Music Together desconectados", "disconnected": "Music Together desconectado",
"host-failed": "Fallo el host de Music Together", "host-failed": "Fallo al hostear Music Together",
"id-copied": "ID del host copiado en el portapapeles", "id-copied": "ID del host copiada al portapapeles",
"id-copy-failed": "No se ha podido copiar el ID del host en el portapapeles", "id-copy-failed": "No se ha podido copiar la ID del host al portapapeles",
"join-failed": "Fallo en la unión a Music Together", "join-failed": "Fallo al unirse a Music Together",
"joined": "Unido a Music Together", "joined": "Unido a Music Together",
"permission-changed": "Permiso de Music Together cambiado a \"{{permission}}\"", "permission-changed": "Permiso de Music Together cambiado a \"{{permission}}\"",
"remove-song-failed": "Error al eliminar la canción", "remove-song-failed": "Error al eliminar la canción",
@ -594,7 +601,7 @@
"name": "Notificaciones" "name": "Notificaciones"
}, },
"picture-in-picture": { "picture-in-picture": {
"description": "Permite cambiar la aplicación al modo de imagen en imagen", "description": "Permite cambiar la aplicación al modo picture-in-picture",
"menu": { "menu": {
"always-on-top": "Siempre encima", "always-on-top": "Siempre encima",
"hotkey": { "hotkey": {
@ -603,17 +610,17 @@
"keybind-options": { "keybind-options": {
"hotkey": "Tecla de acceso rápido" "hotkey": "Tecla de acceso rápido"
}, },
"label": "Elige una tecla de acceso rápido para activar la función de imagen en imagen", "label": "Elige una tecla de acceso rápido para activar la función picture-in-picture",
"title": "Tecla de acceso directo a imagen en imagen" "title": "Tecla de acceso directo a picture-in-picture"
} }
}, },
"save-window-position": "Guardar la posición de la ventana", "save-window-position": "Guardar la posición de la ventana",
"save-window-size": "Guardar tamaño de la ventana", "save-window-size": "Guardar tamaño de la ventana",
"use-native-pip": "Utilizar \"Dos imágenes a la vez\" PiP nativo del navegador" "use-native-pip": "Utilizar PiP nativo del navegador"
}, },
"name": "Imagen en imagen", "name": "Picture-in-picture",
"templates": { "templates": {
"button": "Imagen en imagen" "button": "Picture-in-picture"
} }
}, },
"playback-speed": { "playback-speed": {
@ -624,7 +631,7 @@
} }
}, },
"precise-volume": { "precise-volume": {
"description": "Controla el volumen de manera precisa utilizando la rueda del ratón/teclas de acceso rápido, con una interfaz personalizada y pasos de volumen personalizables", "description": "Controla el volumen de manera precisa utilizando la rueda del ratón/teclas de acceso rápido, con una interfaz personalizada y niveles de volumen personalizables",
"menu": { "menu": {
"arrows-shortcuts": "Controles de teclas de flechas locales", "arrows-shortcuts": "Controles de teclas de flechas locales",
"custom-volume-steps": "Establecer niveles de volumen personalizados", "custom-volume-steps": "Establecer niveles de volumen personalizados",
@ -641,7 +648,7 @@
"title": "Combinaciones de teclas para el volumen" "title": "Combinaciones de teclas para el volumen"
}, },
"volume-steps": { "volume-steps": {
"label": "Escoge los pasos de aumento o disminución del volumen", "label": "Escoge los niveles de aumento o disminución del volumen",
"title": "Niveles de volumen" "title": "Niveles de volumen"
} }
} }
@ -693,7 +700,7 @@
} }
}, },
"shortcuts": { "shortcuts": {
"description": "Permite configurar teclas de acceso rápido globales para la reproducción (reproducir/pausa/siguiente/anterior) y desactivar la OSD multimedia anulando las teclas multimedia, activar Ctrl/CMD + F para buscar, activar la compatibilidad con MPRIS de Linux para las teclas multimedia y teclas de acceso rápido personalizadas para usuarios avanzados", "description": "Permite configurar teclas de acceso rápido globales para la reproducción (reproducir/pausa/siguiente/anterior) y desactivar el OSD multimedia anulando las teclas multimedia, activar Ctrl/CMD + F para buscar, activar la compatibilidad con MPRIS de Linux para las teclas multimedia y teclas de acceso rápido personalizadas para usuarios avanzados",
"menu": { "menu": {
"override-media-keys": "Anular teclas de medios", "override-media-keys": "Anular teclas de medios",
"set-keybinds": "Configurar controles globales de canciones" "set-keybinds": "Configurar controles globales de canciones"
@ -726,8 +733,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Proporciona letras de canciones sincronizadas, utilizando proveedores como LRClib.", "description": "Proporciona letras de canciones sincronizadas, utilizando proveedores como LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - Se ha producido un error al descargar la letra. Por favor, vuelve a intentarlo más tarde.", "fetch": "⚠️\tHa ocurrido un error al obtener la letra.\n\tPor favor, inténtalo de nuevo más tarde.",
"not-found": "⚠️ - No se ha encontrado ninguna letra para esta canción." "not-found": "⚠️ No se ha encontrado ninguna letra para esta canción."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -737,6 +744,10 @@
"line-effect": { "line-effect": {
"label": "Efecto de la línea", "label": "Efecto de la línea",
"submenu": { "submenu": {
"fancy": {
"label": "Elegante",
"tooltip": "Usar efectos grandes, similares a los de una aplicación, en la línea actual"
},
"focus": { "focus": {
"label": "Enfoque", "label": "Enfoque",
"tooltip": "Mostrar solo la línea actual en blanco" "tooltip": "Mostrar solo la línea actual en blanco"
@ -747,18 +758,18 @@
}, },
"scale": { "scale": {
"label": "Escala", "label": "Escala",
"tooltip": "Escala de la línea actual" "tooltip": "Escalar la línea actual"
} }
}, },
"tooltip": "Elige el efecto que deseas aplicar a la línea actual" "tooltip": "Elige el efecto que deseas aplicar a la línea actual"
}, },
"precise-timing": { "precise-timing": {
"label": "Haz que la letra esté perfectamente sincronizada", "label": "Haz que la letra esté perfectamente sincronizada",
"tooltip": "Calcular al milisegundo la visualización de la línea siguiente (puede tener un pequeño impacto en el rendimiento)" "tooltip": "Calcular al milisegundo la visualización de la siguiente línea (puede tener un pequeño impacto en el rendimiento)"
}, },
"show-lyrics-even-if-inexact": { "show-lyrics-even-if-inexact": {
"label": "Mostrar la letra aunque sea inexacta", "label": "Mostrar la letra aunque sea inexacta",
"tooltip": "Si no se encuentra la canción, el complemento vuelve a intentarlo con una búsqueda diferente.\nEl resultado del segundo intento puede no ser exacto." "tooltip": "Si no se encuentra la canción, el plugin vuelve a intentarlo con una búsqueda diferente.\nEl resultado del segundo intento puede no ser exacto."
}, },
"show-time-codes": { "show-time-codes": {
"label": "Visualización del código de tiempo", "label": "Visualización del código de tiempo",
@ -767,7 +778,7 @@
}, },
"name": "Letras sincronizadas", "name": "Letras sincronizadas",
"refetch-btn": { "refetch-btn": {
"fetching": "Recuperando...", "fetching": "Obteniendo...",
"normal": "Volver a buscar letras" "normal": "Volver a buscar letras"
}, },
"warnings": { "warnings": {
@ -778,24 +789,24 @@
}, },
"taskbar-mediacontrol": { "taskbar-mediacontrol": {
"description": "Controla la reproducción desde la barra de tareas de Windows", "description": "Controla la reproducción desde la barra de tareas de Windows",
"name": "Control de medios de la barra de tareas" "name": "Control de medios desde la barra de tareas"
}, },
"touchbar": { "touchbar": {
"description": "Añade un widget TouchBar para los usuarios de macOS", "description": "Añade un widget TouchBar para los usuarios de macOS",
"name": "TouchBar" "name": "TouchBar"
}, },
"tuna-obs": { "tuna-obs": {
"description": "Integración con el complemento Tuna de OBS", "description": "Integración con el plugin Tuna de OBS",
"name": "Tuna OBS" "name": "Tuna OBS"
}, },
"video-toggle": { "video-toggle": {
"description": "Añade un botón para cambiar entre el modo Vídeo/Canción. también puede eliminar opcionalmente toda la pestaña de vídeo", "description": "Añade un botón para cambiar entre el modo Vídeo/Canción. También puede eliminar opcionalmente toda la pestaña de vídeo",
"menu": { "menu": {
"align": { "align": {
"label": "Alineación", "label": "Alineación",
"submenu": { "submenu": {
"left": "Izquierda", "left": "Izquierda",
"middle": "Medio", "middle": "Centro",
"right": "Derecha" "right": "Derecha"
} }
}, },

View File

@ -81,12 +81,12 @@
"menu": { "menu": {
"about": "درباره", "about": "درباره",
"navigation": { "navigation": {
"label": "ناوبری", "label": "کنترل‌های رابط",
"submenu": { "submenu": {
"copy-current-url": "کپی کردن URL فعلی", "copy-current-url": "کپی کردن لینک صفحه فعلی",
"go-back": "بازگشت", "go-back": "صفحه قبل",
"go-forward": "حرکت به جلو", "go-forward": "صفحه بعدی",
"quit": "خروجی", "quit": "خروج از برنامه",
"restart": "راه‌اندازی مجدد برنامه" "restart": "راه‌اندازی مجدد برنامه"
} }
}, },
@ -98,8 +98,8 @@
"submenu": { "submenu": {
"auto-reset-app-cache": "ریست کردن حافظه کش برنامه هنگام شروع", "auto-reset-app-cache": "ریست کردن حافظه کش برنامه هنگام شروع",
"disable-hardware-acceleration": "غیرفعال کردن شتاب سخت‌افزاری", "disable-hardware-acceleration": "غیرفعال کردن شتاب سخت‌افزاری",
"edit-config-json": "ویرایش config.json", "edit-config-json": "config.json ویرایش",
"override-user-agent": "تغییر User-Agent", "override-user-agent": "User-Agent تغییر",
"restart-on-config-changes": "راه‌اندازی مجدد در صورت تغییرات در پیکربندی", "restart-on-config-changes": "راه‌اندازی مجدد در صورت تغییرات در پیکربندی",
"set-proxy": { "set-proxy": {
"label": "تنظیم پراکسی", "label": "تنظیم پراکسی",
@ -109,7 +109,7 @@
"title": "تنظیم پراکسی" "title": "تنظیم پراکسی"
} }
}, },
"toggle-dev-tools": "باز کردن DevTools" "toggle-dev-tools": "DevTools باز کردن"
} }
}, },
"always-on-top": "همیشه در بالا", "always-on-top": "همیشه در بالا",
@ -168,7 +168,7 @@
}, },
"label": "تم", "label": "تم",
"submenu": { "submenu": {
"import-css-file": "وارد کردن فایل CSS سفارشی", "import-css-file": "سفارشی CSS وارد کردن فایل",
"no-theme": "بدون تم" "no-theme": "بدون تم"
} }
} }
@ -177,7 +177,7 @@
} }
}, },
"plugins": { "plugins": {
"enabled": "فعال", "enabled": "فعال/غیرفعال کردن",
"label": "افزونه‌ها", "label": "افزونه‌ها",
"new": "جدید" "new": "جدید"
}, },
@ -187,7 +187,7 @@
"force-reload": "اجبار به بارگذاری مجدد", "force-reload": "اجبار به بارگذاری مجدد",
"reload": "بارگذاری مجدد", "reload": "بارگذاری مجدد",
"reset-zoom": "اندازه واقعی", "reset-zoom": "اندازه واقعی",
"toggle-fullscreen": "تغییر به تمام‌صفحه", "toggle-fullscreen": "تغییر به تمام‌ صفحه",
"zoom-in": "بزرگنمایی", "zoom-in": "بزرگنمایی",
"zoom-out": "کوچکنمایی" "zoom-out": "کوچکنمایی"
} }
@ -219,7 +219,7 @@
"name": "مسدودکننده تبلیغات" "name": "مسدودکننده تبلیغات"
}, },
"album-actions": { "album-actions": {
"description": "افزودن دکمه‌های \"برگرفتن ناپسند\"، \"ناپسند\"، \"پسند\"، و \"حذف پسند\" برای اعمال آنها روی همه آهنگ‌ها در یک فهرست پخش یا آلبوم", "description": "اضافه کردن دکمه‌های عدم پسندیدن، پسندیدن و لغو پسندیدن برای اعمال این تغییرات به تمامی آهنگ‌های یک فهرست پخش یا آلبوم",
"name": "عملیات آلبوم" "name": "عملیات آلبوم"
}, },
"album-color-theme": { "album-color-theme": {
@ -250,7 +250,10 @@
} }
}, },
"opacity": { "opacity": {
"label": "شفافیت" "label": "شفافیت",
"submenu": {
"percent": "{{opacity}}%"
}
}, },
"quality": { "quality": {
"label": "کیفیت", "label": "کیفیت",
@ -259,7 +262,10 @@
} }
}, },
"size": { "size": {
"label": "اندازه" "label": "اندازه",
"submenu": {
"percent": "{{size}}%"
}
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "انتقال نرمی", "label": "انتقال نرمی",
@ -273,8 +279,15 @@
}, },
"name": "حالت محیطی" "name": "حالت محیطی"
}, },
"amuse": {
"description": "حالا ویجت Amuse از YouTube Music هم پشتیبانی می‌کنه! (توسط 6K Labs)",
"name": "Amuse",
"response": {
"query": "سرور Amuse فعال است. برای دریافت اطلاعات آهنگ، از آدرس /query استفاده کنید."
}
},
"api-server": { "api-server": {
"description": "افزودن یک سرور API برای کنترل پخش‌کننده", "description": "برای کنترل پخش‌کننده API افزودن یک سرور",
"dialog": { "dialog": {
"request": { "request": {
"buttons": { "buttons": {
@ -304,14 +317,14 @@
"label": "پورت" "label": "پورت"
} }
}, },
"name": "سرور API [بتا]", "name": "[بتا]API سرور",
"prompt": { "prompt": {
"hostname": { "hostname": {
"label": "نام میزبان را برای سرور API وارد کنید (مثل 0.0.0.0):", "label": "وارد کنید (مثل 0.0.0.0): API نام میزبان را برای سرور",
"title": "نام میزبان" "title": "نام میزبان"
}, },
"port": { "port": {
"label": "پورت را برای سرور API وارد کنید:", "label": "وارد کنید: API پورت را برای سرور",
"title": "پورت" "title": "پورت"
} }
} }
@ -321,8 +334,8 @@
"name": "فشرده‌ساز صدا" "name": "فشرده‌ساز صدا"
}, },
"blur-nav-bar": { "blur-nav-bar": {
"description": "شفاف و محو کردن نوار ناوبری", "description": "شفاف و محو کردن نوار کنترل",
"name": "محو کردن نوار ناوبری" "name": "محو کردن نوار کنترل"
}, },
"bypass-age-restrictions": { "bypass-age-restrictions": {
"description": "دور زدن تأیید سن یوتیوب", "description": "دور زدن تأیید سن یوتیوب",
@ -381,27 +394,27 @@
}, },
"discord": { "discord": {
"backend": { "backend": {
"already-connected": "تلاش برای اتصال با اتصال فعال", "already-connected": "تلاش برای برقراری ارتباط با اتصال فعال",
"connected": "متصل به Discord", "connected": "متصل به دیسکورد",
"disconnected": "قطع اتصال از Discord" "disconnected": "ارتباط با دیسکورد قطع شد"
}, },
"description": "نمایش آنچه گوش می‌دهید به دوستان با Rich Presence", "description": "Rich Presence نمایش آنچه گوش می‌دهید به دوستان با",
"menu": { "menu": {
"auto-reconnect": "اتصال خودکار مجدد", "auto-reconnect": "اتصال خودکار",
"clear-activity": "پاک کردن فعالیت", "clear-activity": "پاک کردن فعالیت",
"clear-activity-after-timeout": "پاک کردن فعالیت پس از تایم‌اوت", "clear-activity-after-timeout": "حذف فعالیت پس از اتمام زمان تعیین‌شده",
"connected": "متصل", "connected": "اتصال برقرار شد",
"disconnected": "قطع شده", "disconnected": "اتصال قطع شد",
"hide-duration-left": "مخفی کردن مدت زمان باقی‌مانده", "hide-duration-left": "مخفی کردن مدت زمان باقی‌مانده",
"hide-github-button": "مخفی کردن دکمه لینک GitHub", "hide-github-button": "مخفی کردن دکمه لینک گیت هاب",
"play-on-youtube-music": "پخش در یوتیوب موسیقی", "play-on-youtube-music": "پخش در یوتیوب موزیک",
"set-inactivity-timeout": "تنظیم تایم‌اوت عدم فعالیت" "set-inactivity-timeout": "تنظیم زمان عدم فعالیت"
}, },
"name": "Rich Presence در Discord", "name": "Discord Rich Presence",
"prompt": { "prompt": {
"set-inactivity-timeout": { "set-inactivity-timeout": {
"label": "ورود تایم‌اوت عدم فعالیت به ثانیه:", "label": "محدودیت زمان عدم فعالیت را به ثانیه وارد کنید:",
"title": "تنظیم تایم‌اوت عدم فعالیت" "title": "تنظیم زمان عدم فعالیت"
} }
} }
}, },
@ -478,6 +491,18 @@
"button": "دانلود" "button": "دانلود"
} }
}, },
"equalizer": {
"description": "اضافه کردن یک اکولایزر به پخش‌کننده",
"menu": {
"presets": {
"label": "تنظیمات از پیش تعیین شده",
"list": {
"bass-booster": "تقویت‌کننده باس صدا"
}
}
},
"name": "اکولایزر"
},
"exponential-volume": { "exponential-volume": {
"description": "نوار لغزنده حجم را به صورت نمایی می‌سازد تا انتخاب حجم‌های پایین‌تر آسان‌تر شود.", "description": "نوار لغزنده حجم را به صورت نمایی می‌سازد تا انتخاب حجم‌های پایین‌تر آسان‌تر شود.",
"name": "حجم نمایی" "name": "حجم نمایی"
@ -490,17 +515,17 @@
"name": "منوی داخل برنامه" "name": "منوی داخل برنامه"
}, },
"lumiastream": { "lumiastream": {
"description": "افزودن پشتیبانی از Lumia Stream", "description": "Lumia Stream افزودن پشتیبانی از",
"name": "Lumia Stream [بتا]" "name": "Lumia Stream [بتا]"
}, },
"lyrics-genius": { "lyrics-genius": {
"description": "افزودن پشتیبانی از متن آهنگ برای بیشتر آهنگ‌ها", "description": "افزودن متن ترانه پشتیبان برای اکثر ترانه ها",
"menu": { "menu": {
"romanized-lyrics": "متن رومی‌شده" "romanized-lyrics": "الفبای لاتین برای آهنگ‌هایی با الفبای شرقی (فینگلیش)"
}, },
"name": "متن آهنگ Genius", "name": "Genius متن آهنگ",
"renderer": { "renderer": {
"fetched-lyrics": "متن آهنگ از Genius بازیابی شد" "fetched-lyrics": "بازیابی شد Genius متن ترانه توسط"
} }
}, },
"music-together": { "music-together": {
@ -536,13 +561,13 @@
"name": "Music Together [بتا]", "name": "Music Together [بتا]",
"toast": { "toast": {
"add-song-failed": "افزودن آهنگ با شکست مواجه شد", "add-song-failed": "افزودن آهنگ با شکست مواجه شد",
"closed": "Music Together بسته شد", "closed": "بسته شد Music Together",
"disconnected": "قطع اتصال Music Together", "disconnected": "Music Together قطع اتصال",
"host-failed": "میزبانی Music Together با شکست مواجه شد", "host-failed": "با شکست مواجه شد Music Together میزبانی",
"id-copied": "شناسه میزبان به کلیپ‌بورد کپی شد", "id-copied": "شناسه میزبان به کلیپ‌بورد کپی شد",
"id-copy-failed": "کپی شناسه میزبان به کلیپ‌بورد با شکست مواجه شد", "id-copy-failed": "کپی شناسه میزبان به کلیپ‌بورد با شکست مواجه شد",
"join-failed": "پیوستن به Music Together با شکست مواجه شد", "join-failed": "با شکست مواجه شد Music Together پیوستن به",
"joined": "به Music Together پیوست", "joined": "پیوست Music Together به",
"permission-changed": "مجوز Music Together به \"{{permission}}\" تغییر یافت", "permission-changed": "مجوز Music Together به \"{{permission}}\" تغییر یافت",
"remove-song-failed": "حذف آهنگ با شکست مواجه شد", "remove-song-failed": "حذف آهنگ با شکست مواجه شد",
"user-connected": "{{name}} به Music Together پیوست", "user-connected": "{{name}} به Music Together پیوست",
@ -551,11 +576,11 @@
}, },
"navigation": { "navigation": {
"description": "بعدی/قبلی به طور مستقیم در رابط یکپارچه شده‌اند، مانند مرورگر مورد علاقه شما", "description": "بعدی/قبلی به طور مستقیم در رابط یکپارچه شده‌اند، مانند مرورگر مورد علاقه شما",
"name": "ناوبری" "name": "کنترل های رابط"
}, },
"no-google-login": { "no-google-login": {
"description": "حذف دکمه‌های ورود به سیستم Google و لینک‌ها از رابط", "description": "حذف دکمه‌ها و لینک‌های ورود به گوگل از رابط کاربری",
"name": "بدون ورود به Google" "name": "بدون ورود به گوگل"
}, },
"notifications": { "notifications": {
"description": "نمایش اعلان هنگامی که آهنگی شروع به پخش می‌کند (اعلان‌های تعاملی در ویندوز در دسترس هستند)", "description": "نمایش اعلان هنگامی که آهنگی شروع به پخش می‌کند (اعلان‌های تعاملی در ویندوز در دسترس هستند)",
@ -566,11 +591,11 @@
"submenu": { "submenu": {
"hide-button-text": "مخفی کردن متن دکمه", "hide-button-text": "مخفی کردن متن دکمه",
"refresh-on-play-pause": "تازه‌سازی در پخش/توقف", "refresh-on-play-pause": "تازه‌سازی در پخش/توقف",
"tray-controls": "باز/بسته شدن با کلیک روی سینی" "tray-controls": "باز/بسته شدن با کلیک روی آیکون در نوار وظیفه"
} }
}, },
"priority": "اولویت اعلان", "priority": "اولویت اعلان",
"toast-style": "سبک Toast", "toast-style": "Toast سبک",
"unpause-notification": "نمایش اعلان هنگام از سرگیری پخش" "unpause-notification": "نمایش اعلان هنگام از سرگیری پخش"
}, },
"name": "اعلان‌ها" "name": "اعلان‌ها"
@ -578,8 +603,234 @@
"picture-in-picture": { "picture-in-picture": {
"description": "اجازه می‌دهد تا برنامه به حالت تصویر در تصویر تغییر کند", "description": "اجازه می‌دهد تا برنامه به حالت تصویر در تصویر تغییر کند",
"menu": { "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

@ -272,7 +272,32 @@
"use-fullscreen": { "use-fullscreen": {
"label": "Käytetään koko näytön tilaa" "label": "Käytetään koko näytön tilaa"
} }
} },
"name": "Tunnelmallinen Tila"
},
"api-server": {
"description": "Lisää API-palvelimen hallitsemaan soitinta",
"dialog": {
"request": {
"buttons": {
"allow": "Hyväksy",
"deny": "Kiellä"
}
}
},
"menu": {
"auth-strategy": {
"submenu": {
"none": {
"label": "Ei valtuuksia"
}
}
},
"port": {
"label": "Portti"
}
},
"name": "API Serveri [Beta]"
}, },
"audio-compressor": { "audio-compressor": {
"description": "Lisää äänen kompressointia (hiljentää voimakkaimpien äänien voimakkuutta ja tehostaa pehmeämpien äänien voimakkuutta)", "description": "Lisää äänen kompressointia (hiljentää voimakkaimpien äänien voimakkuutta ja tehostaa pehmeämpien äänien voimakkuutta)",

View File

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

View File

@ -33,7 +33,7 @@
"css-file-not-found": "Le fichier de CSS \"{{cssFile}}\" n'existe pas, ignorer" "css-file-not-found": "Le fichier de CSS \"{{cssFile}}\" n'existe pas, ignorer"
}, },
"unresponsive": { "unresponsive": {
"details": "Erreur: ne répond pas!\n{{error}}" "details": "Erreur : Aucune réponse!\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "Effacement du cache de l'application" "clearing-cache-after-20s": "Effacement du cache de l'application"
@ -44,7 +44,7 @@
}, },
"dialog": { "dialog": {
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "Le menu est masqué, utilisez « Alt » pour l'afficher (ou « Échap » si vous utilisez le menu de l'application)", "detail": "Le menu est masqué, utilisez 'Alt' pour l'afficher (ou 'Échap' si vous utilisez le menu de l'application)",
"message": "Le masquage du menu est activé", "message": "Le masquage du menu est activé",
"title": "Masquer le menu activé" "title": "Masquer le menu activé"
}, },
@ -279,6 +279,13 @@
}, },
"name": "Mode ambiant" "name": "Mode ambiant"
}, },
"amuse": {
"description": "Ajoute la prise en charge de YouTube Music pour le widget de lecture en cours Amuse par 6K Labs",
"name": "Amuse",
"response": {
"query": "Le serveur API Amuse est en cours d'exécution. Envoyez une requête GET /query pour obtenir des informations sur la chanson."
}
},
"api-server": { "api-server": {
"description": "Ajouter un serveur API pour contrôler le lecteur", "description": "Ajouter un serveur API pour contrôler le lecteur",
"dialog": { "dialog": {
@ -317,7 +324,7 @@
"title": "Nom d'hôte" "title": "Nom d'hôte"
}, },
"port": { "port": {
"label": "Entrer le port du serveur de l'API :", "label": "Entrez le port du serveur de l'API:",
"title": "Port" "title": "Port"
} }
} }
@ -726,8 +733,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Ajoute des paroles synchronisées aux chansons, grâce à LRClib par exemple.", "description": "Ajoute des paroles synchronisées aux chansons, grâce à LRClib par exemple.",
"errors": { "errors": {
"fetch": "⚠️ - Une erreur s'est produite en allant chercher les paroles. Merci de réessayer plus tard.", "fetch": "⚠️\tUne erreur s'est produite en allant chercher les paroles.\n\tMerci de réessayer plus tard.",
"not-found": "⚠️ - Aucune paroles trouvées pour cette musique." "not-found": "⚠️ Aucune paroles trouvées pour cette musique."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -737,6 +744,10 @@
"line-effect": { "line-effect": {
"label": "Effet de ligne", "label": "Effet de ligne",
"submenu": { "submenu": {
"fancy": {
"label": "Raffiné",
"tooltip": "Utilise de grands effets de type application sur la ligne actuelle"
},
"focus": { "focus": {
"label": "Focus", "label": "Focus",
"tooltip": "Rend seulement la ligne actuelle blanche" "tooltip": "Rend seulement la ligne actuelle blanche"

View File

@ -53,6 +53,8 @@
"later": "אחר כך", "later": "אחר כך",
"restart-now": "מתחיל את התוכנה מחדש עכשיו" "restart-now": "מתחיל את התוכנה מחדש עכשיו"
}, },
"detail": "\"{{pluginName}}\" מצריך אתחול",
"message": "\"{{pluginName}}\" דורש אתחול",
"title": "נדרשת הפעלה מחדש" "title": "נדרשת הפעלה מחדש"
}, },
"unresponsive": { "unresponsive": {
@ -69,9 +71,10 @@
"buttons": { "buttons": {
"disable": "בטל עדכונים", "disable": "בטל עדכונים",
"download": "הורדה", "download": "הורדה",
"ok": "אוקי" "ok": "אוקיי"
}, },
"message": ירסא חדשה זמינה כעת", "detail": "גרסה חדשה זמינה, ניתן להוריד אותה ב-{{downloadLink}}",
"message": "גירסה חדשה זמינה כעת",
"title": "קיים עדכון חדש" "title": "קיים עדכון חדש"
} }
}, },
@ -83,7 +86,106 @@
"copy-current-url": "העתק את כתובת ה-URL", "copy-current-url": "העתק את כתובת ה-URL",
"go-back": "חזור אחורה", "go-back": "חזור אחורה",
"go-forward": "לך קדימה", "go-forward": "לך קדימה",
"quit": "יציאה" "quit": "יציאה",
"restart": "הפעל מחדש את היישום"
}
},
"options": {
"label": "אפשרויות",
"submenu": {
"advanced-options": {
"label": "אפשרויות מתקדמות",
"submenu": {
"auto-reset-app-cache": "אפס את מטמון האפליקציה כאשר האפליקציה מתחילה",
"disable-hardware-acceleration": "השבת האצת החומרה",
"edit-config-json": "ערוך את config.json",
"override-user-agent": "עוקף את סוכן המשתמש",
"restart-on-config-changes": "הפעל מחדש בשינויי תצורה",
"set-proxy": {
"label": "הגדר שרת proxy",
"prompt": {
"label": "הזן כתובת פרוקסי: (להשאיר ריק כדי להשבית)",
"placeholder": "דוגמה: SOCKS5://127.0.0.1:9999",
"title": "הגדר שרת proxy"
}
},
"toggle-dev-tools": "שנה את מצב כלי המפתחים"
}
},
"always-on-top": "תמיד מעל הכל",
"auto-update": "עדכון אוטומטי",
"hide-menu": {
"dialog": {
"message": "התפריט יוסתר בהפעלה הבאה, השתמש ב-[Alt] כדי להציג אותו (או סמן את [`] אם אתה משתמש בתפריט בתוך האפליקציה)",
"title": "הסתר תפריט מופעל"
},
"label": "הסתר את התפריט"
},
"language": {
"dialog": {
"message": "השפה תשתנה לאחר הפעלת היישום מחדש",
"title": "השפה שונתה"
},
"label": "שפה",
"submenu": {
"to-help-translate": "רוצים לעזור לתרגם? לחץ כאן"
}
},
"resume-on-start": "המשך את השיר האחרון עם הפעלת האפליקציה",
"single-instance-lock": "נעילת מופע יחיד",
"start-at-login": "התחל בכניסה",
"starting-page": {
"label": "דף פתיחה",
"unset": "בטל"
},
"tray": {
"label": "מגש",
"submenu": {
"disabled": "מושבת",
"enabled-and-hide-app": "מופעל והסתר אפליקציה",
"enabled-and-show-app": "מופעל והמציג את האפליקציה",
"play-pause-on-click": "הפעל/השהה בלחיצה"
}
},
"visual-tweaks": {
"label": "תיקונים חזותיים",
"submenu": {
"like-buttons": {
"default": "ברירת מחדל",
"force-show": "הפעל בכוח",
"hide": "הסתר",
"label": "כפתורי לייק"
},
"remove-upgrade-button": "הסר לחצן שדרוג",
"theme": {
"dialog": {
"button": {
"cancel": "ביטול",
"remove": "הסר"
},
"remove-theme": "האם אתה בטוח שברצונך להסיר את העיצוב המותאם אישית?",
"remove-theme-message": "פעולה זו תסיר את ערכת הנושא המותאמת אישית"
},
"label": "ערכת נושא",
"submenu": {
"import-css-file": "ייבא קובץ CSS מותאם אישית",
"no-theme": "ללא ערכת נושא"
}
}
}
}
}
},
"plugins": {
"enabled": "מופעל",
"label": "פלאגינים",
"new": "חדש"
},
"view": {
"label": "מראה",
"submenu": {
"force-reload": "התחל מחדש בכוח",
"reload": "טען מחדש"
} }
} }
} }

View File

@ -226,10 +226,63 @@
"description": "एल्बम रंग पैलेट के आधार पर एक गतिशील थीम और दृश्य प्रभाव लागू करता है", "description": "एल्बम रंग पैलेट के आधार पर एक गतिशील थीम और दृश्य प्रभाव लागू करता है",
"menu": { "menu": {
"color-mix-ratio": { "color-mix-ratio": {
"label": "रंग मिश्रण अनुपात",
"submenu": { "submenu": {
"percent": "{{ratio}}%" "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": "चिकनाई संक्रमण"
},
"use-fullscreen": {
"label": "पूर्णस्क्रीन का उपयोग"
}
}
},
"api-server": {
"dialog": {
"request": {
"buttons": {
"allow": "अनुमति दें",
"deny": "मना करना"
}
}
} }
}, },
"video-toggle": { "video-toggle": {

View File

@ -2,12 +2,12 @@
"common": { "common": {
"console": { "console": {
"plugins": { "plugins": {
"execute-failed": "Nem sikerült futtatni a plugint {{pluginName}}::{{contextName}}", "execute-failed": "Nem sikerült futtatni a bővítményt {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} a {{ms}}ms időpontban lefutott", "executed-at-ms": "A {{pluginName}}::{{contextName}} bővítmény végrehajtva {{ms}} ms alatt",
"initialize-failed": "Nem sikerült inicializálni a \"{{pluginName}}\" plugint", "initialize-failed": "Nem sikerült inicializálni a \"{{pluginName}}\" bővítményt",
"load-all": "Összes bővítmény betöltése", "load-all": "Összes bővítmény betöltése",
"load-failed": "Nem sikerült betölteni a \"{{pluginName}}\" plugint", "load-failed": "Nem sikerült betölteni a \"{{pluginName}}\" bővítményt",
"loaded": "\"{{pluginName}}\" plugin betöltve", "loaded": "\"{{pluginName}}\" bővítmény betöltve",
"unload-failed": "Nem sikerült a \"{{pluginName}}\" bővítményt kikapcsolni", "unload-failed": "Nem sikerült a \"{{pluginName}}\" bővítményt kikapcsolni",
"unloaded": "A \"{{pluginName}}\" bővítmény kikapcsolva" "unloaded": "A \"{{pluginName}}\" bővítmény kikapcsolva"
} }
@ -33,13 +33,13 @@
"css-file-not-found": "CSS fájl \"{{cssFile}}\" nem létezik, figyelmen kívül hagyva" "css-file-not-found": "CSS fájl \"{{cssFile}}\" nem létezik, figyelmen kívül hagyva"
}, },
"unresponsive": { "unresponsive": {
"details": "Nem reagál hiba!\n{{error}}" "details": "Nem válaszol!\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "Alkalmazás gyorsítótárának törlése" "clearing-cache-after-20s": "Alkalmazás gyorsítótárának törlése"
}, },
"window": { "window": {
"tried-to-render-offscreen": "Az ablak a képernyőn kívül próbált betölteni, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}" "tried-to-render-offscreen": "Az ablak a képernyőn kívül próbált betölteni, ablakMéret={{windowSize}}, kijelzőMéret={{displaySize}}, pozíció={{position}}"
} }
}, },
"dialog": { "dialog": {
@ -53,8 +53,8 @@
"later": "Később", "later": "Később",
"restart-now": "Újraindítás most" "restart-now": "Újraindítás most"
}, },
"detail": "A \"{{pluginName}}\" plugin újraindítást igényel a bekapcsoláshoz", "detail": "A \"{{pluginName}}\" bővítmény bekapcsolása az alkalmazás újraindítását igényli",
"message": "\"{{pluginName}}\" nevű plugin-t újra kell indítani", "message": "\"{{pluginName}}\" nevű bővítményt újra kell indítani",
"title": "Újraindítás szükséges" "title": "Újraindítás szükséges"
}, },
"unresponsive": { "unresponsive": {
@ -73,7 +73,7 @@
"download": "Letöltés", "download": "Letöltés",
"ok": "OK" "ok": "OK"
}, },
"detail": "Az új verzió elérhető, és letölthető az alábbi linken {{downloadLink}}", "detail": "Új verzió elérhető, amely letölthető az alábbi linken {{downloadLink}}",
"message": "Új verzió áll rendelkezésre", "message": "Új verzió áll rendelkezésre",
"title": "Frissítés elérhető" "title": "Frissítés elérhető"
} }
@ -96,7 +96,7 @@
"advanced-options": { "advanced-options": {
"label": "Speciális beállítások", "label": "Speciális beállítások",
"submenu": { "submenu": {
"auto-reset-app-cache": "Az alkalmazás gyorsítótárának törlése indításkor", "auto-reset-app-cache": "Alkalmazás gyorsítótárának törlése indításkor",
"disable-hardware-acceleration": "Hardveres gyorsítás kikapcsolása", "disable-hardware-acceleration": "Hardveres gyorsítás kikapcsolása",
"edit-config-json": "config.json szerkesztése", "edit-config-json": "config.json szerkesztése",
"override-user-agent": "Kliens felülírása", "override-user-agent": "Kliens felülírása",
@ -123,38 +123,38 @@
}, },
"language": { "language": {
"dialog": { "dialog": {
"message": "Az Újraindítást követően változik meg a nyelv", "message": "A nyelv az allkalmazás újraindítása után megváltozik",
"title": "Megváltozott a nyelv" "title": "Nyelv megváltoztatva"
}, },
"label": "Nyelv", "label": "Nyelv",
"submenu": { "submenu": {
"to-help-translate": "Szeretne a fordításban segíteni? Kattintson ide" "to-help-translate": "Szeretnél segíteni a fordításban? Kattints ide"
} }
}, },
"resume-on-start": "Indításkor az utolsó zene folytatása", "resume-on-start": "Zene folytatása az alkalmazás indításakor",
"single-instance-lock": "Csak egy példány engedélyezése", "single-instance-lock": "Csak egy példány",
"start-at-login": "Futtatás rendszerindításkor", "start-at-login": "Futtatás rendszerindításkor",
"starting-page": { "starting-page": {
"label": "Indítási hely", "label": "Induláskor",
"unset": "Visszaállítás" "unset": "Visszaállítás"
}, },
"tray": { "tray": {
"label": "Tálca", "label": "Tálca ikon",
"submenu": { "submenu": {
"disabled": "Letiltva", "disabled": "Letiltva",
"enabled-and-hide-app": "Aktív és az alkalmazás elrejtve", "enabled-and-hide-app": "Engedélyezve és alkalmazás elrejtése",
"enabled-and-show-app": "Aktív és az alkalmazás megjelenítve", "enabled-and-show-app": "Engedélyezve és alkalmazás megjelenítése",
"play-pause-on-click": "Lejátszás/Szünet az ikonra kattintással" "play-pause-on-click": "Lejátszás/Szünet az ikonra kattintással"
} }
}, },
"visual-tweaks": { "visual-tweaks": {
"label": "Kinézeti beállítások", "label": "Megjelenési beállítások",
"submenu": { "submenu": {
"like-buttons": { "like-buttons": {
"default": "Alapértelmezett", "default": "Alapértelmezett",
"force-show": "Megjelenítés kényszerítése", "force-show": "Megjelenítés kényszerítése",
"hide": "Elrejtése", "hide": "Elrejtése",
"label": "Kedvelés gombok" "label": "Reakció gombok"
}, },
"remove-upgrade-button": "Előfizetés gombjának eltávolítása", "remove-upgrade-button": "Előfizetés gombjának eltávolítása",
"theme": { "theme": {
@ -163,8 +163,8 @@
"cancel": "Mégse", "cancel": "Mégse",
"remove": "Eltávolít" "remove": "Eltávolít"
}, },
"remove-theme": "Biztos, hogy el akarja távolítani az egyéni témát?", "remove-theme": "Biztos, hogy el szeretnéd távolítani az egyéni témát?",
"remove-theme-message": "Ez el fogja távolítani az egyéni témát" "remove-theme-message": "Ez eltávolítja az egyéni témát"
}, },
"label": "Téma", "label": "Téma",
"submenu": { "submenu": {
@ -186,10 +186,10 @@
"submenu": { "submenu": {
"force-reload": "Kényszerített újratöltés", "force-reload": "Kényszerített újratöltés",
"reload": "Újratöltés", "reload": "Újratöltés",
"reset-zoom": "Valós méret", "reset-zoom": "Alapértelmezett méret visszaállítása",
"toggle-fullscreen": "Teljes képernyő be/ki", "toggle-fullscreen": "Teljes képernyő be/ki",
"zoom-in": "Nagyítás", "zoom-in": "Szöveg nagyítása",
"zoom-out": "Kicsinyítés" "zoom-out": "Szöveg kicsinyítése"
} }
} }
}, },
@ -208,25 +208,25 @@
}, },
"plugins": { "plugins": {
"ad-speedup": { "ad-speedup": {
"description": "Ha reklám szól, elnémítja a hangot és a lejátszási sebességet 16x-ra állítja", "description": "Ha egy hirdetés elindul, elnémítja a hangot, és a lejátszási sebességet 16x-ra állítja",
"name": "Gyorsítás hozzáadása" "name": "Hirdetésgyorsítás"
}, },
"adblocker": { "adblocker": {
"description": "Alapértelmezés szerint blokkolja az összes hirdetést és nyomkövetést", "description": "Alapértelmezetten minden hirdetés és nyomkövetés blokkolása",
"menu": { "menu": {
"blocker": "Blokkoló" "blocker": "Blokkolási módszer"
}, },
"name": "Reklámblokkoló" "name": "Reklámblokkoló"
}, },
"album-actions": { "album-actions": {
"description": "Dislike, Undislike, Like, Unlike gombok hozzáadása, amivel ezt a lejátszási listán vagy albumon lévő összes dalra alkalmazza", "description": "Hozzáadja a Tetszik, Nem tetszik és ezek visszavonására szolgáló gombokat, hogy ezeket az összes dalra alkalmazhasd egy lejátszási listán vagy albumban",
"name": "Album műveletek" "name": "Album műveletek"
}, },
"album-color-theme": { "album-color-theme": {
"description": "Dinamikus téma és vizuális effektek alkalmazása az album színpalettája alapján", "description": "Dinamikus témát és vizuális effekteket alkalmaz az album színpalettája alapján",
"menu": { "menu": {
"color-mix-ratio": { "color-mix-ratio": {
"label": "Szín keverés aránya", "label": "Színkeverés mértéke",
"submenu": { "submenu": {
"percent": "{{ratio}}%" "percent": "{{ratio}}%"
} }
@ -235,12 +235,12 @@
"name": "Album színtéma" "name": "Album színtéma"
}, },
"ambient-mode": { "ambient-mode": {
"description": "Fényhatás alkalmazása a videóból származó lágy színek vetítésével a képernyő hátterére", "description": "Fényhatás effektust alkalmaz, amely a videóból származó lágy színeket vetíti a képernyő hátterére",
"menu": { "menu": {
"blur-amount": { "blur-amount": {
"label": "Elmosódás mértéke", "label": "Elmosódás mértéke",
"submenu": { "submenu": {
"pixels": "{{blurAmount}} képpontok" "pixels": "{{blurAmount}} pixel"
} }
}, },
"buffer": { "buffer": {
@ -258,7 +258,7 @@
"quality": { "quality": {
"label": "Minőség", "label": "Minőség",
"submenu": { "submenu": {
"pixels": "{{quality}} képpont" "pixels": "{{quality}} pixel"
} }
}, },
"size": { "size": {
@ -270,14 +270,64 @@
"smoothness-transition": { "smoothness-transition": {
"label": "Sima átmenet", "label": "Sima átmenet",
"submenu": { "submenu": {
"during": "{{interpolationTime}}s alatt" "during": "{{interpolationTime}} másodperc alatt"
} }
}, },
"use-fullscreen": { "use-fullscreen": {
"label": "Teljes képernyő használata" "label": "Teljes képernyő használata"
} }
}, },
"name": "Természetes mód" "name": "Ambient mód"
},
"amuse": {
"description": "Hozzáadja a YouTube Music támogatását az Amuse \"now playing\" widgethez a 6K Labs által",
"name": "Amuse",
"response": {
"query": "Az Amuse API szerver fut. Használja a GET /query kérést a dalinformációk lekéréséhez."
}
},
"api-server": {
"description": "Hozzáad egy API szervert a lejátszó vezérléséhez",
"dialog": {
"request": {
"buttons": {
"allow": "Engedélyez",
"deny": "Megtagad"
},
"message": "Engedélyezi, hogy {{ID}} ({{origin}}) hozzáférjen az API-hoz?",
"title": "API-hozzáférési kérelem"
}
},
"menu": {
"auth-strategy": {
"label": "Engedélyezési módszer",
"submenu": {
"auth-at-first": {
"label": "Engedélyezés az első kérésnél"
},
"none": {
"label": "Nincs engedélyezés"
}
}
},
"hostname": {
"label": "Kiszolgáló név"
},
"port": {
"label": "Port"
}
},
"name": "API szerver [Béta]",
"prompt": {
"hostname": {
"label": "Adja meg az API szerver kiszolgáló nevét (például 0.0.0.0):",
"title": "Kiszolgáló neve"
},
"port": {
"label": "Adja meg az API szerver portját:",
"title": "Port"
}
}
}, },
"audio-compressor": { "audio-compressor": {
"description": "Hang tömörítés alkalmazása (csökkenti a jel legzajosabb részeinek hangerősségét, és emeli a legcsendesebb részek hangerősségét)", "description": "Hang tömörítés alkalmazása (csökkenti a jel legzajosabb részeinek hangerősségét, és emeli a legcsendesebb részek hangerősségét)",
@ -325,7 +375,7 @@
"fade-in-duration": "Áttünés időtartama (ms)", "fade-in-duration": "Áttünés időtartama (ms)",
"fade-out-duration": "Fokozatos halkítás időtartama (ms)", "fade-out-duration": "Fokozatos halkítás időtartama (ms)",
"fade-scaling": { "fade-scaling": {
"label": "Áttünés értéke", "label": "Áttünés mértéke",
"linear": "Lineáris", "linear": "Lineáris",
"logarithmic": "Logaritmikus" "logarithmic": "Logaritmikus"
}, },
@ -336,7 +386,7 @@
} }
}, },
"disable-autoplay": { "disable-autoplay": {
"description": "A Zenék nem fognak maguktól elindulni, a bővítmény használata során kézileg kel indítani a zenéket", "description": "Ez a funkció kikapcsolja az automatikus lejátszást, így a zenék nem indulnak el maguktól. Amikor egy album vagy egy dal lejátszása véget ér, a következő szám nem kezdődik el automatikusan. A bővítmény használata során minden zenét manuálisan kell elindítani",
"menu": { "menu": {
"apply-once": "Csak induláskor alkalmazza" "apply-once": "Csak induláskor alkalmazza"
}, },
@ -356,7 +406,7 @@
"connected": "Kapcsolódva", "connected": "Kapcsolódva",
"disconnected": "Nincs Kapcsolódva", "disconnected": "Nincs Kapcsolódva",
"hide-duration-left": "Hátralévő idő elrejtése", "hide-duration-left": "Hátralévő idő elrejtése",
"hide-github-button": "GitHub link gombjának elrejtése", "hide-github-button": "GitHub url gombjának elrejtése",
"play-on-youtube-music": "Lejátszás a YouTube Music-on", "play-on-youtube-music": "Lejátszás a YouTube Music-on",
"set-inactivity-timeout": "Inaktivitási időkorlát beállítása" "set-inactivity-timeout": "Inaktivitási időkorlát beállítása"
}, },
@ -418,7 +468,8 @@
"label": "Letöltés befejezéskor", "label": "Letöltés befejezéskor",
"prompt": { "prompt": {
"last-percent": "x százalék után", "last-percent": "x százalék után",
"last-seconds": "Utolsó x másodperc" "last-seconds": "Utolsó x másodperc",
"title": "Letöltés idejének beállítása"
}, },
"submenu": { "submenu": {
"advanced": "Speciális", "advanced": "Speciális",
@ -440,6 +491,18 @@
"button": "Letöltés" "button": "Letöltés"
} }
}, },
"equalizer": {
"description": "Hangszínszabályzót ad hozzá a zenelejátszóhoz",
"menu": {
"presets": {
"label": "Hangprofil",
"list": {
"bass-booster": "Basszuskiemelés"
}
}
},
"name": "Hangszínszabályzó"
},
"exponential-volume": { "exponential-volume": {
"description": "Az hangerő csúszka exponenciálissá tételével könnyebbé válik az alacsony hangerő kiválasztása.", "description": "Az hangerő csúszka exponenciálissá tételével könnyebbé válik az alacsony hangerő kiválasztása.",
"name": "Exponenciális hangerő" "name": "Exponenciális hangerő"
@ -488,6 +551,7 @@
"host-only": "Csak a házigazda tudja vezérelni a lejátszási listát és a lejátszót", "host-only": "Csak a házigazda tudja vezérelni a lejátszási listát és a lejátszót",
"playlist": "Engedélyezi a vendégeknek a lejátszási lista vezérlését" "playlist": "Engedélyezi a vendégeknek a lejátszási lista vezérlését"
}, },
"set-permission": "Vezérlési engedély módosítása",
"status": { "status": {
"disconnected": "Kapcsolat bontva", "disconnected": "Kapcsolat bontva",
"guest": "Csatlakozva vendégként", "guest": "Csatlakozva vendégként",
@ -560,7 +624,7 @@
} }
}, },
"playback-speed": { "playback-speed": {
"description": "Hallgass gyorsan, hallgass lassan! Hozzáad egy csúszkát, amely szabályozza a dal sebességét", "description": "Hallgassd gyorsan, hallgassd lassan! Hozzáad egy csúszkát, amely szabályozza a dal sebességét",
"name": "Lejátszás sebessége", "name": "Lejátszás sebessége",
"templates": { "templates": {
"button": "Sebesség" "button": "Sebesség"
@ -618,8 +682,10 @@
}, },
"listenbrainz": { "listenbrainz": {
"token": "Add meg a ListenBrainz felhasználói tokenedet" "token": "Add meg a ListenBrainz felhasználói tokenedet"
} },
"scrobble-other-media": "Más média scrobbelése"
}, },
"name": "Scrobbler",
"prompt": { "prompt": {
"lastfm": { "lastfm": {
"api-key": "Last.fm API kulcs", "api-key": "Last.fm API kulcs",
@ -667,19 +733,47 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Szinkronizált dalszövegeket biztosít dalokhoz, LRClib-hez hasonló szolgáltatókat használva.", "description": "Szinkronizált dalszövegeket biztosít dalokhoz, LRClib-hez hasonló szolgáltatókat használva.",
"errors": { "errors": {
"fetch": "⚠️ - Hiba történt a dalszövegek lekérése közben. Kérlek, próbáld újra később.", "fetch": "⚠️\tHiba történt a dalszöveg lekérése közben.\n\tKérk, próbálja meg később újra.",
"not-found": "⚠️ - Nem található dalszöveg ehhez a zenéhez." "not-found": "⚠️ - Ehhez a dalhoz nem található dalszöveg."
}, },
"menu": { "menu": {
"default-text-string": {
"label": "Alapértelmezett karakter a dalszövegek között",
"tooltip": "Válassza ki az alapértelmezett karaktert, amelyet a dalszövegek közötti szünethez használni szeretne"
},
"line-effect": { "line-effect": {
"label": "Soreffekt",
"submenu": { "submenu": {
"fancy": {
"label": "Díszes",
"tooltip": "Használj nagy, alkalmazásszerű effektusokat az aktuális sorhoz"
},
"focus": {
"label": "Fókuszált",
"tooltip": "Az aktuális sor kijelőlése fehérrel"
},
"offset": {
"label": "Eltolás",
"tooltip": "Az aktuális sort jobbra tolja. (mintha tabulálnád)"
},
"scale": { "scale": {
"label": "Mérték" "label": "Méretezett",
"tooltip": "Az aktuális sort kissé nagyobbra méretezi, kiemelve azt a többi sor közül"
} }
} },
"tooltip": "Válassza ki az aktuális sorra alkalmazandó effektust"
}, },
"precise-timing": { "precise-timing": {
"label": "Dalszöveg tökéletes szinkronizálása" "label": "Dalszöveg tökéletes szinkronizálása",
"tooltip": "Számítsa ki az aktuális sor megjelenítésének idejét ezredmásodperc pontossággal (ez kis mértékben befolyásolhatja a teljesítményt)"
},
"show-lyrics-even-if-inexact": {
"label": "Pontatlan időzítésű dalszövegek megjelenítése",
"tooltip": "Ha a dalt nem találja, a bővítmény újra próbálkozik egy másik keresési lekérdezéssel.\nAz eredmény a második próbálkozás után nem biztos, hogy pontos lesz."
},
"show-time-codes": {
"label": "Időkódok megjelenítése",
"tooltip": "Az időkódok megjelenítése a dalszövegek mellett"
} }
}, },
"name": "Szinkronizált dalszövegek", "name": "Szinkronizált dalszövegek",

View File

@ -2,7 +2,7 @@
"common": { "common": {
"console": { "console": {
"plugins": { "plugins": {
"execute-failed": "Gagal saat mengeksekusi plugin {{pluginName}}::{{contextName}}", "execute-failed": "Plugin {{pluginName}}::{{contextName}} dieksekusi di {{ms}}ms",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} dieksekusi pada {{ms}}ms", "executed-at-ms": "Plugin {{pluginName}}::{{contextName}} dieksekusi pada {{ms}}ms",
"initialize-failed": "Gagal dalam menginisialisasi plugin \"{{pluginName}}\"", "initialize-failed": "Gagal dalam menginisialisasi plugin \"{{pluginName}}\"",
"load-all": "Memuat semua plugin", "load-all": "Memuat semua plugin",
@ -279,6 +279,13 @@
}, },
"name": "Mode ambient" "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": { "api-server": {
"description": "Menambahkan server API untuk mengontrol pemutar", "description": "Menambahkan server API untuk mengontrol pemutar",
"dialog": { "dialog": {
@ -676,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "Masukkan token pengguna ListenBrainz" "token": "Masukkan token pengguna ListenBrainz"
}, },
"scrobble-alternative-title": "Gunakan judul alternatif",
"scrobble-other-media": "Scrobble media lain" "scrobble-other-media": "Scrobble media lain"
}, },
"name": "Scrobbler", "name": "Scrobbler",
@ -726,8 +734,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Menyediakan lirik lagu yang disinkronkan, menggunakan penyedia seperti LRClib.", "description": "Menyediakan lirik lagu yang disinkronkan, menggunakan penyedia seperti LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - Terjadi kesalahan saat mengambil lirik. Coba lagi nanti.", "fetch": "⚠️\tTerjadi kesalahan saat mengambil lirik.\n\tSilakan coba lagi nanti.",
"not-found": "⚠️ - Tidak ada lirik yang ditemukan untuk lagu ini." "not-found": "⚠️ Tidak ada lirik yang ditemukan untuk lagu ini."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -737,6 +745,10 @@
"line-effect": { "line-effect": {
"label": "Efek garis", "label": "Efek garis",
"submenu": { "submenu": {
"fancy": {
"label": "Mewah",
"tooltip": "Gunakan efek besar seperti aplikasi pada baris saat ini"
},
"focus": { "focus": {
"label": "Fokus", "label": "Fokus",
"tooltip": "Jadikan hanya baris saat ini berwarna putih" "tooltip": "Jadikan hanya baris saat ini berwarna putih"

View File

@ -683,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "Inserire il token utente per ListenBrainz" "token": "Inserire il token utente per ListenBrainz"
}, },
"scrobble-alternative-title": "Usa titoli alternativi",
"scrobble-other-media": "Scrobble altri media" "scrobble-other-media": "Scrobble altri media"
}, },
"name": "Scrobbler", "name": "Scrobbler",
@ -744,6 +745,9 @@
"line-effect": { "line-effect": {
"label": "Effetto linea", "label": "Effetto linea",
"submenu": { "submenu": {
"fancy": {
"tooltip": "Usa effetti grandi, simili a quelli di un'app sulla riga attuale"
},
"focus": { "focus": {
"label": "Focus", "label": "Focus",
"tooltip": "Rendi bianca solo la riga corrente" "tooltip": "Rendi bianca solo la riga corrente"

286
src/i18n/resources/ka.json Normal file
View File

@ -0,0 +1,286 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "პლაგინის დაყენების შეცდომა {{pluginName}}::{{contextName}}",
"executed-at-ms": "პლაგინი {{pluginName}}::{{contextName}} გაეშვა {{ms}} მილიწამში",
"initialize-failed": "პლაგინის ინიციალიზაცია ვერ მოხდა\"{{pluginName}}\"",
"load-all": "იტვირთება ყველა პლაგინი",
"load-failed": "პლაგინის ჩატვირთვა ვერ მოხდა \"{{pluginName}}\"",
"loaded": "პლაგინი \"{{pluginName}}\" ჩაიტვირთა"
}
}
},
"language": {
"code": "ka",
"local-name": "ქართული",
"name": "Georgian"
},
"main": {
"dialog": {
"need-to-restart": {
"buttons": {
"later": "მოგვიანებით"
}
},
"unresponsive": {
"buttons": {
"quit": "გასვლა",
"relaunch": "თავიდან გაშვება",
"wait": "მოცდა"
}
},
"update-available": {
"buttons": {
"download": "გადმოწერა",
"ok": "დიახ"
}
}
},
"menu": {
"about": "შესახებ",
"navigation": {
"label": "ნავიგაცია",
"submenu": {
"quit": "გასვლა"
}
},
"options": {
"label": "მორგება",
"submenu": {
"language": {
"label": "ენა"
},
"starting-page": {
"unset": "მოხსნა"
},
"tray": {
"submenu": {
"disabled": "გამორთულია"
}
},
"visual-tweaks": {
"submenu": {
"like-buttons": {
"default": "ნაგულისხმევი",
"hide": "დამალვა"
},
"theme": {
"dialog": {
"button": {
"cancel": "გაუქმება",
"remove": "წაშლა"
}
},
"label": "თემა"
}
}
}
}
},
"plugins": {
"enabled": "ჩართულია",
"label": "დამატებები",
"new": "ახალი"
},
"view": {
"label": "ხედი",
"submenu": {
"reload": "თავიდან ჩატვირთვა"
}
}
},
"tray": {
"next": "შემდეგი",
"play-pause": "დაკვრა/შეჩერება",
"previous": "წინა",
"quit": "გასვლა"
}
},
"plugins": {
"adblocker": {
"menu": {
"blocker": "დამბლოკავი"
}
},
"album-color-theme": {
"menu": {
"color-mix-ratio": {
"submenu": {
"percent": "{{ratio}}%"
}
}
}
},
"ambient-mode": {
"menu": {
"buffer": {
"label": "ბუფერი",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "გაუმჭვირვალობა",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "ხარისხი"
},
"size": {
"label": "ზომა",
"submenu": {
"percent": "{{size}}%"
}
}
}
},
"amuse": {
"name": "Amuse"
},
"api-server": {
"dialog": {
"request": {
"buttons": {
"allow": "დაშვება",
"deny": "აკრძალვა"
}
}
},
"menu": {
"hostname": {
"label": "ჰოსტის სახელი"
},
"port": {
"label": "პორტი"
}
},
"prompt": {
"hostname": {
"title": "ჰოსტის სახელი"
},
"port": {
"title": "პორტი"
}
}
},
"captions-selector": {
"prompt": {
"selector": {
"none": "არცერთი"
}
}
},
"crossfade": {
"menu": {
"advanced": "დამატებით"
},
"prompt": {
"options": {
"multi-input": {
"fade-scaling": {
"linear": "წრფივი",
"logarithmic": "ლოგარითმული"
}
}
}
}
},
"discord": {
"menu": {
"connected": "დაკავშირებული",
"disconnected": "გათიშული"
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "დიახ"
}
},
"start-download-playlist": {
"buttons": {
"ok": "დიახ"
}
}
},
"feedback": {
"converting": "გადაყვანა…",
"downloading": "გადმოწერა…",
"loading": "ჩატვირთვა…",
"saving": "შენახვა…"
}
},
"menu": {
"download-finish-settings": {
"submenu": {
"advanced": "დამატებით",
"enabled": "ჩართულია",
"percent": "პროცენტი",
"seconds": "წამი"
}
},
"presets": "პრესეტი"
},
"name": "გადმომწერი",
"templates": {
"button": "გადმოწერა"
}
},
"music-together": {
"internal": {
"save": "შენახვა"
},
"menu": {
"status": {
"disconnected": "გათიშული"
}
}
},
"navigation": {
"name": "ნავიგაცია"
},
"notifications": {
"name": "გაფრთხილებები"
},
"picture-in-picture": {
"name": "სურათი სურათში",
"templates": {
"button": "სურათი სურათში"
}
},
"playback-speed": {
"templates": {
"button": "სიჩქარე"
}
},
"shortcuts": {
"prompt": {
"keybind": {
"keybind-options": {
"next": "შემდეგი",
"previous": "წინა"
}
}
}
},
"sponsorblock": {
"name": "სარეკლამო ბლოკი"
},
"synced-lyrics": {
"menu": {
"line-effect": {
"submenu": {
"focus": {
"label": "ფოკუსი"
}
}
}
}
}
}
}

View File

@ -683,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "ListenBrainz 유저 토큰 입력" "token": "ListenBrainz 유저 토큰 입력"
}, },
"scrobble-alternative-title": "대체 제목 사용하기",
"scrobble-other-media": "다른 미디어 스크로블하기" "scrobble-other-media": "다른 미디어 스크로블하기"
}, },
"name": "스크로블러", "name": "스크로블러",
@ -767,6 +768,10 @@
"label": "가사를 최대한 정교하게 동기화", "label": "가사를 최대한 정교하게 동기화",
"tooltip": "다음 줄의 표시를 밀리초 단위로 계산합니다 (성능에 약간의 영향을 미칠 수 있음)" "tooltip": "다음 줄의 표시를 밀리초 단위로 계산합니다 (성능에 약간의 영향을 미칠 수 있음)"
}, },
"romanization": {
"label": "가사 로마자 변환",
"tooltip": "가사가 영어가 아닌 언어로 되어있는 경우, 로마자 표기를 표시합니다."
},
"show-lyrics-even-if-inexact": { "show-lyrics-even-if-inexact": {
"label": "가사가 정확하지 않더라도 표시", "label": "가사가 정확하지 않더라도 표시",
"tooltip": "노래를 찾을 수 없는 경우, 플러그인이 다른 검색어로 다시 검색합니다.\n두번째 검색 결과는 정확하지 않을 수 있습니다." "tooltip": "노래를 찾을 수 없는 경우, 플러그인이 다른 검색어로 다시 검색합니다.\n두번째 검색 결과는 정확하지 않을 수 있습니다."
@ -799,6 +804,10 @@
"description": "OBS의 확장인 Tuna와의 통합을 활성화합니다", "description": "OBS의 확장인 Tuna와의 통합을 활성화합니다",
"name": "Tuna OBS" "name": "Tuna OBS"
}, },
"unobtrusive-player": {
"description": "노래 재생 중 플레이어가 팝업되는 것을 방지합니다",
"name": "플레이어 방해 금지"
},
"video-toggle": { "video-toggle": {
"description": "영상/노래 모드를 전환하는 버튼을 추가합니다. 선택적으로 전체 영상 탭을 제거할 수도 있습니다", "description": "영상/노래 모드를 전환하는 버튼을 추가합니다. 선택적으로 전체 영상 탭을 제거할 수도 있습니다",
"menu": { "menu": {

View File

@ -207,6 +207,10 @@
} }
}, },
"plugins": { "plugins": {
"ad-speedup": {
"description": "यदि कुनै विज्ञापन चल्छ भने, यसले अडियो म्यूट गर्छ र प्लेब्याक गतिको गति १६x मा सेट गर्छ",
"name": "विज्ञापन तीव्रगति"
},
"adblocker": { "adblocker": {
"description": "सबै विज्ञापन र ट्र्याकइंगहरू ब्लक गर्नुहोस्", "description": "सबै विज्ञापन र ट्र्याकइंगहरू ब्लक गर्नुहोस्",
"menu": { "menu": {
@ -275,6 +279,56 @@
}, },
"name": "परिवेश मोड" "name": "परिवेश मोड"
}, },
"amuse": {
"description": "६के ल्याब्सद्वारा अम्यूस नाउ प्लेइङ विजेटका लागि युट्युब म्युजिक समर्थन थप्दछ",
"name": "अम्यूस",
"response": {
"query": "Amuse API सर्भर चलिरहेको छ। गीत जानकारी प्राप्त गर्न GET /query प्रयोग गर्नुहोस्।"
}
},
"api-server": {
"description": "प्लेयर नियन्त्रण गर्नका लागि API सर्भर थप्दछ",
"dialog": {
"request": {
"buttons": {
"allow": "अनुमति दिनुहोस्",
"deny": "अस्वीकार गर्नुहोस्"
},
"message": "{{ID}} ({{origin}}) लाई API पहुँच अनुमति दिनुहुन्छ?",
"title": "API अनुमतिको अनुरोध"
}
},
"menu": {
"auth-strategy": {
"label": "अनुमति रणनीति",
"submenu": {
"auth-at-first": {
"label": "पहिलो अनुरोधमै अनुमति दिनुहोस्"
},
"none": {
"label": "कुनै अनुमति आवश्यक छैन"
}
}
},
"hostname": {
"label": "होस्टनेम"
},
"port": {
"label": "पोर्ट"
}
},
"name": "API सर्भर [बिटा]",
"prompt": {
"hostname": {
"label": "API सर्भरका लागि होस्टनेम प्रविष्ट गर्नुहोस् (उदाहरण: 0.0.0.0):",
"title": "होस्टनेम"
},
"port": {
"label": "API सर्भरका लागि पोर्ट प्रविष्ट गर्नुहोस्:",
"title": "पोर्ट"
}
}
},
"audio-compressor": { "audio-compressor": {
"description": "अडियोमा कम्प्रेसन लागू गर्नुहोस् (सङ्केतको सबैभन्दा चर्को भागहरूको भोल्युम कम गर्दछ र नरम भागहरूको भोल्युम बढाउँछ)", "description": "अडियोमा कम्प्रेसन लागू गर्नुहोस् (सङ्केतको सबैभन्दा चर्को भागहरूको भोल्युम कम गर्दछ र नरम भागहरूको भोल्युम बढाउँछ)",
"name": "अडियो कम्प्रेसर" "name": "अडियो कम्प्रेसर"
@ -410,6 +464,21 @@
"description": "इन्टरफेसबाट सिधै MP3/स्रोत अडियो डाउनलोड गर", "description": "इन्टरफेसबाट सिधै MP3/स्रोत अडियो डाउनलोड गर",
"menu": { "menu": {
"choose-download-folder": "डाउनलोड फोल्डर चयन गर्नुहोस्", "choose-download-folder": "डाउनलोड फोल्डर चयन गर्नुहोस्",
"download-finish-settings": {
"label": "समाप्त भएपछि डाउनलोड गर्नुहोस्",
"prompt": {
"last-percent": "x प्रतिशतपछि",
"last-seconds": "अन्तिम x सेकेन्ड",
"title": "कहिले डाउनलोड गर्ने भनेर कन्फिगर गर्नुहोस्"
},
"submenu": {
"advanced": "उन्नत",
"enabled": "सक्रिय गरिएको",
"mode": "समय मोड",
"percent": "प्रतिशत",
"seconds": "सेकेन्डहरू"
}
},
"download-playlist": "डाउनलोड प्लेलिस्ट", "download-playlist": "डाउनलोड प्लेलिस्ट",
"presets": "प्रिसेटहरू", "presets": "प्रिसेटहरू",
"skip-existing": "विद्यमान फाइलहरू स्किप गर्नुहोस्" "skip-existing": "विद्यमान फाइलहरू स्किप गर्नुहोस्"
@ -422,6 +491,18 @@
"button": "डाउनलोड" "button": "डाउनलोड"
} }
}, },
"equalizer": {
"description": "प्लेयरमा इक्वलाइजर थप्दछ",
"menu": {
"presets": {
"label": "पूर्वसेटहरू",
"list": {
"bass-booster": "बास बूस्टर"
}
}
},
"name": "इक्वलाइजर"
},
"exponential-volume": { "exponential-volume": {
"description": "भोल्युम स्लाइडरलाई घातीय बनाउँछ त्यसैले कम भोल्युमहरू चयन गर्न सजिलो हुन्छ।", "description": "भोल्युम स्लाइडरलाई घातीय बनाउँछ त्यसैले कम भोल्युमहरू चयन गर्न सजिलो हुन्छ।",
"name": "एक्सपोनेन्सियल भोल्युम" "name": "एक्सपोनेन्सियल भोल्युम"
@ -649,6 +730,63 @@
"description": "स्वचालित रूपमा गैर-सङ्गीत भागहरू जस्तै इन्ट्रो/आउट्रो वा सङ्गीत भिडियोका भागहरू छोड्नुहोस्", "description": "स्वचालित रूपमा गैर-सङ्गीत भागहरू जस्तै इन्ट्रो/आउट्रो वा सङ्गीत भिडियोका भागहरू छोड्नुहोस्",
"name": "स्पन्सरब्लक" "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": { "taskbar-mediacontrol": {
"description": "तपाईँको विन्डोज टास्कबारबाट प्लेब्याक नियन्त्रण गर्नुहोस्", "description": "तपाईँको विन्डोज टास्कबारबाट प्लेब्याक नियन्त्रण गर्नुहोस्",
"name": "टास्कबार मेडिया कन्ट्रोल" "name": "टास्कबार मेडिया कन्ट्रोल"

View File

@ -33,7 +33,7 @@
"css-file-not-found": "CSS-bestand \"{{cssFile}}\" bestaat niet, wordt genegeerd" "css-file-not-found": "CSS-bestand \"{{cssFile}}\" bestaat niet, wordt genegeerd"
}, },
"unresponsive": { "unresponsive": {
"details": "Onverantwoordelijkheidsfout!\n{{error}}" "details": "Niet-reagerende fout!\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "App-cache wissen" "clearing-cache-after-20s": "App-cache wissen"
@ -46,7 +46,7 @@
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "Menu is verborgen, gebruik 'Alt' om het weer te geven (of 'Escape' als u de In-App Menu gebruikt)", "detail": "Menu is verborgen, gebruik 'Alt' om het weer te geven (of 'Escape' als u de In-App Menu gebruikt)",
"message": "Menu verbergen is ingeschakeld", "message": "Menu verbergen is ingeschakeld",
"title": "Menu Verbergen Ingeschakeld" "title": "Menu verbergen ingeschakeld"
}, },
"need-to-restart": { "need-to-restart": {
"buttons": { "buttons": {
@ -65,7 +65,7 @@
}, },
"detail": "Het programma reageert niet! Kies wat u wilt doen:", "detail": "Het programma reageert niet! Kies wat u wilt doen:",
"message": "De applicatie reageert niet", "message": "De applicatie reageert niet",
"title": "Venster Niet Reagerend" "title": "Venster reageert niet"
}, },
"update-available": { "update-available": {
"buttons": { "buttons": {
@ -250,7 +250,7 @@
} }
}, },
"opacity": { "opacity": {
"label": "Dekking", "label": "Transparantie",
"submenu": { "submenu": {
"percent": "{{opacity}}%" "percent": "{{opacity}}%"
} }
@ -268,7 +268,7 @@
} }
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "Soepelheid overgang", "label": "Vloeiende overgang",
"submenu": { "submenu": {
"during": "Tijdens {{interpolationTime}} s" "during": "Tijdens {{interpolationTime}} s"
} }
@ -279,6 +279,56 @@
}, },
"name": "Omgevingsmodus" "name": "Omgevingsmodus"
}, },
"amuse": {
"description": "Voegt YouTube Music ondersteuning toe voor de Amuse now playing widget van 6K Labs",
"name": "Amuse",
"response": {
"query": "Amuse API server loopt. Gebruik /query voor nummer informatie."
}
},
"api-server": {
"description": "Voegt een API server toe om de speler te besturen",
"dialog": {
"request": {
"buttons": {
"allow": "Toestaan",
"deny": "Weigeren"
},
"message": "Sta {{ID}} {{origin}} toegang toe tot de API?",
"title": "API autorisatieverzoek"
}
},
"menu": {
"auth-strategy": {
"label": "Autorisatie strategie",
"submenu": {
"auth-at-first": {
"label": "Autoriseer bij eerste verzoek"
},
"none": {
"label": "geen autorisatie"
}
}
},
"hostname": {
"label": "Hostnaam"
},
"port": {
"label": "Poort"
}
},
"name": "API Server [Beta]",
"prompt": {
"hostname": {
"label": "Voeg de hostnaam (bv. 0.0.0.0) voor de API server in:",
"title": "Hostnaam"
},
"port": {
"label": "Voeg de poort voor de API server in:",
"title": "Poort"
}
}
},
"audio-compressor": { "audio-compressor": {
"description": "Past compressie toe op audio (verlaagt het volume van de luidste delen van het signaal en verhoogt het volume van de zachtste delen)", "description": "Past compressie toe op audio (verlaagt het volume van de luidste delen van het signaal en verhoogt het volume van de zachtste delen)",
"name": "Audiocompressor" "name": "Audiocompressor"
@ -395,7 +445,7 @@
"download-progress": "Downloaden: {{percent}}%", "download-progress": "Downloaden: {{percent}}%",
"downloading": "Aan het downloaden…", "downloading": "Aan het downloaden…",
"downloading-counter": "{{current}}/{{total}} aan het downloaden…", "downloading-counter": "{{current}}/{{total}} aan het downloaden…",
"downloading-playlist": "Afspeellijst \"{{playlistTitle}}\" {{playlistId}} aan het downloaden ({{playlistSize}} liederen)", "downloading-playlist": "Afspeellijst \"{{playlistTitle}}\" {{playlistId}} aan het downloaden ({{playlistSize}} nummers)",
"error-while-downloading": "Er is een fout opgetreden tijdens het downloaden van \"{{author}} - {{title}}\": {{error}}", "error-while-downloading": "Er is een fout opgetreden tijdens het downloaden van \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "De map \"{{playlistFolder}}\" bestaat al", "folder-already-exists": "De map \"{{playlistFolder}}\" bestaat al",
"getting-playlist-info": "Afspeellijst informatie ophalen…", "getting-playlist-info": "Afspeellijst informatie ophalen…",
@ -441,6 +491,18 @@
"button": "Download" "button": "Download"
} }
}, },
"equalizer": {
"description": "Voegt een equalizer toe aan de speler",
"menu": {
"presets": {
"label": "Voorinstellingen",
"list": {
"bass-booster": "Basversterker"
}
}
},
"name": "Equalizer"
},
"exponential-volume": { "exponential-volume": {
"description": "Maakt de volumeschuif exponentieel zodat het gemakkelijker is om lagere volumes te selecteren.", "description": "Maakt de volumeschuif exponentieel zodat het gemakkelijker is om lagere volumes te selecteren.",
"name": "Exponentieel Volume" "name": "Exponentieel Volume"
@ -450,14 +512,14 @@
"menu": { "menu": {
"hide-dom-window-controls": "Verberg DOM-vensterbedieningselementen" "hide-dom-window-controls": "Verberg DOM-vensterbedieningselementen"
}, },
"name": "In-App menu" "name": "In-App Menu"
}, },
"lumiastream": { "lumiastream": {
"description": "Voegt ondersteuning voor Lumia Stream toe", "description": "Voegt ondersteuning voor Lumia Stream toe",
"name": "Lumia Stream [Beta]" "name": "Lumia Stream [Beta]"
}, },
"lyrics-genius": { "lyrics-genius": {
"description": "Voegt tekstondersteuning toe voor de meeste nummers", "description": "Voegt songtekstondersteuning toe voor de meeste nummers",
"menu": { "menu": {
"romanized-lyrics": "Geromaniseerde Teksten" "romanized-lyrics": "Geromaniseerde Teksten"
}, },
@ -527,15 +589,19 @@
"interactive-settings": { "interactive-settings": {
"label": "Interactieve instellingen", "label": "Interactieve instellingen",
"submenu": { "submenu": {
"hide-button-text": "Verberg tekst op de knop", "hide-button-text": "Knoptekst verbergen",
"refresh-on-play-pause": "Herlaad bij het afspelen/pauzeren" "refresh-on-play-pause": "Herlaad bij het afspelen/pauzeren",
"tray-controls": "Open/Sluit op tray klik"
} }
}, },
"priority": "Meldingprioriteit",
"toast-style": "Toast stijl",
"unpause-notification": "Laat een notificatie zijn bij het depauzeren" "unpause-notification": "Laat een notificatie zijn bij het depauzeren"
}, },
"name": "Meldingen" "name": "Meldingen"
}, },
"picture-in-picture": { "picture-in-picture": {
"description": "Laat de app toe om naar picture-in-picture modus om te schakelen",
"menu": { "menu": {
"always-on-top": "Altijd bovenaan", "always-on-top": "Altijd bovenaan",
"hotkey": { "hotkey": {
@ -543,26 +609,226 @@
"prompt": { "prompt": {
"keybind-options": { "keybind-options": {
"hotkey": "Sneltoets" "hotkey": "Sneltoets"
} },
"label": "Kies een sneltoets om tussen picture-in-picture te schakelen",
"title": "Picture-in-picture sneltoets"
} }
}, },
"save-window-position": "Sla schermpositie op", "save-window-position": "Sla schermpositie op",
"save-window-size": "Sla schermgrootte op" "save-window-size": "Sla schermgrootte op",
"use-native-pip": "Gebruik browser ingebouwde PiP"
},
"name": "Picture-in-picture",
"templates": {
"button": "Picture-in-picture"
} }
}, },
"video-toggle": { "playback-speed": {
"description": "Luister snel, luister langzaam! Voegt een schuifregelaar toe die de muzieksnelheid regelt",
"name": "Afspeelsnelheid",
"templates": {
"button": "Snelheid"
}
},
"precise-volume": {
"description": "Regel het volume nauwkeurig met behulp van het muiswiel/sneltoetsen, met een aangepaste HUD en aanpasbare volumestappen",
"menu": { "menu": {
"mode": { "arrows-shortcuts": "Lokale Pijltjestoetsen bediening",
"submenu": { "custom-volume-steps": "Stel aangepaste volumestappen in",
"disabled": "Uitgeschakeld" "global-shortcuts": "Globale sneltoetsen"
},
"name": "Nauwkeurig volume",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Volume verlagen",
"increase": "Volume verhogen"
},
"label": "Kies Globale Volume toetsen:",
"title": "Globale Volume toetsen"
},
"volume-steps": {
"label": "Kies Stappen voor volumeverhoging/-verlaging",
"title": "Volume Stappen"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Huidige kwaliteit: {{quality}}",
"message": "Kies videokwaliteit:",
"title": "Kies Videokwaliteit"
}
}
},
"description": "Maakt het mogelijk de videokwaliteit te wijzigen met een knop op de video-overlay",
"name": "Videokwaliteitwisselaar"
},
"scrobbler": {
"description": "Ondersteuning voor scrobbling toevoegen (etc. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Kan niet verifiëren bij Last.fm\nVerberg de pop-up tot de volgende herstart.",
"title": "Authenticatie mislukt"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API Instellingen"
},
"listenbrainz": {
"token": "Voer het ListenBrainz-gebruikerstoken in"
},
"scrobble-other-media": "Scrobble andere media"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Last.fm API sleutel",
"api-secret": "Last.fm API geheim"
},
"listenbrainz": {
"token": {
"label": "Voer uw ListenBrainz-gebruikerstoken in:",
"title": "ListenBrainz token"
} }
} }
} }
}, },
"visualizer": { "shortcuts": {
"description": "Voeg een visuele equalizer toe", "description": "Maakt het mogelijk algemene sneltoetsen in te stellen voor afspelen (afspelen/pauzeren/volgende/vorige) en het uitschakelen van media-OSD door mediatoetsen te overschrijven, het inschakelen van Ctrl/CMD + F om te zoeken, het inschakelen van Linux MPRIS-ondersteuning voor mediatoetsen en aangepaste sneltoetsen voor gevorderde gebruikers",
"menu": { "menu": {
"visualizer-type": "Type visualisator" "override-media-keys": "Media toetsen overschrijven",
"set-keybinds": "Stel de algemene songbediening in"
},
"name": "Snelkoppelingen (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Volgende",
"play-pause": "Afspelen / Pauzeren",
"previous": "Vorige"
},
"label": "Kies globale toetsen voor nummer bediening:",
"title": "Globale toetsen"
}
}
},
"skip-disliked-songs": {
"description": "Slaat disliked nummers over",
"name": "Sla disliked nummers over"
},
"skip-silences": {
"description": "Sla automatisch stiltesecties in nummers over",
"name": "Stiltes overslaan"
},
"sponsorblock": {
"description": "Slaat automatisch niet-muziekgedeelten over, zoals intro/outro of gedeelten van muziekvideo's waarin het nummer niet wordt afgespeeld",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Biedt gesynchroniseerde songteksten voor nummers, met behulp van providers zoals LRClib.",
"errors": {
"fetch": "⚠️\tEr is een fout opgetreden bij het ophalen van de songtekst.\n\tProbeer het later opnieuw.",
"not-found": "⚠️ Er is geen songtekst gevonden voor dit nummer."
},
"menu": {
"default-text-string": {
"label": "Standaardteken tussen songteksten",
"tooltip": "Kies het standaardteken dat u wilt gebruiken voor de opening tussen de songteksten"
},
"line-effect": {
"label": "Lijneffect",
"submenu": {
"fancy": {
"label": "Luxe",
"tooltip": "Gebruik grote, app-achtige effecten op de huidige regel"
},
"focus": {
"label": "Focus",
"tooltip": "Maak alleen de huidige regel wit"
},
"offset": {
"label": "Offset",
"tooltip": "Offset aan de rechterkant van de huidige lijn"
},
"scale": {
"label": "Schaal",
"tooltip": "Schaal de huidige regel"
}
},
"tooltip": "Kies het effect dat u op de huidige regel wilt toepassen"
},
"precise-timing": {
"label": "Zorg ervoor dat de songteksten perfect gesynchroniseerd zijn",
"tooltip": "Bereken tot op de milliseconde de weergave van de volgende regel (kan een kleine impact hebben op de prestaties)"
},
"show-lyrics-even-if-inexact": {
"label": "Toon songteksten, zelfs als ze onnauwkeurig zijn",
"tooltip": "Als het nummer niet wordt gevonden, probeert de plug-in het opnieuw met een andere zoekopdracht.\nHet resultaat van de tweede poging is mogelijk niet exact."
},
"show-time-codes": {
"label": "Toon tijdcodes",
"tooltip": "Toon de tijdcodes naast de songtekst"
}
},
"name": "Gesynchroniseerde songteksten",
"refetch-btn": {
"fetching": "Ophalen...",
"normal": "Songteksten opnieuw ophalen"
},
"warnings": {
"duration-mismatch": "⚠️ - De songteksten zijn mogelijk niet synchroon vanwege een niet-overeenkomende duur.",
"inexact": "⚠️ - De songtekst van dit nummer is mogelijk niet exact",
"instrumental": "⚠️ - Dit is een instrumentaal nummer"
}
},
"taskbar-mediacontrol": {
"description": "Bedien het afspelen vanaf uw Windows-taakbalk",
"name": "Taakbalk Mediabediening"
},
"touchbar": {
"description": "Voegt een TouchBar-widget toe voor macOS-gebruikers",
"name": "TouchBar"
},
"tuna-obs": {
"description": "Integratie met OBS's plug-in Tuna",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Voegt een knop toe om te schakelen tussen de video-/nummermodus. kan optioneel ook het hele videotabblad verwijderen",
"menu": {
"align": {
"label": "Uitlijning",
"submenu": {
"left": "Links",
"middle": "Midden",
"right": "Rechts"
}
},
"force-hide": "Forceer het verwijderen van het videotabblad",
"mode": {
"label": "Modus",
"submenu": {
"custom": "Aangepaste schakelaar",
"disabled": "Uitgeschakeld",
"native": "Native schakelaar"
}
}
},
"name": "Videoschakelaar",
"templates": {
"button": "Nummer"
}
},
"visualizer": {
"description": "Voegt een visualisator toe aan de speler",
"menu": {
"visualizer-type": "Visualisatietype"
}, },
"name": "Visualisator" "name": "Visualisator"
} }

View File

@ -280,7 +280,11 @@
"name": "Tryb otoczenia" "name": "Tryb otoczenia"
}, },
"amuse": { "amuse": {
"name": "Amuse" "description": "Wspiera integrację YouTube Music z widgetami Amuse (od 6K Labs)",
"name": "Amuse",
"response": {
"query": "Serwer API Amuse działa. Użyj metody GET do /query, aby zdobyć informację o utworze."
}
}, },
"api-server": { "api-server": {
"description": "Pozwala na kontrolowanie YouTube Music poprzez podłączenie specjalnego serwera API", "description": "Pozwala na kontrolowanie YouTube Music poprzez podłączenie specjalnego serwera API",
@ -497,7 +501,7 @@
} }
} }
}, },
"name": "Equalizer" "name": "Korektor"
}, },
"exponential-volume": { "exponential-volume": {
"description": "Sprawia, że suwak głośności jest proporcjonalna, dzięki czemu łatwiej jest wybrać niższą głośność.", "description": "Sprawia, że suwak głośności jest proporcjonalna, dzięki czemu łatwiej jest wybrać niższą głośność.",
@ -679,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "Podaj token użytkownika ListenBrainz" "token": "Podaj token użytkownika ListenBrainz"
}, },
"scrobble-alternative-title": "Użyj alternatywnych tytułów",
"scrobble-other-media": "Scrobbluj pozostałe multimedia" "scrobble-other-media": "Scrobbluj pozostałe multimedia"
}, },
"name": "Scrobblowanie", "name": "Scrobblowanie",
@ -729,8 +734,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Dodaje zsynchronizowane napisy do utworów używając między innymi LRClib.", "description": "Dodaje zsynchronizowane napisy do utworów używając między innymi LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - Wystąpił błąd podczas pobierania tekstu utworu. Spróbuj ponownie później.", "fetch": "⚠️\tWystąpił błąd podczas pobierania tekstu utworu.\n\tSpróbuj ponownie później.",
"not-found": "⚠️ - Nie znaleziono napisów dla tego utworu." "not-found": "⚠️ Nie znaleziono napisów dla tego utworu."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -741,7 +746,8 @@
"label": "Efekty linijki", "label": "Efekty linijki",
"submenu": { "submenu": {
"fancy": { "fancy": {
"label": "Facy" "label": "Facy",
"tooltip": "Użyj specjalnych efektów w stylu aplikacji na obecną linię"
}, },
"focus": { "focus": {
"label": "Fokus", "label": "Fokus",

View File

@ -2,14 +2,14 @@
"common": { "common": {
"console": { "console": {
"plugins": { "plugins": {
"execute-failed": "Falha ao executar o plugin {{pluginName}}::{{contextName}}", "execute-failed": "Não foi possível executar o plugin {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} executado com {{ms}}ms", "executed-at-ms": "Plugin {{pluginName}}::{{contextName}} executado em {{ms}}ms",
"initialize-failed": "Falha ao inicializar o plugin \"{{pluginName}}\"", "initialize-failed": "Não foi possível iniciar o plugin \"{{pluginName}}\"",
"load-all": "Carregando todos os plugins", "load-all": "A carregar todos os plugins",
"load-failed": "Falha ao carregar o plugin \"{{pluginName}}\"", "load-failed": "Não foi possível ativar o plugin \"{{pluginName}}\"",
"loaded": "Plugin \"{{pluginName}}\" carregado", "loaded": "Plugin \"{{pluginName}}\" ativado",
"unload-failed": "Falha ao descarregar o plugin \"{{pluginName}}\"", "unload-failed": "Não foi possível desativar o plugin \"{{pluginName}}\"",
"unloaded": "Plugin \"{{pluginName}}\" descarregado" "unloaded": "Plugin \"{{pluginName}}\" desativado"
} }
} }
}, },
@ -21,7 +21,7 @@
"main": { "main": {
"console": { "console": {
"did-finish-load": { "did-finish-load": {
"dev-tools": "Carregamento finalizado. DevTools aberto" "dev-tools": "Carregamento concluído. DevTools aberto"
}, },
"i18n": { "i18n": {
"loaded": "i18n carregado" "loaded": "i18n carregado"
@ -30,64 +30,64 @@
"receive-command": "Comando recebido através do protocolo: \"{{command}}\"" "receive-command": "Comando recebido através do protocolo: \"{{command}}\""
}, },
"theme": { "theme": {
"css-file-not-found": "Arquivo CSS \"{{cssFile}}\" não existe, ignorando" "css-file-not-found": "O ficheiro CSS \"{{cssFile}}\" não existe, a ignorar"
}, },
"unresponsive": { "unresponsive": {
"details": "Erro sem resposta!\n{{error}}" "details": "Erro de falta de resposta!\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "Limpando o cache do aplicativo" "clearing-cache-after-20s": "A limpar a cache da aplicação"
}, },
"window": { "window": {
"tried-to-render-offscreen": "Janela tentou desenhar fora do ecrã, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}" "tried-to-render-offscreen": "Tentativa de desenho fora do ecrã na janela, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
} }
}, },
"dialog": { "dialog": {
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "O menu está oculto, use a tecla 'Alt' para mostra-lo (ou 'Esc' se estiver usando o menu do aplicativo)", "detail": "O menu está oculto, utilize \"Alt\" para o mostrar (ou \"Escape\" se estiver a utilizar o menu da aplicação)",
"message": "Ocultar menu está ativado", "message": "Ocultar Menu está ativado",
"title": "Ocultar menu ativado" "title": "Ocultar Menu ativado"
}, },
"need-to-restart": { "need-to-restart": {
"buttons": { "buttons": {
"later": "Depois", "later": "Depois",
"restart-now": "Reiniciar agora" "restart-now": "Reiniciar agora"
}, },
"detail": "O plugin {{pluginName}} precisa ser reiniciado para ter efeito", "detail": "O plugin \"{{pluginName}}\" requer um reinício para ter efeito",
"message": "\"{{pluginName}}\" precisa ser reiniciado", "message": "\"{{pluginName}}\" precisa de ser reiniciado",
"title": "É necessário reiniciar" "title": "É necessário reiniciar"
}, },
"unresponsive": { "unresponsive": {
"buttons": { "buttons": {
"quit": "Sair", "quit": "Sair",
"relaunch": "Reiniciar", "relaunch": "Reiniciar",
"wait": "Espere" "wait": "Esperar"
}, },
"detail": "Lamentamos o inconveniente! Por favor escolha o que fazer:", "detail": "Lamentamos o incómodo! Por favor, escolha o que fazer:",
"message": "A aplicação não está respondendo", "message": "A aplicação não está a responder",
"title": "A janela não está respondendo" "title": "A janela não está a responder"
}, },
"update-available": { "update-available": {
"buttons": { "buttons": {
"disable": "Desabilitar atualizações", "disable": "Desativar atualizações",
"download": "Baixar", "download": "Transferir",
"ok": "Ok" "ok": "Ok"
}, },
"detail": "Uma nova versão está disponível e pode ser baixada em {{downloadLink}}", "detail": "Está disponível uma nova versão que pode ser descarregada em {{downloadLink}}",
"message": "Uma nova versão está disponível", "message": "Está disponível uma nova versão",
"title": "Atualização disponível" "title": "Atualização disponível"
} }
}, },
"menu": { "menu": {
"about": "Sobre", "about": "Acerca de",
"navigation": { "navigation": {
"label": "Navegação", "label": "Navegação",
"submenu": { "submenu": {
"copy-current-url": "Copiar URL atual", "copy-current-url": "Copiar URL atual",
"go-back": "Voltar", "go-back": "Retroceder",
"go-forward": "Avançar", "go-forward": "Avançar",
"quit": "Saída", "quit": "Sair",
"restart": "Reiniciar aplicativo" "restart": "Reiniciar a aplicação"
} }
}, },
"options": { "options": {
@ -96,15 +96,15 @@
"advanced-options": { "advanced-options": {
"label": "Opções avançadas", "label": "Opções avançadas",
"submenu": { "submenu": {
"auto-reset-app-cache": "Reiniciar cache do aplicativo quando o aplicativo abrir", "auto-reset-app-cache": "Repor a cache quando a aplicação é iniciada",
"disable-hardware-acceleration": "Desabilitar aceleração por hardware", "disable-hardware-acceleration": "Desativar a aceleração de hardware",
"edit-config-json": "Editar config.json", "edit-config-json": "Editar config.json",
"override-user-agent": "Substituir User-Agent", "override-user-agent": "Substituir User-Agent",
"restart-on-config-changes": "Reinicie as alterações de configurações feitas", "restart-on-config-changes": "Reiniciar após alterações de configuração",
"set-proxy": { "set-proxy": {
"label": "Definir proxy", "label": "Definir proxy",
"prompt": { "prompt": {
"label": "Inserir Endereço do Proxy: (deixe em branco para desativar)", "label": "Introduza o endereço do proxy: (deixe em branco para desativar)",
"placeholder": "Exemplo: SOCKS5://127.0.0.1:9999", "placeholder": "Exemplo: SOCKS5://127.0.0.1:9999",
"title": "Definir proxy" "title": "Definir proxy"
} }
@ -113,62 +113,62 @@
} }
}, },
"always-on-top": "Sempre no topo", "always-on-top": "Sempre no topo",
"auto-update": "Atualização automática", "auto-update": "Atualizações automáticas",
"hide-menu": { "hide-menu": {
"dialog": { "dialog": {
"message": "O menu será ocultado na próxima inicialização, use [Alt] para mostrá-lo (ou acento grave [`] se estiver usando o menu interno do aplicativo)", "message": "O menu será ocultado da próxima vez que abrir a aplicação, utilize [Alt] para o mostrar (ou [`] se estiver a utilizar o menu interno da aplicação)",
"title": "Ocultar Menu Ativado" "title": "Ocultar Menu ativado"
}, },
"label": "Ocultar Menu" "label": "Ocultar Menu"
}, },
"language": { "language": {
"dialog": { "dialog": {
"message": "Idioma será alterado após reiniciar", "message": "O idioma será alterado após o reinício",
"title": "Idioma Alterado" "title": "Idioma alterado"
}, },
"label": "Idioma", "label": "Idioma",
"submenu": { "submenu": {
"to-help-translate": "Quer ajudar na tradução? Clique aqui" "to-help-translate": "Quer ajudar na tradução? Clique aqui"
} }
}, },
"resume-on-start": "Continuar última música ao iniciar o aplicativo", "resume-on-start": "Retomar a última música quando a app é iniciada",
"single-instance-lock": "Trava de instância única", "single-instance-lock": "Limitar a uma única instância",
"start-at-login": "Iniciar no login", "start-at-login": "Iniciar com o sistema",
"starting-page": { "starting-page": {
"label": "Página inicial", "label": "Página inicial",
"unset": "Indefinido" "unset": "Não definida"
}, },
"tray": { "tray": {
"label": "Bandeja", "label": "Tabuleiro do sistema",
"submenu": { "submenu": {
"disabled": "Desabilitado", "disabled": "Desativado",
"enabled-and-hide-app": "Ativado e esconder aplicativo", "enabled-and-hide-app": "Ativado e ocultar a aplicação",
"enabled-and-show-app": "Ativado e mostrar aplicativo", "enabled-and-show-app": "Ativado e mostrar a aplicação",
"play-pause-on-click": "Play/Pausa ao clicar" "play-pause-on-click": "Reproduzir/Pausar ao clicar"
} }
}, },
"visual-tweaks": { "visual-tweaks": {
"label": "Tweaks Visuais", "label": "Ajustes visuais",
"submenu": { "submenu": {
"like-buttons": { "like-buttons": {
"default": "Padrão", "default": "Padrão",
"force-show": "Forçar mostrar", "force-show": "Mostrar sempre",
"hide": "Esconder", "hide": "Esconder",
"label": "Botões de curtida" "label": "Botões do \"Gosto\""
}, },
"remove-upgrade-button": "Remover botão upgrade", "remove-upgrade-button": "Remover o botão de upgrade",
"theme": { "theme": {
"dialog": { "dialog": {
"button": { "button": {
"cancel": "Cancelar", "cancel": "Cancelar",
"remove": "Remover" "remove": "Remover"
}, },
"remove-theme": "Você tem certeza que quer remover o tema customizado?", "remove-theme": "Tem a certeza de que pretende remover o tema personalizado?",
"remove-theme-message": "Isso removerá o tema customizado" "remove-theme-message": "Isto irá remover o tema personalizado"
}, },
"label": "Tema", "label": "Tema",
"submenu": { "submenu": {
"import-css-file": "Importar arquivo CSS personalizado", "import-css-file": "Importar ficheiro CSS personalizado",
"no-theme": "Sem tema" "no-theme": "Sem tema"
} }
} }
@ -186,19 +186,19 @@
"submenu": { "submenu": {
"force-reload": "Forçar Recarregamento", "force-reload": "Forçar Recarregamento",
"reload": "Recarregar", "reload": "Recarregar",
"reset-zoom": "Tamanho Atual", "reset-zoom": "Tamanho real",
"toggle-fullscreen": "Ativar Tela Cheia", "toggle-fullscreen": "Ativar ecrã inteiro",
"zoom-in": "Zoom Dentro", "zoom-in": "Aumentar o zoom",
"zoom-out": "Zoom Fora" "zoom-out": "Diminuir o zoom"
} }
} }
}, },
"tray": { "tray": {
"next": "Próximo", "next": "Próxima",
"play-pause": "Play/Pausa", "play-pause": "Reproduzir/Pausar",
"previous": "Anterior", "previous": "Anterior",
"quit": "Sair", "quit": "Sair",
"restart": "Reiniciar aplicativo", "restart": "Reiniciar aplicação",
"show": "Mostrar janela", "show": "Mostrar janela",
"tooltip": { "tooltip": {
"default": "YouTube Music", "default": "YouTube Music",
@ -208,11 +208,11 @@
}, },
"plugins": { "plugins": {
"ad-speedup": { "ad-speedup": {
"description": "Se um anúncio for reproduzido, ele será silenciado o áudio e será definido a velocidade de reprodução para 16x", "description": "Se um anúncio for reproduzido, silencia o áudio e define a velocidade de reprodução para 16x",
"name": "Acelerar os anúncios" "name": "Acelerar os anúncios"
}, },
"adblocker": { "adblocker": {
"description": "Bloquear todos os anúncios e rastreamento automaticamente", "description": "Bloqueie todos os anúncios e monitorização automaticamente",
"menu": { "menu": {
"blocker": "Bloqueador" "blocker": "Bloqueador"
}, },
@ -223,10 +223,10 @@
"name": "Ações no álbum" "name": "Ações no álbum"
}, },
"album-color-theme": { "album-color-theme": {
"description": "Aplica um tema dinâmico e efeitos visuais com base na paleta de cores do álbum", "description": "Aplica um tema dinâmico e efeitos visuais baseados na paleta de cores do álbum",
"menu": { "menu": {
"color-mix-ratio": { "color-mix-ratio": {
"label": "Relação de mistura de cores", "label": "Proporção de mistura de cores",
"submenu": { "submenu": {
"percent": "{{ratio}}%" "percent": "{{ratio}}%"
} }
@ -235,7 +235,7 @@
"name": "Tema de cores do álbum" "name": "Tema de cores do álbum"
}, },
"ambient-mode": { "ambient-mode": {
"description": "Aplica um efeito de iluminação lançando cores suaves do vídeo no fundo da tela.", "description": "Aplica um efeito de iluminação, projetando cores suaves do vídeo no fundo do ecrã",
"menu": { "menu": {
"blur-amount": { "blur-amount": {
"label": "Quantidade de desfoque", "label": "Quantidade de desfoque",
@ -274,45 +274,64 @@
} }
}, },
"use-fullscreen": { "use-fullscreen": {
"label": "Tela cheia" "label": "Utilizar o ecrã inteiro"
} }
}, },
"name": "Modo Ambiente" "name": "Modo Ambiente"
}, },
"amuse": {
"description": "Adiciona suporte ao YouTube Music para o widget Amuse now playing da 6K Labs",
"name": "Amuse",
"response": {
"query": "O servidor da API Amuse está a ser executado. GET /query para obter informações sobre uma música."
}
},
"api-server": { "api-server": {
"description": "Adiciona um servidor API para controlar o leitor",
"dialog": { "dialog": {
"request": { "request": {
"buttons": { "buttons": {
"allow": "Permitir", "allow": "Permitir",
"deny": "Negar" "deny": "Negar"
} },
"message": "Permitir que {{ID}} ({{origin}}) aceda à API?",
"title": "Pedido de autorização da API"
} }
}, },
"menu": { "menu": {
"auth-strategy": { "auth-strategy": {
"label": "Estratégia de Autorização", "label": "Estratégia de autorização",
"submenu": { "submenu": {
"auth-at-first": { "auth-at-first": {
"label": "Autorizar ao primeiro pedido" "label": "Autorizar no primeiro pedido"
}, },
"none": { "none": {
"label": "Sem autorização" "label": "Sem autorização"
} }
} }
}, },
"hostname": {
"label": "Nome do anfitrião"
},
"port": { "port": {
"label": "Porta" "label": "Porta"
} }
}, },
"name": "Servidor API [Beta]",
"prompt": { "prompt": {
"hostname": {
"label": "Introduza o nome do anfitrião (como 0.0.0.0) para o servidor API:",
"title": "Nome do anfitrião"
},
"port": { "port": {
"label": "Introduza a porta para o servidor API:",
"title": "Porta" "title": "Porta"
} }
} }
}, },
"audio-compressor": { "audio-compressor": {
"description": "Aplicar compressão ao áudio (diminui o volume das partes mais altas do sinal e aumenta o volume das partes mais suaves)", "description": "Aplicar compressão ao áudio (diminui o volume das partes mais altas do sinal e aumenta o volume das partes mais suaves)",
"name": "Compressor de áudio" "name": "Compressor de Áudio"
}, },
"blur-nav-bar": { "blur-nav-bar": {
"description": "Torna a barra de navegação transparente e desfocada", "description": "Torna a barra de navegação transparente e desfocada",
@ -323,21 +342,21 @@
"name": "Ignorar restrições de idade" "name": "Ignorar restrições de idade"
}, },
"captions-selector": { "captions-selector": {
"description": "Seletor de legenda para faixas de áudio do YouTube Music", "description": "Seletor de legendas para as faixas de áudio do YouTube Music",
"menu": { "menu": {
"autoload": "Selecionar automaticamente a última legenda usada", "autoload": "Selecionar automaticamente a última legenda utilizada",
"disable-captions": "Sem legendas por padrão" "disable-captions": "Sem legendas por defeito"
}, },
"name": "Seletor de legendas", "name": "Seletor de legendas",
"prompt": { "prompt": {
"selector": { "selector": {
"label": "Idioma da legenda atual: {{language}}", "label": "Idioma atual das legendas: {{language}}",
"none": "Nenhuma", "none": "Nenhuma",
"title": "Selecione o idioma da legenda" "title": "Selecione o idioma das legendas"
} }
}, },
"templates": { "templates": {
"title": "Seletor de legendas aberto" "title": "Abrir o seletor de legendas"
} }
}, },
"compact-sidebar": { "compact-sidebar": {
@ -353,41 +372,41 @@
"prompt": { "prompt": {
"options": { "options": {
"multi-input": { "multi-input": {
"fade-in-duration": "Duração da transição no início (ms)", "fade-in-duration": "Duração da transição (fade-in) no início (ms)",
"fade-out-duration": "Duração da transição no final (ms)", "fade-out-duration": "Duração da transição (fade-out) no final (ms)",
"fade-scaling": { "fade-scaling": {
"label": "Escala da transição", "label": "Escala da transição",
"linear": "Linear", "linear": "Linear",
"logarithmic": "Logarítmica" "logarithmic": "Logarítmica"
}, },
"seconds-before-end": "Realizar transição N segundos antes do final" "seconds-before-end": "Realizar transição N segundos antes do fim"
}, },
"title": "Opções de transição" "title": "Opções da transição"
} }
} }
}, },
"disable-autoplay": { "disable-autoplay": {
"description": "Faz a música começar no modo \"pausado\"", "description": "Faz com que a música comece no modo \"pausado\"",
"menu": { "menu": {
"apply-once": "Aplicar apenas na inicialização" "apply-once": "Aplicar apenas no arranque"
}, },
"name": "Desativar reprodução automática" "name": "Desativar reprodução automática"
}, },
"discord": { "discord": {
"backend": { "backend": {
"already-connected": "Tentativa de conexão com conexão já ativa", "already-connected": "Tentativa de conexão com ligação já ativa",
"connected": "Conectado ao Discord", "connected": "Conectado ao Discord",
"disconnected": "Desconectado do Discord" "disconnected": "Desconectado do Discord"
}, },
"description": "Mostre aos seus amigos o que você ouve com Rich Presence", "description": "Mostre aos seus amigos o que está a ouvir com a Rich Presence",
"menu": { "menu": {
"auto-reconnect": "Reconexão automática", "auto-reconnect": "Reconectar automaticamente",
"clear-activity": "Limpar atividade", "clear-activity": "Limpar atividade",
"clear-activity-after-timeout": "Limpar atividade após o tempo limite", "clear-activity-after-timeout": "Limpar atividade após o tempo limite",
"connected": "Conectado", "connected": "Conectado",
"disconnected": "Desconectado", "disconnected": "Desconectado",
"hide-duration-left": "Ocultar duração restante", "hide-duration-left": "Ocultar duração restante",
"hide-github-button": "Ocultar botão de link do GitHub", "hide-github-button": "Ocultar botão do GitHub",
"play-on-youtube-music": "Reproduzir no YouTube Music", "play-on-youtube-music": "Reproduzir no YouTube Music",
"set-inactivity-timeout": "Definir tempo limite de inatividade" "set-inactivity-timeout": "Definir tempo limite de inatividade"
}, },
@ -406,85 +425,97 @@
"buttons": { "buttons": {
"ok": "OK" "ok": "OK"
}, },
"message": "Poxa! Desculpe, o download falhou…", "message": "Ah! Desculpas, o download falhou…",
"title": "Erro no download!" "title": "Erro ao transferir!"
}, },
"start-download-playlist": { "start-download-playlist": {
"buttons": { "buttons": {
"ok": "OK" "ok": "OK"
}, },
"detail": "({{playlistSize}} músicas)", "detail": "({{playlistSize}} músicas)",
"message": "Baixando lista de reprodução {{playlistTitle}}", "message": "A descarregar a lista de reprodução {{playlistTitle}}",
"title": "Download iniciado" "title": "Download iniciado"
} }
}, },
"feedback": { "feedback": {
"conversion-progress": "Conversão: {{percent}}%", "conversion-progress": "Conversão: {{percent}}%",
"converting": "Convertendo…", "converting": "A converter…",
"done": "Finalizado: {{filePath}}", "done": "Concluído: {{filePath}}",
"download-info": "Baixando {{artist}} - {{title}} {{videoId}}", "download-info": "A descarregar {{artist}} - {{title}} {{videoId}}",
"download-progress": "Baixando: {{percent}}%", "download-progress": "A transferir: {{percent}}%",
"downloading": "Baixando…", "downloading": "A transferir…",
"downloading-counter": "Baixando {{current}}/{{total}}…", "downloading-counter": "A transferir {{current}}/{{total}}…",
"downloading-playlist": "Baixando lista de reprodução \"{{playlistTitle}}\" - {{playlistSize}} músicas ({{playlistId}})", "downloading-playlist": "A descarregar a lista de reprodução \"{{playlistTitle}}\" - {{playlistSize}} músicas ({{playlistId}})",
"error-while-downloading": "Erro ao baixar \"{{author}} - {{title}}\": {{error}}", "error-while-downloading": "Erro ao descarregar \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "A pasta {{playlistFolder}} já existe", "folder-already-exists": "A pasta {{playlistFolder}} já existe",
"getting-playlist-info": "Obtendo informações da lista de reprodução…", "getting-playlist-info": "A obter informações da playlist…",
"loading": "Carregando…", "loading": "A carregar…",
"playlist-has-only-one-song": "A lista de reprodução possui apenas um item, baixando-o diretamente", "playlist-has-only-one-song": "A lista de reprodução tem apenas um item, descarregando-o diretamente",
"playlist-id-not-found": "ID da lista de reprodução não encontrado", "playlist-id-not-found": "Não foi encontrado nenhum ID da lista de reprodução",
"playlist-is-empty": "Lista de reprodução vazia", "playlist-is-empty": "Lista de reprodução vazia",
"playlist-is-mix-or-private": "Erro ao obter informações da lista de reprodução: tenha certeza que ela não está privada ou não seja \"Mixtapes criadas para você\"\n\n{{error}}", "playlist-is-mix-or-private": "Erro ao obter informações da playlist: certifique-se de que ela não seja privada ou uma mix personalizada\n\n{{error}}",
"preparing-file": "Preparando arquivos…", "preparing-file": "A preparar o ficheiro…",
"saving": "Salvando…", "saving": "A guardar…",
"trying-to-get-playlist-id": "Tentando pegar ID da lista de reprodução: {{playlistId}}", "trying-to-get-playlist-id": "A tentar obter o ID da playlist: {{playlistId}}",
"video-id-not-found": "Vídeo não encontrado", "video-id-not-found": "Vídeo não encontrado",
"writing-id3": "Escrevendo tags ID3…" "writing-id3": "A guardar etiquetas ID3…"
} }
}, },
"description": "Baixa MP3 / fonte de áudio diretamente da interface", "description": "Descarregue MP3 / fonte de áudio diretamente da interface",
"menu": { "menu": {
"choose-download-folder": "Escolha a pasta de download", "choose-download-folder": "Escolha a pasta de download",
"download-finish-settings": { "download-finish-settings": {
"label": "Baixar ao terminar", "label": "Transferir ao terminar",
"prompt": { "prompt": {
"last-percent": "Depois de x por cento", "last-percent": "Depois de x por cento",
"last-seconds": "Últimos x segundos", "last-seconds": "Últimos x segundos",
"title": "Configurar quando baixar" "title": "Configurar quando descarregar"
}, },
"submenu": { "submenu": {
"advanced": "Avançado", "advanced": "Avançado",
"enabled": "Ativado", "enabled": "Ativado",
"mode": "Modo de tempo", "mode": "Modo de tempo",
"percent": "Porcentagem", "percent": "Percentagem",
"seconds": "Segundos" "seconds": "Segundos"
} }
}, },
"download-playlist": "Baixar lista de reprodução", "download-playlist": "Descarregar playlist",
"presets": "Predefinições", "presets": "Pré-configurações",
"skip-existing": "Ignorar arquivos existentes" "skip-existing": "Ignorar ficheiros existentes"
}, },
"name": "Downloader", "name": "Downloader",
"renderer": { "renderer": {
"can-not-update-progress": "Não é possível atualizar o progresso" "can-not-update-progress": "Não é possível atualizar o progresso"
}, },
"templates": { "templates": {
"button": "Baixar" "button": "Descarregar"
} }
}, },
"equalizer": {
"description": "Adiciona um equalizador ao leitor",
"menu": {
"presets": {
"label": "Pré-configurações",
"list": {
"bass-booster": "Amplificador de graves"
}
}
},
"name": "Equalizador"
},
"exponential-volume": { "exponential-volume": {
"description": "Torna o controle deslizante de volume exponencial, facilitando a seleção de volumes mais baixos.", "description": "Torna o controlo do volume exponencial para que seja mais fácil selecionar volumes mais baixos.",
"name": "Volume Exponencial" "name": "Volume Exponencial"
}, },
"in-app-menu": { "in-app-menu": {
"description": "Dá às barras de menu uma aparência sofisticada, escura ou com a cor do álbum", "description": "Dá às barras de menu uma aparência sofisticada, escura ou com a cor do álbum",
"menu": { "menu": {
"hide-dom-window-controls": "Ocultar controles da janela DOM" "hide-dom-window-controls": "Ocultar os controlos da janela DOM"
}, },
"name": "Menu no aplicativo" "name": "Menu da aplicação"
}, },
"lumiastream": { "lumiastream": {
"description": "Adiciona suporte Lumia Stream", "description": "Adiciona suporte a Lumia Stream",
"name": "Lumia Stream [Beta]" "name": "Lumia Stream [Beta]"
}, },
"lyrics-genius": { "lyrics-genius": {
@ -494,61 +525,61 @@
}, },
"name": "Letras Genius", "name": "Letras Genius",
"renderer": { "renderer": {
"fetched-lyrics": "Buscar letras no Genius" "fetched-lyrics": "Letras encontradas no Genius"
} }
}, },
"music-together": { "music-together": {
"description": "Compartilha a playlist com outros. Quando o host tocar uma música, todos poderão ouvir a mesma canção", "description": "Partilhe uma playlist com outros. Quando o anfitrião tocar uma música, todos os outros ouvirão a mesma música",
"dialog": { "dialog": {
"enter-host": "Digite o ID do Host" "enter-host": "Introduza o ID do anfitrião"
}, },
"internal": { "internal": {
"save": "Salvar", "save": "Guardar",
"track-source": "Fonte da faixa", "track-source": "Origem da faixa",
"unknown-user": "Usuário Desconhecido" "unknown-user": "Utilizador desconhecido"
}, },
"menu": { "menu": {
"click-to-copy-id": "Copiar ID do Host", "click-to-copy-id": "Copiar o ID do anfitrião",
"close": "Fechar o Música Juntos", "close": "Fechar o Music Together",
"connected-users": "Usuários Conectados", "connected-users": "Utilizadores conectados",
"disconnect": "Desconectar do Música Juntos", "disconnect": "Desconectar Music Together",
"empty-user": "Sem usuários conectados", "empty-user": "Sem utilizadores conectados",
"host": "Host do Música Juntos", "host": "Anfitrião do Music Together",
"join": "Juntar ao Música Juntos", "join": "Juntar-se ao Music Together",
"permission": { "permission": {
"all": "Permita que outros controlem a playlist e ao player", "all": "Permitir que os convidados controlem a playlist e o leitor",
"host-only": "Apenas o host pode controlar a playlist e ao player", "host-only": "Apenas o anfitrião pode controlar a playlist e o leitor",
"playlist": "Permitir que outros controlem a playlist" "playlist": "Permitir que os convidados controlem a playlist"
}, },
"set-permission": "Alterar permissões de controle", "set-permission": "Alterar permissões de controlo",
"status": { "status": {
"disconnected": "Desconectado", "disconnected": "Desconectado",
"guest": "Conectado como Convidado", "guest": "Conectado como convidado",
"host": "Conectado como Host" "host": "Conectado como anfitrião"
} }
}, },
"name": "Música Juntos [Beta]", "name": "Music Together [Beta]",
"toast": { "toast": {
"add-song-failed": "Falha ao adicionar canção", "add-song-failed": "Falha ao adicionar música",
"closed": "Música Juntos encerrado", "closed": "Music Together fechado",
"disconnected": "Música Juntos foi desconectado", "disconnected": "Music Together desconectado",
"host-failed": "Falha ao hospedar o Music Together", "host-failed": "Falha ao hospedar o Music Together",
"id-copied": "ID de anfitrião copiado para a área de transferência", "id-copied": "ID do anfitrião copiado para a Área de Transferência",
"id-copy-failed": "Falha ao copiar o ID de anfitrião para a área de transferência", "id-copy-failed": "Falha ao copiar o ID do anfitrião para a Área de Transferência",
"join-failed": "Falha ao entrar em Music Together", "join-failed": "Falha ao entrar no Music Together",
"joined": "Entrou em Music Together", "joined": "Entrou no Music Together",
"permission-changed": "A permissão do Music Together foi alterada para \"{{permission}}\"", "permission-changed": "A permissão do Music Together foi alterada para \"{{permission}}\"",
"remove-song-failed": "Falha ao remover música", "remove-song-failed": "Falha ao remover música",
"user-connected": "{{name}} entrou em Music Together", "user-connected": "{{name}} entrou no Music Together",
"user-disconnected": "{{name}} saiu do Music Together" "user-disconnected": "{{name}} saiu do Music Together"
} }
}, },
"navigation": { "navigation": {
"description": "Setas de navegação Próximo/Voltar integradas diretamente na interface, como no seu navegador favorito", "description": "Setas de navegação Avançar/Retroceder integradas diretamente na interface, como no seu navegador favorito",
"name": "Navegação" "name": "Navegação"
}, },
"no-google-login": { "no-google-login": {
"description": "Remove os botões e links de login do Google da interface", "description": "Remove os botões de login do Google e links da interface",
"name": "Sem login do Google" "name": "Sem login do Google"
}, },
"notifications": { "notifications": {
@ -556,36 +587,36 @@
"menu": { "menu": {
"interactive": "Notificações interativas", "interactive": "Notificações interativas",
"interactive-settings": { "interactive-settings": {
"label": "Configurações interativas", "label": "Definições interativas",
"submenu": { "submenu": {
"hide-button-text": "Ocultar texto do botão", "hide-button-text": "Ocultar o texto do botão",
"refresh-on-play-pause": "Atualizar ao reproduzir/pausar", "refresh-on-play-pause": "Atualizar ao reproduzir/pausar",
"tray-controls": "Abrir/Fechar no clique da bandeja" "tray-controls": "Abrir/Fechar com um clique no tabuleiro do sistema"
} }
}, },
"priority": "Prioridade de notificação", "priority": "Prioridade da notificação",
"toast-style": "Estilo de alerta", "toast-style": "Estilo da notificação",
"unpause-notification": "Mostrar notificação ao despausar" "unpause-notification": "Mostrar notificação ao desativar a pausa"
}, },
"name": "Notificações" "name": "Notificações"
}, },
"picture-in-picture": { "picture-in-picture": {
"description": "Permite mudar o aplicativo para o modo picture-in-picture", "description": "Permite mudar a aplicação para o modo picture-in-picture",
"menu": { "menu": {
"always-on-top": "Sempre no topo", "always-on-top": "Sempre em cima",
"hotkey": { "hotkey": {
"label": "Tecla de atalho", "label": "Tecla de atalho",
"prompt": { "prompt": {
"keybind-options": { "keybind-options": {
"hotkey": "Tecla de atalho" "hotkey": "Tecla de atalho"
}, },
"label": "Escolha uma tecla de atalho para alternar o picture-in-picture", "label": "Escolha uma tecla de atalho para ativar o picture-in-picture",
"title": "Tecla de atalho picture-in-picture" "title": "Tecla de atalho picture-in-picture"
} }
}, },
"save-window-position": "Salvar posição da janela", "save-window-position": "Guardar posição da janela",
"save-window-size": "Salvar tamanho da janela", "save-window-size": "Guardar tamanho da janela",
"use-native-pip": "Use PiP nativo do navegador" "use-native-pip": "Utilizar PiP nativo do navegador"
}, },
"name": "Picture-in-picture", "name": "Picture-in-picture",
"templates": { "templates": {
@ -593,17 +624,17 @@
} }
}, },
"playback-speed": { "playback-speed": {
"description": "Ouça rápido, ouça devagar! Adiciona um controle deslizante que controla a velocidade da música", "description": "Ouça rápido, ouça devagar! Adiciona um controlo deslizante que controla a velocidade da música",
"name": "Velocidade de reprodução", "name": "Velocidade de reprodução",
"templates": { "templates": {
"button": "Velocidade" "button": "Velocidade"
} }
}, },
"precise-volume": { "precise-volume": {
"description": "Controle o volume com precisão usando a roda do mouse/teclas de atalho, com um HUD personalizado e etapas de volume personalizáveis", "description": "Controle o volume com precisão utilizando a roda do rato/teclas de atalho, com um HUD personalizado e incrementos de volume personalizáveis",
"menu": { "menu": {
"arrows-shortcuts": "Controles locais das teclas de seta", "arrows-shortcuts": "Controlo preciso com as teclas de seta esq./dir.",
"custom-volume-steps": "Definir etapas de volume personalizadas", "custom-volume-steps": "Definir incrementos de volume personalizados",
"global-shortcuts": "Teclas de atalho globais" "global-shortcuts": "Teclas de atalho globais"
}, },
"name": "Volume preciso", "name": "Volume preciso",
@ -613,12 +644,12 @@
"decrease": "Diminuir o volume", "decrease": "Diminuir o volume",
"increase": "Aumentar o volume" "increase": "Aumentar o volume"
}, },
"label": "Escolha atalhos de teclado de volume global:", "label": "Escolha atalhos de teclado para o volume global:",
"title": "Atalhos de teclado de volume global" "title": "Atalhos de teclado para o volume global"
}, },
"volume-steps": { "volume-steps": {
"label": "Escolha as etapas de aumento/diminuição de volume", "label": "Escolha o tamanho dos incrementos/decrementos de volume",
"title": "Etapas de volume" "title": "Incrementos de volume"
} }
} }
}, },
@ -632,90 +663,94 @@
} }
} }
}, },
"description": "Permite alterar a qualidade do vídeo com um botão na sobreposição de vídeo", "description": "Permite alterar a qualidade do vídeo com um botão sobreposto ao vídeo",
"name": "Trocador de qualidade do vídeo" "name": "Alterador de qualidade de vídeo"
}, },
"scrobbler": { "scrobbler": {
"description": "Adicionar suporte para scrobbling (Last.fm, ListenBrainz)", "description": "Adicionar suporte para scrobbling (last.fm, Listenbrainz, etc.)",
"dialog": { "dialog": {
"lastfm": { "lastfm": {
"auth-failed": { "auth-failed": {
"message": "Falha ao autenticar com a Last.fm\nOculte o pop-up até a próxima reinicialização.", "message": "Falha ao autenticar com a Last.fm\nO pop-up será ocultado até reiniciar a aplicação.",
"title": "Falha na autenticação" "title": "Falha na autenticação"
} }
} }
}, },
"menu": { "menu": {
"lastfm": { "lastfm": {
"api-settings": "Configurações de API Last.fm" "api-settings": "Definições da API da Last.fm"
}, },
"listenbrainz": { "listenbrainz": {
"token": "Insira o token de utilizador ListenBrainz" "token": "Introduza o token de utilizador do ListenBrainz"
}, },
"scrobble-other-media": "Scrobble outros mídia" "scrobble-other-media": "Scrobble de outros conteúdos"
}, },
"name": "Scrobbler", "name": "Scrobbler",
"prompt": { "prompt": {
"lastfm": { "lastfm": {
"api-key": "Chave de API Last.fm", "api-key": "Chave da API da Last.fm",
"api-secret": "Segredo da API Last.fm" "api-secret": "Segredo da API da Last.fm"
}, },
"listenbrainz": { "listenbrainz": {
"token": { "token": {
"label": "Insira seu token de usuário do ListenBrainz:", "label": "Introduza o seu token de utilizador ListenBrainz:",
"title": "Token ListenBrainz" "title": "Token ListenBrainz"
} }
} }
} }
}, },
"shortcuts": { "shortcuts": {
"description": "Permite definir teclas de atalho globais para reprodução (reproduzir/pausar/próximo/anterior) e desligar o OSD de mídia substituindo as teclas de mídia, ativando Ctrl/CMD + F para pesquisar, ativando o suporte Linux MPRIS para teclas de mídia e teclas de atalho personalizadas para usuários avançados", "description": "Permite definir teclas de atalho globais para a reprodução (reproduzir/pausar/próximo/anterior) e desativar o OSD multimédia substituindo as teclas multimédia, ativar Ctrl/CMD + F para pesquisar, ativar o suporte Linux MPRIS para teclas multimédia e teclas de atalho personalizadas para utilizadores avançados",
"menu": { "menu": {
"override-media-keys": "Substituir teclas de mídia", "override-media-keys": "Substituir as teclas de multimédia",
"set-keybinds": "Definir controles globais de música" "set-keybinds": "Definir controlos globais para a música"
}, },
"name": "Atalhos (& MPRIS)", "name": "Atalhos (& MPRIS)",
"prompt": { "prompt": {
"keybind": { "keybind": {
"keybind-options": { "keybind-options": {
"next": "Próximo", "next": "Próximo",
"play-pause": "Reproduzir/Pausar", "play-pause": "Reproduzir / Pausar",
"previous": "Anterior" "previous": "Anterior"
}, },
"label": "Escolha atalhos de teclado globais para controle de músicas:", "label": "Escolha teclas globais para o controlo da música:",
"title": "Atalhos globais do teclado" "title": "Atalhos globais do teclado"
} }
} }
}, },
"skip-disliked-songs": { "skip-disliked-songs": {
"description": "Pula músicas com 'não gostei'", "description": "Salta as canções de que não gosta",
"name": "Pular músicas com 'não gostei'" "name": "Saltar músicas que não gostei"
}, },
"skip-silences": { "skip-silences": {
"description": "Pular automaticamente seções de silêncio nas músicas", "description": "Saltar automaticamente as partes silenciosas das canções",
"name": "Pular silêncios" "name": "Saltar silêncios"
}, },
"sponsorblock": { "sponsorblock": {
"description": "Ignora automaticamente partes não musicais, como introdução/final ou partes de videoclipes onde a música não está tocando", "description": "Salta automaticamente partes que não são música, como a intro/outro ou partes de vídeos de música em que a música não está a ser reproduzida",
"name": "SponsorBlock (bloqueador de patrocínios)" "name": "SponsorBlock"
}, },
"synced-lyrics": { "synced-lyrics": {
"description": "Fornece letras sincronizadas de músicas, utilizando fornecedores como o LRClib.", "description": "Fornece letras de músicas sincronizadas, utilizando fornecedores como o LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - Ocorreu um erro ao obter as letras da música. Por favor, tenta novamente mais tarde.", "fetch": "⚠️ Ocorreu um erro ao obter a letra da música.\n\tPor favor, tente novamente mais tarde.",
"not-found": "⚠️ - Não foram encontradas letras para esta música." "not-found": "⚠️ Não foram encontradas letras para esta canção."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
"label": "Caractere padrão entre as letras", "label": "Carácter predefinido entre letras",
"tooltip": "Escolha o caractere padrão para usar no espaço entre as letras" "tooltip": "Escolha o carácter predefinido a utilizar para o intervalo entre letras"
}, },
"line-effect": { "line-effect": {
"label": "Efeito de linha", "label": "Efeito da linha",
"submenu": { "submenu": {
"fancy": {
"label": "Elegante",
"tooltip": "Utilizar grandes efeitos semelhantes aos da aplicação na linha atual"
},
"focus": { "focus": {
"label": "Foco", "label": "Foco",
"tooltip": "Deixe apenas a linha atual branca" "tooltip": "Tornar branca apenas a linha atual"
}, },
"offset": { "offset": {
"label": "Deslocamento", "label": "Deslocamento",
@ -729,11 +764,11 @@
"tooltip": "Escolha o efeito a ser aplicado à linha atual" "tooltip": "Escolha o efeito a ser aplicado à linha atual"
}, },
"precise-timing": { "precise-timing": {
"label": "Sincronize perfeitamente as letras", "label": "Fazer com que as letras estejam perfeitamente sincronizadas",
"tooltip": "Calcule até o milissegundo a exibição da próxima linha (pode ter um pequeno impacto no desempenho)" "tooltip": "Calcular ao milissegundo a visualização da linha seguinte (pode ter um pequeno impacto no desempenho)"
}, },
"show-lyrics-even-if-inexact": { "show-lyrics-even-if-inexact": {
"label": "Mostrar letras mesmo que imprecisas", "label": "Mostrar as letras, mesmo que sejam imprecisas",
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato." "tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
}, },
"show-time-codes": { "show-time-codes": {
@ -743,29 +778,29 @@
}, },
"name": "Letras Sincronizadas", "name": "Letras Sincronizadas",
"refetch-btn": { "refetch-btn": {
"fetching": "Buscando...", "fetching": "A obter...",
"normal": "Buscar as letras novamente" "normal": "Buscar as letras novamente"
}, },
"warnings": { "warnings": {
"duration-mismatch": "⚠️ - As letras da música pode estar dessincronizada devido a um erro de duração.", "duration-mismatch": "⚠️ - A letra da música pode estar dessincronizada devido a um erro de duração.",
"inexact": "⚠️ - As letras desta música podem não ser exactas.", "inexact": "⚠️ - A letra desta canção pode não ser exata",
"instrumental": "⚠️ - Esta é uma música instrumental." "instrumental": "⚠️ - Esta é uma música instrumental"
} }
}, },
"taskbar-mediacontrol": { "taskbar-mediacontrol": {
"description": "Controle a reprodução na barra de tarefas do Windows", "description": "Controle a reprodução a partir da barra de tarefas do Windows",
"name": "Controle de mídia da barra de tarefas" "name": "Controlo multimédia da barra de tarefas"
}, },
"touchbar": { "touchbar": {
"description": "Adiciona um widget TouchBar para usuários do macOS", "description": "Adiciona um widget TouchBar para utilizadores do macOS",
"name": "Barra de toque" "name": "TouchBar"
}, },
"tuna-obs": { "tuna-obs": {
"description": "Integração com o plugin Tuna do OBS", "description": "Integração com o plugin Tuna do OBS",
"name": "Tuna OBS" "name": "Tuna OBS"
}, },
"video-toggle": { "video-toggle": {
"description": "Adiciona um botão para alternar entre o modo Vídeo/Música. Também pode, opcionalmente, remover toda a guia de vídeo", "description": "Adiciona um botão para alternar entre o modo Vídeo/ Música. Opcionalmente, também pode remover completamente o separador do vídeo",
"menu": { "menu": {
"align": { "align": {
"label": "Alinhamento", "label": "Alinhamento",
@ -775,12 +810,12 @@
"right": "Direita" "right": "Direita"
} }
}, },
"force-hide": "Forçar remoção da guia de vídeo", "force-hide": "Forçar a remoção do separador de vídeo",
"mode": { "mode": {
"label": "Modo", "label": "Modo",
"submenu": { "submenu": {
"custom": "Alternar personalizado", "custom": "Alternar personalizado",
"disabled": "Desabilitado", "disabled": "Desativado",
"native": "Alternar nativo" "native": "Alternar nativo"
} }
} }
@ -791,11 +826,11 @@
} }
}, },
"visualizer": { "visualizer": {
"description": "Adiciona um visualizador ao player", "description": "Adiciona um visualizador ao leitor",
"menu": { "menu": {
"visualizer-type": "Tipo de visualizador" "visualizer-type": "Tipo de visualizador"
}, },
"name": "Visualizer" "name": "Visualizador"
} }
} }
} }

View File

@ -268,38 +268,45 @@
} }
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "Fluenta tranzitiei", "label": "Fluiditatea tranzitiei",
"submenu": { "submenu": {
"during": "In timpul {{interpolationTime}} s" "during": "In timpul {{interpolationTime}} s"
} }
}, },
"use-fullscreen": { "use-fullscreen": {
"label": "Foloseste fullscreen" "label": "Ecran Plin în utilizare"
} }
}, },
"name": "Mod ambiental" "name": "Mod ambiental"
}, },
"amuse": {
"description": "Adauga suport Youtube Music pentru Amuse se redă acum widget de 6K Labs",
"name": "Amuse",
"response": {
"query": "Server-ul API-ului Amuse rulează. GET /query pentru a obține informații despre melodie."
}
},
"api-server": { "api-server": {
"description": "Adauga un server API pentru a controla player-ul", "description": "Adaugă un server API pentru a controla player-ul",
"dialog": { "dialog": {
"request": { "request": {
"buttons": { "buttons": {
"allow": "Permite", "allow": "Permite",
"deny": "Respinge" "deny": "Respinge"
}, },
"message": "Permite {{ID}} {{origin}} sa acceseze API-ul?", "message": "Permite {{ID}} {{origin}} să acceseze API-ul?",
"title": "Cerere autorizare API" "title": "Cerere autorizare API"
} }
}, },
"menu": { "menu": {
"auth-strategy": { "auth-strategy": {
"label": "Strategie autorizare", "label": "Strategie de autorizare",
"submenu": { "submenu": {
"auth-at-first": { "auth-at-first": {
"label": "Autorizare la prima cerere" "label": "Autorizare la prima cerere"
}, },
"none": { "none": {
"label": "Fara autorizare" "label": "Fără autorizare"
} }
} }
}, },
@ -313,101 +320,101 @@
"name": "Server API [Beta]", "name": "Server API [Beta]",
"prompt": { "prompt": {
"hostname": { "hostname": {
"label": "Introduceti nume host (0.0.0.0 de ex.) pentru server-ul API:", "label": "Introduceți nume host (0.0.0.0 de ex.) pentru server-ul API:",
"title": "Nume host" "title": "Nume host"
}, },
"port": { "port": {
"label": "Introduceti port-ul pentru server-ul API:", "label": "Introduceți port-ul pentru server-ul API:",
"title": "Port" "title": "Port"
} }
} }
}, },
"audio-compressor": { "audio-compressor": {
"description": "Aplica compresie pe audio (scade volumul partilor cele mai sonore si creste volumul partilor mai putin sonore)", "description": "Aplică compresie pe audio (scade volumul părților cele mai zgomotoase și crește volumul părților mai puțin zgomotoase)",
"name": "Compresor audio" "name": "Compresor audio"
}, },
"blur-nav-bar": { "blur-nav-bar": {
"description": "Fa bara de navigare semi-transparenta", "description": "Face bara de navigare semi-transparentă",
"name": "Bara de naviagtie semi-transparenta" "name": "Estompează Bara de Navigație"
}, },
"bypass-age-restrictions": { "bypass-age-restrictions": {
"description": "Treci peste verificarea de varsta a YouTube-ului", "description": "Treci peste verificarea de vârstă a YouTube-ului",
"name": "Ignora restrictiile de varsta" "name": "Ignoră restricțiile de vârstă"
}, },
"captions-selector": { "captions-selector": {
"description": "Selector de subtitrari pentru piesele audio de pe YouTube Music", "description": "Selector de subtitrări pentru piesele audio de pe YouTube Music",
"menu": { "menu": {
"autoload": "Selecteaza automat ultima subtitrare folosita", "autoload": "Selectează automat ultima subtitrare folosită",
"disable-captions": "Fara subtitrari by default" "disable-captions": "Fără subtitrări în mod implicit"
}, },
"name": "Selector de subtitrari", "name": "Selector de subtitrări",
"prompt": { "prompt": {
"selector": { "selector": {
"label": "Limba curenta a subtitrarilor: {{language}}", "label": "Limba curentă a subtitrărilor: {{language}}",
"none": "Niciuna", "none": "Niciuna",
"title": "Alege limba subtitrarilor" "title": "Alege limba subtitrărilor"
} }
}, },
"templates": { "templates": {
"title": "Deschide selectorul de subtitrari" "title": "Deschide selectorul de subtitrări"
} }
}, },
"compact-sidebar": { "compact-sidebar": {
"description": "Pastreaza bara laterala mereu in modul compact", "description": "Păstrează bara laterală mereu în modul compact",
"name": "Bara laterala compacta" "name": "Bara Laterală Compactă"
}, },
"crossfade": { "crossfade": {
"description": "Tranzitioneaza intre cantece", "description": "Tranziționează între melodii",
"menu": { "menu": {
"advanced": "Avansat" "advanced": "Avansat"
}, },
"name": "Tranzitie [Beta]", "name": "Tranziție [Beta]",
"prompt": { "prompt": {
"options": { "options": {
"multi-input": { "multi-input": {
"fade-in-duration": "Durata tranzitie de inceput (ms)", "fade-in-duration": "Durată tranziție de început (ms)",
"fade-out-duration": "Durata tranzitie de sfarsit (ms)", "fade-out-duration": "Durată tranziției de sfârșit (ms)",
"fade-scaling": { "fade-scaling": {
"label": "Scala tranzitiei", "label": "Scalare de estompare",
"linear": "Linear", "linear": "Liniar",
"logarithmic": "Logaritmic" "logarithmic": "Logaritmic"
}, },
"seconds-before-end": "Tranzitie N secunde inainte de final" "seconds-before-end": "Tranziție N secunde înainte de final"
}, },
"title": "Optiuni de tranzitie" "title": "Opțiuni de tranziție"
} }
} }
}, },
"disable-autoplay": { "disable-autoplay": {
"description": "Fa cantecul sa inceapa in modul \"pauza\"", "description": "Face cântecul să înceapă în modul \"pauză\"",
"menu": { "menu": {
"apply-once": "Se aplica doar la pornirea aplicatiei" "apply-once": "Se aplică doar la pornirea aplicației"
}, },
"name": "Dezactiveaza redarea automata" "name": "Dezactivează redarea automată"
}, },
"discord": { "discord": {
"backend": { "backend": {
"already-connected": "S-a incercat conectarea cu o conexiune activa", "already-connected": "S-a încercat conectarea cu o conexiune activă",
"connected": "Conectat la Discord", "connected": "Conectat la Discord",
"disconnected": "Deconectat de la Discord" "disconnected": "Deconectat de la Discord"
}, },
"description": "Arata-le prietenilor ce asculti cu Rich Presence", "description": "Arată-le prietenilor ce asculți cu Rich Presence",
"menu": { "menu": {
"auto-reconnect": "Reconectare automata", "auto-reconnect": "Reconectare automată",
"clear-activity": "Sterge activitatea", "clear-activity": "Șterge activitatea",
"clear-activity-after-timeout": "Sterge activitatea dupa timeout", "clear-activity-after-timeout": "Șterge activitatea după timeout",
"connected": "Conectat", "connected": "Conectat",
"disconnected": "Deconectat", "disconnected": "Deconectat",
"hide-duration-left": "Ascunde timpul ramas", "hide-duration-left": "Ascunde timpul rămas",
"hide-github-button": "Ascunde butonul cu link-ul GitHub", "hide-github-button": "Ascunde butonul cu link-ul GitHub",
"play-on-youtube-music": "Reda pe YouTube Music", "play-on-youtube-music": "Redă pe YouTube Music",
"set-inactivity-timeout": "Seteaza intervalul de inactivitate" "set-inactivity-timeout": "Setează intervalul de inactivitate"
}, },
"name": "Discord Rich Presence", "name": "Discord Rich Presence",
"prompt": { "prompt": {
"set-inactivity-timeout": { "set-inactivity-timeout": {
"label": "Introduceti perioada de inactivitate dorita in secunde:", "label": "Introduceți perioada de inactivitate dorită în secunde:",
"title": "Seteaza timpul de inactivitate" "title": "Setează timpul de inactivitate"
} }
} }
}, },
@ -418,51 +425,51 @@
"buttons": { "buttons": {
"ok": "OK" "ok": "OK"
}, },
"message": "Argh! Scuze, descarcarea a esuat…", "message": "Ah! Scuze, descărcarea a eșuat…",
"title": "Eroare la descarcare!" "title": "Eroare la descărcare!"
}, },
"start-download-playlist": { "start-download-playlist": {
"buttons": { "buttons": {
"ok": "OK" "ok": "OK"
}, },
"detail": "({{playlistSize}} cantece)", "detail": "({{playlistSize}} melodii)",
"message": "Se descarca Playlist-ul {{playlistTitle}}", "message": "Se descarca Playlist-ul {{playlistTitle}}",
"title": "Descarcarea a inceput" "title": "Descărcarea a început"
} }
}, },
"feedback": { "feedback": {
"conversion-progress": "Conversie: {{percent}}%", "conversion-progress": "Conversie: {{percent}}%",
"converting": "Se converteste…", "converting": "Se convertește…",
"done": "Descarcat: {{filePath}}", "done": "Descărcat: {{filePath}}",
"download-info": "Se descarca {{artist}} -{{title}} [{{videoId}}", "download-info": "Se descarcă {{artist}} -{{title}} [{{videoId}}",
"download-progress": "Se descarca: {{percent}}%", "download-progress": "Se descarcă: {{percent}}%",
"downloading": "Se descarca…", "downloading": "Se descarcă…",
"downloading-counter": "Se descarca {{current}}/{{total}}…", "downloading-counter": "Se descarcă {{current}}/{{total}}…",
"downloading-playlist": "Se descarca playlist-ul \"{{playlistTitle}}\" - {{playlistSize}} piese ({{playlistId}})", "downloading-playlist": "Se descarcă lista de redare \"{{playlistTitle}}\" - {{playlistSize}} piese ({{playlistId}})",
"error-while-downloading": "Eroare la descarcarea piesei \"{{author}} - {{title}}\":{{error}}", "error-while-downloading": "Eroare la descarcareă piesei \"{{author}} - {{title}}\":{{error}}",
"folder-already-exists": "Folderul {{playlistFolder}} exista deja", "folder-already-exists": "Dosarul {{playlistFolder}} există deja",
"getting-playlist-info": "Se aduna informatiile despre playlist…", "getting-playlist-info": "Se adună informațiile despre lista de redare…",
"loading": "Se incarca…", "loading": "Se incarcă…",
"playlist-has-only-one-song": "Playlist-ul are doar un element, acesta va fi descarcat direct", "playlist-has-only-one-song": "Lista de redare are doar un element, acesta va fi descărcat direct",
"playlist-id-not-found": "Niciun ID al playlist-ului nu a fost gasit", "playlist-id-not-found": "Niciun ID al listei de redare nu a fost gasit",
"playlist-is-empty": "Playlist-ul este gol", "playlist-is-empty": "Lista de redare este goală",
"playlist-is-mix-or-private": "Eroare la colectarea informatiilor despre playlist: asigurati-va ca nu este privat sau un playlist \"Mixed for you\"\n\n{{error}}", "playlist-is-mix-or-private": "Eroare la colectarea informațiilor despre lista de redare: asigurați-vă că nu este privat sau o listă de redare \"Mixed for you\"\n\n{{error}}",
"preparing-file": "Se pregateste fisierul…", "preparing-file": "Se pregătește fișierul…",
"saving": "Se salveaza…", "saving": "Se salvează…",
"trying-to-get-playlist-id": "Se incearca obtinerea ID-ului playlist-ului: {{playlistId}}", "trying-to-get-playlist-id": "Se încearcă obținerea ID-ului listei de redare: {{playlistId}}",
"video-id-not-found": "Video-ul nu a fost gasit", "video-id-not-found": "Videoclipul nu a fost găsit",
"writing-id3": "Se scriu tag-urile ID3…" "writing-id3": "Se scriu tag-urile ID3…"
} }
}, },
"description": "Descarca MP3 / sursa audio direct din interfata", "description": "Descarcă MP3 / sursa audio direct din interfață",
"menu": { "menu": {
"choose-download-folder": "Alege folderul de descarcari", "choose-download-folder": "Alege folderul de descărcări",
"download-finish-settings": { "download-finish-settings": {
"label": "Descarcare la finalizare", "label": "Descărcare la finalizare",
"prompt": { "prompt": {
"last-percent": "Dupa x la suta", "last-percent": "După x la sută",
"last-seconds": "Ultimele x secunde", "last-seconds": "Ultimele x secunde",
"title": "Configureaza cand sa descarce" "title": "Configurează când să se descarce"
}, },
"submenu": { "submenu": {
"advanced": "Avansat", "advanced": "Avansat",
@ -472,35 +479,47 @@
"seconds": "Secunde" "seconds": "Secunde"
} }
}, },
"download-playlist": "Descarca playlist-ul", "download-playlist": "Descarcă lista de redare",
"presets": "Setari implicite", "presets": "Setări implicite",
"skip-existing": "Treci peste fisierele existente" "skip-existing": "Treci peste fișierele existente"
}, },
"name": "Downloader", "name": "Descărcător",
"renderer": { "renderer": {
"can-not-update-progress": "Nu se poate actualiza progresul" "can-not-update-progress": "Nu se poate actualiza progresul"
}, },
"templates": { "templates": {
"button": "Descarca" "button": "Descarcă"
} }
}, },
"equalizer": {
"description": "Adauă un egalizator la player",
"menu": {
"presets": {
"label": "Setări implicite",
"list": {
"bass-booster": "Amplificator de bas"
}
}
},
"name": "Egalizator"
},
"exponential-volume": { "exponential-volume": {
"description": "Fa slider-ul de volum exponential pentru a fi mai usor de selectat volumuri reduse.", "description": "Face glisorul de volum exponențial pentru a fi mai ușor de selectat volume reduse.",
"name": "Volum exponential" "name": "Volum exponențial"
}, },
"in-app-menu": { "in-app-menu": {
"description": "Ofera barelor de meniu un aspect extravagant, intunecat sau de culoarea albumului", "description": "Oferă barelor de meniu un aspect extravagant, întunecat sau de culoarea albumului",
"menu": { "menu": {
"hide-dom-window-controls": "Ascunde controalele ferestrei DOM" "hide-dom-window-controls": "Ascunde controalele ferestrei DOM"
}, },
"name": "Meniul aplicatiei" "name": "Meniul aplicației"
}, },
"lumiastream": { "lumiastream": {
"description": "Adauga asistenta pentru Lumia Stream", "description": "Adaugă asistenta pentru Lumia Stream",
"name": "Lumia Stream [Beta]" "name": "Lumia Stream [Beta]"
}, },
"lyrics-genius": { "lyrics-genius": {
"description": "Adauga versuri pentru majoritatea cantecelor", "description": "Adaugă versuri pentru majoritatea cântecelor",
"menu": { "menu": {
"romanized-lyrics": "Versuri romantizate" "romanized-lyrics": "Versuri romantizate"
}, },
@ -510,29 +529,29 @@
} }
}, },
"music-together": { "music-together": {
"description": "Impartaseste playlist-ul cu altii. Cand gazda va pune o piesa, toti ceilalti vor auzi acelasi cantec", "description": "Împărtășește lista de redare cu alții. Când gazda va pune o piesă, toți ceilalți vor auzi aceeași melodie",
"dialog": { "dialog": {
"enter-host": "Introdu ID-ul host-ului" "enter-host": "Introdu ID-ul host-ului"
}, },
"internal": { "internal": {
"save": "Salveaza", "save": "Salvează",
"track-source": "Sursa piesei", "track-source": "Sursa piesei",
"unknown-user": "Utilizator necunoscut" "unknown-user": "Utilizator necunoscut"
}, },
"menu": { "menu": {
"click-to-copy-id": "Copiaza ID-ul host-ului", "click-to-copy-id": "Copiază ID-ul host-ului",
"close": "Inchide Music Together", "close": "Închide Music Together",
"connected-users": "Utilizatori conectati", "connected-users": "Utilizatori conecțati",
"disconnect": "Deconecteaza Music Together", "disconnect": "Deconectează Music Together",
"empty-user": "Niciun utilizator conectat", "empty-user": "Niciun utilizator conectat",
"host": "Gazda Music Together", "host": "Gazda Music Together",
"join": "Alatura-te Music Together", "join": "Alătura-te Music Together",
"permission": { "permission": {
"all": "Permite invitatilor sa controleze playlist-ul si player-ul", "all": "Permite invitaților să controleze lista de redare si player-ul",
"host-only": "Doar gazda poate controla playlist-ul si player-ul", "host-only": "Doar gazda poate controla lista de redare și player-ul",
"playlist": "Permite invitatilor controlul asupra playlist-ului" "playlist": "Permite invitaților controlul asupra listei de redare"
}, },
"set-permission": "Schimba controlul permisiunilor", "set-permission": "Schimbă controlul permisiunilor",
"status": { "status": {
"disconnected": "Deconectat", "disconnected": "Deconectat",
"guest": "Conectat ca invitat", "guest": "Conectat ca invitat",
@ -541,63 +560,63 @@
}, },
"name": "Music Together [Beta]", "name": "Music Together [Beta]",
"toast": { "toast": {
"add-song-failed": "Adaugarea piesei a esuat", "add-song-failed": "Adăugarea piesei a eșuat",
"closed": "Music Together inchis", "closed": "Music Together închis",
"disconnected": "Music Together deconectat", "disconnected": "Music Together deconectat",
"host-failed": "Nu s-a reusit gazduirea Music Together", "host-failed": "Nu s-a reușit găzduirea Music Together",
"id-copied": "ID-ul host-ului a fost copiat in clipboard", "id-copied": "ID-ul host-ului a fost copiat în clipboard",
"id-copy-failed": "Eroare la copierea ID-ului host-ului in clipboard", "id-copy-failed": "Eroare la copierea ID-ului host-ului în clipboard",
"join-failed": "Nu s-a reusit alaturarea la Music Together", "join-failed": "Nu s-a reușit alăturarea la Music Together",
"joined": "V-ati alaturat Music Together", "joined": "V-ați alăturat Music Together",
"permission-changed": "Permisiunile Music Together s-au schimbat la \"{{permission}}\"", "permission-changed": "Permisiunile Music Together s-au schimbat la \"{{permission}}\"",
"remove-song-failed": "Eroare la indepartarea cantecului", "remove-song-failed": "Eroare la îndepărtarea melodiei",
"user-connected": "{{name}} s-a alaturat la Music Together", "user-connected": "{{name}} s-a alăturat la Music Together",
"user-disconnected": "{{name}} a parasit Music Together" "user-disconnected": "{{name}} a părăsit Music Together"
} }
}, },
"navigation": { "navigation": {
"description": "Sagetile pentru Urmatorul/Anteriorul integrate direct in interfata, ca in browser-ul tau preferat", "description": "Săgețile pentru Următorul/Anteriorul integrate direct în interfață, ca în browser-ul tău preferat",
"name": "Navigatie" "name": "Navigație"
}, },
"no-google-login": { "no-google-login": {
"description": "Elimina butonul de autentificare Google si link-urile din interfata", "description": "Elimină butonul de autentificare Google și link-urile din interfață",
"name": "Nicio autentificare Google" "name": "Nicio autentificare Google"
}, },
"notifications": { "notifications": {
"description": "Afiseaza o notificare cand incepe sa cante o piesa (notificarile interactive sunt disponibile pe Windows)", "description": "Afișează o notificare când începe să cânte o piesă (notificările interactive sunt disponibile pe Windows)",
"menu": { "menu": {
"interactive": "Notificari interactive", "interactive": "Notificări interactive",
"interactive-settings": { "interactive-settings": {
"label": "Setari interactive", "label": "Setări interactive",
"submenu": { "submenu": {
"hide-button-text": "Ascunde textul butoanelor", "hide-button-text": "Ascunde textul butoanelor",
"refresh-on-play-pause": "Reimprospateaza la Reda/Pauza", "refresh-on-play-pause": "Reîmprospătează la Redă/Pauză",
"tray-controls": "Deschide/Inchide la apasarea icnoitei pentru meniul Tray" "tray-controls": "Deschide/Închide la apăsarea iconiței pentru meniul Tray"
} }
}, },
"priority": "Prioritatea notificarilor", "priority": "Prioritatea notificărilor",
"toast-style": "Stilul notificarilor", "toast-style": "Stilul notificărilor",
"unpause-notification": "Arata notificarile la pauza" "unpause-notification": "Arată notificările la pauză"
}, },
"name": "Notificari" "name": "Notificări"
}, },
"picture-in-picture": { "picture-in-picture": {
"description": "Permite sa schimbi aplicatie la modul picture-in-picture", "description": "Permite să schimbi aplicația la modul picture-in-picture",
"menu": { "menu": {
"always-on-top": "Mereu deasupra", "always-on-top": "Mereu deasupra",
"hotkey": { "hotkey": {
"label": "Scurtaturi pe tastatura", "label": "Scurtături pe tastatură",
"prompt": { "prompt": {
"keybind-options": { "keybind-options": {
"hotkey": "Scurtaturi din taste" "hotkey": "Scurtături din taste"
}, },
"label": "Scurtaturi din taste pentru picture-in-picture", "label": "Alege tasta pentru picture-in-picture",
"title": "Scurtatura Picture-in-picture" "title": "Scurtătura Picture-in-picture"
} }
}, },
"save-window-position": "Salveaza pozitia ferestrei", "save-window-position": "Salvează poziția ferestrei",
"save-window-size": "Salveaza marimea ferestrei", "save-window-size": "Salvează mărimea ferestrei",
"use-native-pip": "Foloseste PiP-ul nativ pentru broswer" "use-native-pip": "Folosește PiP-ul nativ pentru broswer"
}, },
"name": "Picture-in-picture", "name": "Picture-in-picture",
"templates": { "templates": {
@ -605,31 +624,31 @@
} }
}, },
"playback-speed": { "playback-speed": {
"description": "Asculta rapid, asculta lent! Adauga un slider pentru viteza de redare a cantecului", "description": "Ascultă rapid, ascultă lent! Adaugă un slider pentru viteza de redare a melodiei",
"name": "Viteza de redare", "name": "Viteza de redare",
"templates": { "templates": {
"button": "Viteza" "button": "Viteză"
} }
}, },
"precise-volume": { "precise-volume": {
"description": "Controleaza volumul precis folosind rotita mouse-ului/scurtaturi din tastatura, cu un HUD personalizat si incremente de volum personalizate", "description": "Controlează volumul precis folosind rotița mouse-ului/scurtăturii din tastatură, cu un HUD personalizat și incremente de volum personalizate",
"menu": { "menu": {
"arrows-shortcuts": "Control cu tastele sageti locale", "arrows-shortcuts": "Control cu tastele-săgeți locale",
"custom-volume-steps": "Seteaza incrementele de volum", "custom-volume-steps": "Setează incrementele de volum",
"global-shortcuts": "Scurtaturi de tastatura globale" "global-shortcuts": "Scurtături de tastatură globale"
}, },
"name": "Volum precis", "name": "Volum precis",
"prompt": { "prompt": {
"global-shortcuts": { "global-shortcuts": {
"keybind-options": { "keybind-options": {
"decrease": "Redu volumul audio", "decrease": "Redu volumul audio",
"increase": "Creste volumul audio" "increase": "Crește volumul audio"
}, },
"label": "Alege combinatiile de taste globale pentru volumul audio:", "label": "Alege combinațiile de taste globale pentru volumul audio:",
"title": "Combinatii globale de taste pentru volum" "title": "Combinații globale de taste pentru volum"
}, },
"volume-steps": { "volume-steps": {
"label": "Alege pasii de increment pentru volum audio", "label": "Alege pașii de increment pentru volum audio",
"title": "Incremente de volum" "title": "Incremente de volum"
} }
} }
@ -638,28 +657,28 @@
"backend": { "backend": {
"dialog": { "dialog": {
"quality-changer": { "quality-changer": {
"detail": "Calitate actuala: {{quality}}", "detail": "Calitate actuală: {{quality}}",
"message": "Alegeti calitatea video:", "message": "Alegeți calitatea video:",
"title": "Alegeti calitatea video" "title": "Alegeți calitatea video"
} }
} }
}, },
"description": "Permite schimbarea calitatii video cu un buton prezent peste video", "description": "Permite schimbarea calității video cu un buton prezent peste video",
"name": "Modificator de calitate video" "name": "Schimbător de calitate video"
}, },
"scrobbler": { "scrobbler": {
"description": "Adauga asistenta pentru scrobbling (etc. last.fm, Listenbrainz)", "description": "Adaugă asistenta pentru scrobbling (etc. last.fm, Listenbrainz)",
"dialog": { "dialog": {
"lastfm": { "lastfm": {
"auth-failed": { "auth-failed": {
"message": "Autentificarea cu Last.fm a esuat\nAscunde acest pop-up pana la urmatoarea repornire.", "message": "Autentificarea cu Last.fm a eșuat\nAscunde acest pop-up până la următoarea repornire.",
"title": "Autentificare Esuata" "title": "Autentificare Eșuată"
} }
} }
}, },
"menu": { "menu": {
"lastfm": { "lastfm": {
"api-settings": "Setari pentru API-ul Last.fm" "api-settings": "Setări pentru API-ul Last.fm"
}, },
"listenbrainz": { "listenbrainz": {
"token": "Introdu token-ul de utilizator ListenBrainz" "token": "Introdu token-ul de utilizator ListenBrainz"
@ -674,102 +693,105 @@
}, },
"listenbrainz": { "listenbrainz": {
"token": { "token": {
"label": "Introdu token-ul tau de utilizator ListenBrainz:", "label": "Introdu token-ul tău de utilizator ListenBrainz:",
"title": "Token-ul ListenBrainz" "title": "Token-ul ListenBrainz"
} }
} }
} }
}, },
"shortcuts": { "shortcuts": {
"description": "Permite setari globale pentru scurtaturi pe tastatura pentru playback (reda/pauza/urmatorul/anteriorul), pentru oprirea media OSD prin suprascriera tastelor media, pentru folosirea combinatiei Ctrl/CMD + F pentru a cauta, pentru asistenta Linux MPRIS pentru taste media si pentru scurtaturi perosnalizate pentru utilizatori avansati", "description": "Permite setari globale pentru scurtături pe tastatură pentru redare (redă/pauză/următorul/anteriorul) și pentru oprirea media OSD prin suprascriera tastelor media, pentru folosirea combinației Ctrl/CMD + F pentru a căuta, pentru pornirea asistenței Linux MPRIS pentru taste media și pentru scurtături personalizate pentru utilizatori avansați",
"menu": { "menu": {
"override-media-keys": "Suprascrie tastele media", "override-media-keys": "Suprascrie tastele media",
"set-keybinds": "Seteaza scurtaturile globale pentru cantece" "set-keybinds": "Setează scurtăturile globale pentru melodii"
}, },
"name": "Scurtaturi (& MPRIS)", "name": "Scurtături (& MPRIS)",
"prompt": { "prompt": {
"keybind": { "keybind": {
"keybind-options": { "keybind-options": {
"next": "Urmatorul", "next": "Următorul",
"play-pause": "Reda / Pauza", "play-pause": "Redă / Pauză",
"previous": "Anteriorul" "previous": "Anteriorul"
}, },
"label": "Alege combinatia de taste globala pentru controlul cantecelor:", "label": "Alege combinația de taste globală pentru controlul melodiilor:",
"title": "Scurtaturi pe tastatura globale" "title": "Scurtături pe tastatură globale"
} }
} }
}, },
"skip-disliked-songs": { "skip-disliked-songs": {
"description": "Sari peste cantecele disliked", "description": "Sari peste melodiile neplăcute",
"name": "Treci peste cantecele disliked" "name": "Treci peste melodiile neplăcute"
}, },
"skip-silences": { "skip-silences": {
"description": "Treci automat peste sectiunile de liniste din cantece", "description": "Treci automat peste secțiunile de liniște din melodii",
"name": "Treci peste liniste" "name": "Treci peste liniște"
}, },
"sponsorblock": { "sponsorblock": {
"description": "Treci automat peste partile non-muzicale precum intro/outro sau parti din video-ul catecului, cand nu se aude cantecul", "description": "Treci automat peste părțile non-muzicale precum intro/outro sau părți din video-ul melodiei, când nu se aude melodia",
"name": "SponsorBlock" "name": "SponsorBlock"
}, },
"synced-lyrics": { "synced-lyrics": {
"description": "Furnizeaza versuri sincronizate melodiilor, folosind furnizori precum LRClib.", "description": "Furnizează versuri sincronizate melodiilor, folosind furnizori precum LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - A aparut o eroare in timpul incarcarii versurilor. Te rog incearca din nou mai tarziu.", "fetch": "⚠️ - A apărut o eroare în timpul încărcării versurilor. \nTe rog încearcă din nou mai târziu.",
"not-found": "⚠️ - Nu au fost gasite versuri pentru aceasta melodie." "not-found": "⚠️ Nu au fost găsite versuri pentru această melodie."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
"label": "Caracter implicit intre versuri", "label": "Caracter implicit între versuri",
"tooltip": "Alege caracterul implicit folosit pentru spatiul dintre versuri" "tooltip": "Alege caracterul implicit folosit pentru spațiul dintre versuri"
}, },
"line-effect": { "line-effect": {
"label": "Efect de linie", "label": "Efect de linie",
"submenu": { "submenu": {
"fancy": {
"tooltip": "Folosește efecte largi pe linia curentă"
},
"focus": { "focus": {
"label": "Focalizare", "label": "Focalizare",
"tooltip": "Doar linia curenta este alba" "tooltip": "Doar linia curentă este albă"
}, },
"offset": { "offset": {
"label": "Offset", "label": "Deplasare",
"tooltip": "Deplasare la dreapta pentru linia curenta" "tooltip": "Deplasare la dreapta pentru linia curentă"
}, },
"scale": { "scale": {
"label": "Marime", "label": "Mărime",
"tooltip": "Schimba dimensiunea liniei curente" "tooltip": "Schimbă dimensiunea liniei curente"
} }
}, },
"tooltip": "Alege efectul aplicat liniei curente" "tooltip": "Alege efectul aplicat liniei curente"
}, },
"precise-timing": { "precise-timing": {
"label": "Sincronizeaza versurile perfect", "label": "Sincronizează versurile perfect",
"tooltip": "Calculeaza afisarea urmatoarei linii pana la milisecunda (poate afecta performanta)" "tooltip": "Calculează afisarea următoarei linii până la milisecundă (poate afecta performanța)"
}, },
"show-lyrics-even-if-inexact": { "show-lyrics-even-if-inexact": {
"label": "Afiseaza versurile chiar daca sunt inexacte", "label": "Afișează versurile chiar dacă sunt inexacte",
"tooltip": "Daca melodia nu este gasita, plugin-ul incearca din nou cu o cautare diferita.\nRezultatul acestei incercari poate sa nu fie exact." "tooltip": "Dacă melodia nu este găsită, plugin-ul încearcă din nou cu o căutare diferită.\nRezultatul acestei încercări poate să nu fie exact."
}, },
"show-time-codes": { "show-time-codes": {
"label": "Afiseaza timecode-urile", "label": "Afișează codurile de timp",
"tooltip": "Afiseaza codurile de timp langa versuri" "tooltip": "Afișează codurile de timp lângă versuri"
} }
}, },
"name": "Versuri Sincronizate", "name": "Versuri Sincronizate",
"refetch-btn": { "refetch-btn": {
"fetching": "Incarcare...", "fetching": "Încărcare...",
"normal": "Reincarcare versuri" "normal": "Reîncărcare versuri"
}, },
"warnings": { "warnings": {
"duration-mismatch": "⚠️ - Versurile pot fi desincronizate din cauza unei nepotriviri de duratie.", "duration-mismatch": "⚠️ - Versurile pot fi desincronizate din cauza unei nepotriviri de durație.",
"inexact": "⚠️ - Versurile pentru aceasta melodie pot fi inexacte", "inexact": "⚠️ - Versurile pentru această melodie pot fi inexacte",
"instrumental": "⚠️ - Aceasta melodie este instrumentala" "instrumental": "⚠️ - Această melodie este instrumentală"
} }
}, },
"taskbar-mediacontrol": { "taskbar-mediacontrol": {
"description": "Controleaza redarea din Bara de Activitati Windows", "description": "Controlează redarea din Bara de Activități Windows",
"name": "Control media in Bara de Activitate" "name": "Control media in Bara de Activitate"
}, },
"touchbar": { "touchbar": {
"description": "Adauga un widget TouchBar pentru utilizatorii macOS", "description": "Adaugă un widget TouchBar pentru utilizatorii macOS",
"name": "TouchBar" "name": "TouchBar"
}, },
"tuna-obs": { "tuna-obs": {
@ -777,17 +799,17 @@
"name": "Tuna OBS" "name": "Tuna OBS"
}, },
"video-toggle": { "video-toggle": {
"description": "Adauga un buton ce schimba intre modurile Video/Cantec. se poate optional elimia complet optiunea video", "description": "Adaugă un buton ce schimbă între modurile Video/Melodie. De asemenea se poate elimina opțional toată fila video",
"menu": { "menu": {
"align": { "align": {
"label": "Aliniere", "label": "Aliniere",
"submenu": { "submenu": {
"left": "Stanga", "left": "Stânga",
"middle": "Mijloc", "middle": "Mijloc",
"right": "Dreapta" "right": "Dreapta"
} }
}, },
"force-hide": "Forteaza eliminarea tab-ului video", "force-hide": "Forțează eliminarea filei video",
"mode": { "mode": {
"label": "Mod", "label": "Mod",
"submenu": { "submenu": {
@ -799,15 +821,15 @@
}, },
"name": "Comutator video", "name": "Comutator video",
"templates": { "templates": {
"button": "Cantec" "button": "Melodie"
} }
}, },
"visualizer": { "visualizer": {
"description": "Adauga un visualizer la player", "description": "Adaugă un vizualizator la player",
"menu": { "menu": {
"visualizer-type": "Tip de visualizer" "visualizer-type": "Tip de vizualizator"
}, },
"name": "Visualizer" "name": "Vizualizator"
} }
} }
} }

View File

@ -683,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "Введите токен пользователя ListenBrainz" "token": "Введите токен пользователя ListenBrainz"
}, },
"scrobble-alternative-title": "Использовать альтернативные названия",
"scrobble-other-media": "Скробблинг других медиа" "scrobble-other-media": "Скробблинг других медиа"
}, },
"name": "Скробблер", "name": "Скробблер",

View File

@ -33,7 +33,7 @@
"css-file-not-found": "සීඑස්එස් ගොනුව \"{{cssFile}}\" නොපවතී, නොසලකා හැරීම" "css-file-not-found": "සීඑස්එස් ගොනුව \"{{cssFile}}\" නොපවතී, නොසලකා හැරීම"
}, },
"unresponsive": { "unresponsive": {
"details": "ප්‍රතිචාර නොදක්වන දෝෂයක් {{error}}" "details": "ප්‍රතිචාර නොදක්වන දෝෂයක්\n{{error}}"
}, },
"when-ready": { "when-ready": {
"clearing-cache-after-20s": "යෙදුම් කෑශ් නිදහස් කරමින්" "clearing-cache-after-20s": "යෙදුම් කෑශ් නිදහස් කරමින්"
@ -41,7 +41,7 @@
}, },
"dialog": { "dialog": {
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "මෙනුව සැගවී ඇත, 'Alt' යතුර නැවත පෙන්වීමට භාවිතා කරන්න. (හෝ In-App මෙනුවේ 'Escape')", "detail": "මෙනුව සැගවී ඇත, නැවත පෙන්වීමට 'Alt' යතුර භාවිතා කරන්න. (හෝ In-App මෙනුවේ 'Escape')",
"message": "මෙනුව සැගවීම සාර්තකයි", "message": "මෙනුව සැගවීම සාර්තකයි",
"title": "මෙනුව සැගවීම සක්‍රීයයි" "title": "මෙනුව සැගවීම සක්‍රීයයි"
}, },

View File

@ -1,9 +1,119 @@
{ {
"common": {
"console": {
"plugins": {
"execute-failed": "Misslyckades med att köra plugin {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} kördes på {{ms}} ms",
"initialize-failed": "Misslyckades med att initialisera pluginen \"{{pluginName}}\"",
"load-all": "Laddar alla pluginer",
"load-failed": "Misslyckades med att ladda pluginen \"{{pluginName}}\"",
"loaded": "Pluginen \"{{pluginName}}\" laddad",
"unload-failed": "Misslyckades med att avlasta pluginen \"{{pluginName}}\"",
"unloaded": "Pluginen \"{{pluginName}}\" avlastad"
}
}
},
"language": { "language": {
"code": "sv", "code": "sv",
"local-name": "Svenska", "local-name": "Svenska",
"name": "Swedish" "name": "Swedish"
}, },
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Laddning klar. DevTools öppnad"
},
"i18n": {
"loaded": "i18n laddad"
},
"second-instance": {
"receive-command": "Mottog kommando via protokoll: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS-filen \"{{cssFile}}\" finns inte, ignorerar"
},
"unresponsive": {
"details": "Oresponsivt fel!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Rensar appens cache"
},
"window": {
"tried-to-render-offscreen": "Fönstret försökte rendera utanför skärmen, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menyn är dold, använd 'Alt' för att visa den (eller 'Escape' om du använder inbyggd meny)",
"message": "Dölj Meny är aktiverat",
"title": "Dölj Meny aktiverad"
},
"need-to-restart": {
"buttons": {
"later": "Senare",
"restart-now": "Starta om nu"
},
"detail": "\"{{pluginName}}\" pluginen kräver en omstart för att träda i kraft",
"message": "\"{{pluginName}}\" behöver startas om",
"title": "Omstart krävs"
},
"unresponsive": {
"buttons": {
"quit": "Avsluta",
"relaunch": "Starta om",
"wait": "Vänta"
},
"detail": "Vi beklagar besväret! Välj vad du vill göra:",
"message": "Programmet svarar inte",
"title": "Fönstret svarar inte"
},
"update-available": {
"buttons": {
"disable": "Stäng av uppdateringar",
"download": "Ladda ned",
"ok": "OK"
},
"detail": "En ny version är tillgänglig och kan laddas ned på {{downloadLink}}",
"message": "En ny version är tillgänglig",
"title": "Uppdatering tillgänglig"
}
},
"menu": {
"about": "Om",
"navigation": {
"label": "Navigering",
"submenu": {
"copy-current-url": "Kopiera nuvarande länk",
"go-back": "Föregående",
"go-forward": "Nästa",
"quit": "Lämna",
"restart": "Starta om appen"
}
},
"options": {
"label": "Valmöjligheter",
"submenu": {
"advanced-options": {
"label": "Avancerade valmöjligheter",
"submenu": {
"auto-reset-app-cache": "Nollställ appcache när appen startar",
"disable-hardware-acceleration": "Stäng av hårdvaruacceleration",
"edit-config-json": "Redigera config.json",
"restart-on-config-changes": "Starta om vid konfigurationsändringar",
"set-proxy": {
"label": "Ställ in proxy",
"prompt": {
"title": "Ställ in proxy"
}
}
}
},
"always-on-top": "Alltid överst",
"auto-update": "Uppdatera automatiskt"
}
}
}
},
"plugins": { "plugins": {
"navigation": { "navigation": {
"name": "Navigering" "name": "Navigering"

836
src/i18n/resources/ta.json Normal file
View File

@ -0,0 +1,836 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "சொருகி செயல்படுத்துவதில் தோல்வி {{pluginName}} :: {{contextName}}",
"executed-at-ms": "சொருகி {{pluginName}} :: {{contextName}} {{ms}} ms இல் செயல்படுத்தப்படுகிறது",
"initialize-failed": "சொருகி தொடங்குவதில் தோல்வி \"{{pluginName}}\"",
"load-all": "அனைத்து செருகுநிரல்களையும் ஏற்றுகிறது",
"load-failed": "சொருகி ஏற்றுவதில் தோல்வி \"{{pluginName}}\"",
"loaded": "சொருகி \"{{pluginName}}\" ஏற்றப்பட்டது",
"unload-failed": "சொருகி \"{{pluginName}}\"",
"unloaded": "சொருகி \"{{pluginName}}\" இறக்கப்பட்டது"
}
}
},
"language": {
"code": "என்",
"local-name": "ஆங்கிலம்",
"name": "ஆங்கிலம்"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "ஏற்றுதல் முடிந்தது. டெவ்டூல்ச் திறக்கப்பட்டது"
},
"i18n": {
"loaded": "ப18ல் ஏற்றப்பட்டது"
},
"second-instance": {
"receive-command": "நெறிமுறை மீது கட்டளை பெறப்பட்டது: \"{{command}}\""
},
"theme": {
"css-file-not-found": "சிஎச்எச் கோப்பு \"{{cssFile}}\" புறக்கணிக்கிறது"
},
"unresponsive": {
"details": "பதிலளிக்காத பிழை!\n {{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "பயன்பாட்டு தற்காலிக சேமிப்பை அழித்தல்"
},
"window": {
"tried-to-render-offscreen": "சாளரம் ஆஃப்ச்கிரீன், சாளரங்கள் = {{windowSize}}, டிச்ப்ளேச்ச் = {{displaySize}}, நிலை = {{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "பட்டியல் மறைக்கப்பட்டுள்ளது, அதைக் காட்ட 'ஆல்ட்' ஐப் பயன்படுத்தவும் (அல்லது பயன்பாட்டில் மெனுவைப் பயன்படுத்தினால் 'தப்பிக்க')",
"message": "மறை பட்டியல் இயக்கப்பட்டது",
"title": "பட்டியல் இயக்கப்பட்டது"
},
"need-to-restart": {
"buttons": {
"later": "பின்னர்",
"restart-now": "இப்போது மறுதொடக்கம் செய்யுங்கள்"
},
"detail": "\"{{pluginName}}\" சொருகி நடைமுறைக்கு மறுதொடக்கம் தேவை",
"message": "\"{{pluginName}}\" மறுதொடக்கம் செய்ய வேண்டும்",
"title": "மறுதொடக்கம் தேவை"
},
"unresponsive": {
"buttons": {
"quit": "வெளியேறு",
"relaunch": "மீண்டும் தொடங்கவும்",
"wait": "காத்திருங்கள்"
},
"detail": "சிரமத்திற்கு வருந்துகிறோம்! என்ன செய்ய வேண்டும் என்பதைத் தேர்வுசெய்க:",
"message": "பயன்பாடு பதிலளிக்கவில்லை",
"title": "சாளரம் பதிலளிக்கவில்லை"
},
"update-available": {
"buttons": {
"disable": "புதுப்பிப்புகளை முடக்கு",
"download": "பதிவிறக்கம்",
"ok": "சரி"
},
"detail": "ஒரு புதிய பதிப்பு கிடைக்கிறது மற்றும் {{downloadLink}} இல் பதிவிறக்கம் செய்யலாம்",
"message": "புதிய பதிப்பு கிடைக்கிறது",
"title": "புதுப்பிப்பு கிடைக்கிறது"
}
},
"menu": {
"about": "பற்றி",
"navigation": {
"label": "வானோடல்",
"submenu": {
"copy-current-url": "தற்போதைய முகவரி ஐ நகலெடுக்கவும்",
"go-back": "திரும்பிச் செல்லுங்கள்",
"go-forward": "முன்னோக்கிச் செல்லுங்கள்",
"quit": "வெளியேறு",
"restart": "பயன்பாட்டை மறுதொடக்கம் செய்யுங்கள்"
}
},
"options": {
"label": "விருப்பங்கள்",
"submenu": {
"advanced-options": {
"label": "மேம்பட்ட விருப்பங்கள்",
"submenu": {
"auto-reset-app-cache": "பயன்பாடு தொடங்கும் போது பயன்பாட்டு தற்காலிக சேமிப்பை மீட்டமைக்கவும்",
"disable-hardware-acceleration": "வன்பொருள் முடுக்கம் முடக்கு",
"edit-config-json": "Config.json ஐத் திருத்து",
"override-user-agent": "பயனர்-முகவர் மீறவும்",
"restart-on-config-changes": "கட்டமைப்பு மாற்றங்களை மறுதொடக்கம் செய்யுங்கள்",
"set-proxy": {
"label": "பதிலாள் அமைக்கவும்",
"prompt": {
"label": "பதிலாள் முகவரியை உள்ளிடவும்: (முடக்க காலியாக விடவும்)",
"placeholder": "எடுத்துக்காட்டு: SOCKS5: //127.0.0.1: 9999",
"title": "பதிலாள் அமைக்கவும்"
}
},
"toggle-dev-tools": "டெவ்டூல்சை மாற்றவும்"
}
},
"always-on-top": "எப்போதும் மேலே",
"auto-update": "ஆட்டோ புதுப்பிப்பு",
"hide-menu": {
"dialog": {
"message": "அடுத்த துவக்கத்தில் பட்டியல் மறைக்கப்படும், அதைக் காட்ட [Alt] ஐப் பயன்படுத்தவும் (அல்லது App-menu ஐப் பயன்படுத்தினால் [அல்லது பின்னணி [`])",
"title": "பட்டியல் இயக்கப்பட்டது"
},
"label": "மெனுவை மறைக்கவும்"
},
"language": {
"dialog": {
"message": "மறுதொடக்கம் செய்த பிறகு மொழி மாற்றப்படும்",
"title": "மொழி மாற்றப்பட்டது"
},
"label": "மொழி",
"submenu": {
"to-help-translate": "மொழிபெயர்க்க உதவ வேண்டுமா? இங்கே சொடுக்கு செய்க"
}
},
"resume-on-start": "பயன்பாடு தொடங்கும் போது கடைசி பாடலை மீண்டும் தொடங்குங்கள்",
"single-instance-lock": "ஒற்றை நிகழ்வு பூட்டு",
"start-at-login": "உள்நுழைவில் தொடங்கவும்",
"starting-page": {
"label": "தொடக்க பக்கம்",
"unset": "அமைக்கப்படாதது"
},
"tray": {
"label": "தட்டு",
"submenu": {
"disabled": "முடக்கப்பட்டது",
"enabled-and-hide-app": "இயக்கப்பட்ட மற்றும் பயன்பாட்டை மறைக்கவும்",
"enabled-and-show-app": "இயக்கப்பட்டது மற்றும் பயன்பாட்டைக் காட்டு",
"play-pause-on-click": "சொடுக்கு செய்யவும்/இடைநிறுத்தவும்"
}
},
"visual-tweaks": {
"label": "காட்சி மாற்றங்கள்",
"submenu": {
"like-buttons": {
"default": "இயல்புநிலை",
"force-show": "படை நிகழ்ச்சி",
"hide": "மறை",
"label": "பொத்தான்கள் போன்றவை"
},
"remove-upgrade-button": "மேம்படுத்தல் பொத்தானை அகற்று",
"theme": {
"dialog": {
"button": {
"cancel": "ரத்துசெய்",
"remove": "அகற்று"
},
"remove-theme": "தனிப்பயன் கருப்பொருளை அகற்ற விரும்புகிறீர்களா?",
"remove-theme-message": "இது தனிப்பயன் கருப்பொருளை அகற்றும்"
},
"label": "கருப்பொருள்",
"submenu": {
"import-css-file": "தனிப்பயன் சிஎச்எச் கோப்பை இறக்குமதி செய்க",
"no-theme": "கருப்பொருள் இல்லை"
}
}
}
}
}
},
"plugins": {
"enabled": "இயக்கப்பட்டது",
"label": "செருகுநிரல்கள்",
"new": "புதிய"
},
"view": {
"label": "பார்வை",
"submenu": {
"force-reload": "படை மறுஏற்றம்",
"reload": "ஏற்றவும்",
"reset-zoom": "உண்மையான அளவு",
"toggle-fullscreen": "முழுத் திரையை மாற்றவும்",
"zoom-in": "பெரிதாக்கு",
"zoom-out": "சிறிதாக்கு"
}
}
},
"tray": {
"next": "அடுத்தது",
"play-pause": "விளையாடு/இடைநிறுத்தம்",
"previous": "முந்தைய",
"quit": "வெளியேறு",
"restart": "பயன்பாட்டை மறுதொடக்கம் செய்யுங்கள்",
"show": "சாளரத்தைக் காட்டு",
"tooltip": {
"default": "யூடியூப் இசை",
"with-song-info": "YouTube இசை: {{artist}} - {{title}}"
}
}
},
"plugins": {
"ad-speedup": {
"description": "ஒரு விளம்பரம் விளையாடினால் அது ஆடியோவை முடக்குகிறது மற்றும் பின்னணி வேகத்தை 16x ஆக அமைக்கிறது",
"name": "விளம்பர விரைவு"
},
"adblocker": {
"description": "எல்லா விளம்பரங்களையும் தடுத்து பெட்டியிலிருந்து கண்காணிக்கவும்",
"menu": {
"blocker": "தடுப்பான்"
},
"name": "விளம்பர தடுப்பான்"
},
"album-actions": {
"description": "பிளேலிச்ட் அல்லது ஆல்பத்தில் உள்ள அனைத்து பாடல்களுக்கும் இதைப் பயன்படுத்த பொத்தான்கள் போன்றவற்றைச் சேர்க்கவும், விரும்பாதது, போன்றவை, மற்றும் பொத்தான்களைப் போலல்லாமல் சேர்க்கவும்",
"name": "ஆல்பம் செயல்கள்"
},
"album-color-theme": {
"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": "மென்மையான மாற்றம்",
"submenu": {
"during": "{{interpolationTime}} s இன் போது"
}
},
"use-fullscreen": {
"label": "முழுத்திரை பயன்படுத்துதல்"
}
},
"name": "சுற்றுப்புற முறை"
},
"amuse": {
"description": "6K ஆய்வகங்களால் இப்போது விட்செட்டில் விளையாடும் Amuse க்கு YouTube இசை ஆதரவை சேர்க்கிறது",
"name": "பொழுதுபோக்கு",
"response": {
"query": "பநிஇ சேவையகம் இயங்குகிறது. பாடல் தகவலைப் பெற /வினவல்."
}
},
"api-server": {
"description": "பிளேயரைக் கட்டுப்படுத்த பநிஇ சேவையகத்தைச் சேர்க்கிறது",
"dialog": {
"request": {
"buttons": {
"allow": "இசைவு",
"deny": "மறுக்கவும்"
},
"message": "பநிஇ ஐ அணுக {{ID}} ({{origin}}) அனுமதிக்கவா?",
"title": "பநிஇ அங்கீகார கோரிக்கை"
}
},
"menu": {
"auth-strategy": {
"label": "அங்கீகார உத்தி",
"submenu": {
"auth-at-first": {
"label": "முதல் கோரிக்கையின் பேரில் ஏற்பு"
},
"none": {
"label": "ஏற்பு இல்லை"
}
}
},
"hostname": {
"label": "புரவலன்பெயர்"
},
"port": {
"label": "துறைமுகம்"
}
},
"name": "பநிஇ சேவையகம் [பீட்டா]",
"prompt": {
"hostname": {
"label": "பநிஇ சேவையகத்திற்கு ஓச்ட்பெயரை (0.0.0.0 போன்றவை) உள்ளிடவும்:",
"title": "புரவலன்பெயர்"
},
"port": {
"label": "பநிஇ சேவையகத்திற்கான துறைமுகத்தை உள்ளிடவும்:",
"title": "துறைமுகம்"
}
}
},
"audio-compressor": {
"description": "ஆடியோவுக்கு சுருக்கத்தைப் பயன்படுத்துங்கள் (சமிக்ஞையின் உரத்த பகுதிகளின் அளவைக் குறைத்து, மென்மையான பகுதிகளின் அளவை உயர்த்துகிறது)",
"name": "ஆடியோ அமுக்கி"
},
"blur-nav-bar": {
"description": "வழிசெலுத்தல் பட்டியை வெளிப்படையானதாகவும் மங்கலாகவும் ஆக்குகிறது",
"name": "மங்கலான வழிசெலுத்தல் பட்டி"
},
"bypass-age-restrictions": {
"description": "YouTube அகவை சரிபார்ப்பு பைபாச்",
"name": "அகவை கட்டுப்பாடுகள் பைபாச்"
},
"captions-selector": {
"description": "YouTube இசை ஆடியோ டிராக்குகளுக்கான தலைப்பு தேர்வாளர்",
"menu": {
"autoload": "கடைசியாக பயன்படுத்தப்பட்ட தலைப்பை தானாகத் தேர்ந்தெடுக்கவும்",
"disable-captions": "முன்னிருப்பாக தலைப்புகள் இல்லை"
},
"name": "தலைப்புகள் தேர்வாளர்",
"prompt": {
"selector": {
"label": "தற்போதைய தலைப்பு மொழி: {{language}}",
"none": "எதுவுமில்லை",
"title": "தலைப்பு மொழியைத் தேர்ந்தெடுக்கவும்"
}
},
"templates": {
"title": "திறந்த தலைப்புகள் தேர்வாளர்"
}
},
"compact-sidebar": {
"description": "எப்போதும் பக்கப்பட்டியை சிறிய பயன்முறையில் அமைக்கவும்",
"name": "சிறிய பக்கப்பட்டி"
},
"crossfade": {
"description": "பாடல்களுக்கு இடையில் கிராச்ஃபேட்",
"menu": {
"advanced": "மேம்பட்ட"
},
"name": "கிராச்ஃபேட் [பீட்டா]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "காலகட்டத்தில் (எம்.எச்) மங்கிவிடும்",
"fade-out-duration": "காலத்தை மங்கச் செய்யுங்கள் (எம்.எச்)",
"fade-scaling": {
"label": "மங்கலான அளவிடுதல்",
"linear": "நேரியல்",
"logarithmic": "மடக்கை"
},
"seconds-before-end": "கிராச்ஃபேட் n வினாடிகள் முடிவுக்கு முன்"
},
"title": "கிராச்ஃபேட் விருப்பங்கள்"
}
}
},
"disable-autoplay": {
"description": "\"இடைநிறுத்தப்பட்ட\" பயன்முறையில் பாடல் தொடங்குகிறது",
"menu": {
"apply-once": "தொடக்கத்தில் மட்டுமே பொருந்தும்"
},
"name": "ஆட்டோபிளேவை முடக்கு"
},
"discord": {
"backend": {
"already-connected": "செயலில் இணைப்புடன் இணைக்க முயற்சித்தது",
"connected": "முரண்பாட்டுடன் இணைக்கப்பட்டுள்ளது",
"disconnected": "முரண்பாட்டிலிருந்து துண்டிக்கப்பட்டது"
},
"description": "பணக்கார இருப்பைக் கொண்டு நீங்கள் கேட்பதை உங்கள் நண்பர்களுக்குக் காட்டுங்கள்",
"menu": {
"auto-reconnect": "ஆட்டோ மீண்டும் இணைக்கவும்",
"clear-activity": "தெளிவான செயல்பாடு",
"clear-activity-after-timeout": "காலக்கெடுவுக்குப் பிறகு தெளிவான செயல்பாடு",
"connected": "இணைக்கப்பட்டுள்ளது",
"disconnected": "துண்டிக்கப்பட்டது",
"hide-duration-left": "காலம் மீதமுள்ளதை மறைக்கவும்",
"hide-github-button": "அறிவிலிமையம் இணைப்பு பொத்தானை மறைக்கவும்",
"play-on-youtube-music": "யூடியூப் இசையில் விளையாடுங்கள்",
"set-inactivity-timeout": "செயலற்ற நேரம் முடிந்தது"
},
"name": "முரண்பாடு பணக்கார இருப்பு",
"prompt": {
"set-inactivity-timeout": {
"label": "நொடிகளில் செயலற்ற நேரத்தை உள்ளிடவும்:",
"title": "செயலற்ற நேரம் முடிந்தது"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "சரி"
},
"message": "ஆர்க்! மன்னிப்பு, பதிவிறக்கம் தோல்வியுற்றது…",
"title": "பதிவிறக்கத்தில் பிழை!"
},
"start-download-playlist": {
"buttons": {
"ok": "சரி"
},
"detail": "({{playlistSize}} பாடல்கள்)",
"message": "பிளேலிச்ட்டைப் பதிவிறக்குகிறது {{playlistTitle}}",
"title": "பதிவிறக்கம் தொடங்கியது"
}
},
"feedback": {
"conversion-progress": "மாற்றம்: {{percent}}%",
"converting": "மாற்றுகிறது…",
"done": "முடிந்தது: {{filePath}}",
"download-info": "பதிவிறக்கம் {{artist}} - {{title}} [{{videoId}}}",
"download-progress": "பதிவிறக்கம்: {{percent}}%",
"downloading": "பதிவிறக்கம்…",
"downloading-counter": "பதிவிறக்கம் {{current}}/{{{total}}…",
"downloading-playlist": "பிளேலிச்ட்டைப் பதிவிறக்குதல் \"{{playlistTitle}}\" - {{playlistSize}} பாடல்கள் ({{playlistId}})",
"error-while-downloading": "பிழை \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "{{playlistFolder}}} ஏற்கனவே உள்ளது",
"getting-playlist-info": "பிளேலிச்ட் தகவலைப் பெறுதல்…",
"loading": "ஏற்றுகிறது…",
"playlist-has-only-one-song": "பிளேலிச்ட்டில் ஒரே ஒரு உருப்படி மட்டுமே உள்ளது, அதை நேரடியாக பதிவிறக்குகிறது",
"playlist-id-not-found": "பிளேலிச்ட் ஐடி எதுவும் கிடைக்கவில்லை",
"playlist-is-empty": "பிளேலிச்ட் காலியாக உள்ளது",
"playlist-is-mix-or-private": "பிளேலிச்ட் தகவலைப் பெறுவதில் பிழை: இது ஒரு தனிப்பட்ட அல்லது \"உங்களுக்காக கலப்பு\" பிளேலிச்ட் அல்ல என்பதை உறுதிப்படுத்திக் கொள்ளுங்கள்\n\n {{error}}",
"preparing-file": "கோப்பைத் தயாரித்தல்…",
"saving": "சேமிப்பு…",
"trying-to-get-playlist-id": "பிளேலிச்ட் ஐடியைப் பெற முயற்சிக்கிறது: {{playlistId}}}",
"video-id-not-found": "வீடியோ கிடைக்கவில்லை",
"writing-id3": "ஐடி 3 குறிச்சொற்களை எழுதுதல்…"
}
},
"description": "எம்பி 3 / மூல ஆடியோவை இடைமுகத்திலிருந்து நேரடியாக பதிவிறக்குகிறது",
"menu": {
"choose-download-folder": "பதிவிறக்க கோப்புறையைத் தேர்வுசெய்க",
"download-finish-settings": {
"label": "முடிவில் பதிவிறக்கவும்",
"prompt": {
"last-percent": "ஃச் சதவீதத்திற்குப் பிறகு",
"last-seconds": "கடைசி ஃச் விநாடிகள்",
"title": "எப்போது பதிவிறக்கம் செய்ய வேண்டும் என்பதை உள்ளமைக்கவும்"
},
"submenu": {
"advanced": "மேம்பட்ட",
"enabled": "இயக்கப்பட்டது",
"mode": "நேர முறை",
"percent": "விழுக்காடு",
"seconds": "நொடிகள்"
}
},
"download-playlist": "பிளேலிச்ட்டைப் பதிவிறக்கவும்",
"presets": "முன்னமைவுகள்",
"skip-existing": "இருக்கும் கோப்புகளைத் தவிர்க்கவும்"
},
"name": "பதிவிறக்குபவர்",
"renderer": {
"can-not-update-progress": "முன்னேற்றத்தை புதுப்பிக்க முடியாது"
},
"templates": {
"button": "பதிவிறக்கம்"
}
},
"equalizer": {
"description": "பிளேயருக்கு ஒரு சமநிலையைச் சேர்க்கிறது",
"menu": {
"presets": {
"label": "முன்னமைவுகள்",
"list": {
"bass-booster": "பாச் பூச்டர்"
}
}
},
"name": "சமநிலைப்படுத்தி"
},
"exponential-volume": {
"description": "தொகுதி ச்லைடர் அதிவேகமானது, எனவே குறைந்த தொகுதிகளைத் தேர்ந்தெடுப்பது எளிது.",
"name": "அதிவேக தொகுதி"
},
"in-app-menu": {
"description": "மெனு-பட்டியை ஒரு ஆடம்பரமான, இருண்ட அல்லது ஆல்பம்-வண்ண தோற்றத்தைக் கொடுங்கள்",
"menu": {
"hide-dom-window-controls": "டோம் சாளர கட்டுப்பாடுகளை மறைக்கவும்"
},
"name": "பயன்பாட்டில் பட்டியல்"
},
"lumiastream": {
"description": "லூமியா ச்ட்ரீம் ஆதரவை சேர்க்கிறது",
"name": "லூமியா ச்ட்ரீம் [பீட்டா]"
},
"lyrics-genius": {
"description": "பெரும்பாலான பாடல்களுக்கு பாடல் ஆதரவை சேர்க்கிறது",
"menu": {
"romanized-lyrics": "ரோமானிய பாடல்"
},
"name": "பாடல் சீனியச்",
"renderer": {
"fetched-lyrics": "சீனியசுக்கு பாடல் வரிகள்"
}
},
"music-together": {
"description": "ஒரு பிளேலிச்ட்டை மற்றவர்களுடன் பகிர்ந்து கொள்ளுங்கள். புரவலன் ஒரு பாடலை விளையாடும்போது, மற்றவர்கள் அனைவரும் ஒரே பாடலைக் கேட்பார்கள்",
"dialog": {
"enter-host": "புரவலன் ஐடியை உள்ளிடவும்"
},
"internal": {
"save": "சேமி",
"track-source": "ட்ராக் சோர்ச்",
"unknown-user": "தெரியாத பயனர்"
},
"menu": {
"click-to-copy-id": "புரவலன் ஐடியை நகலெடுக்கவும்",
"close": "ஒன்றாக இசையை மூடு",
"connected-users": "இணைக்கப்பட்ட பயனர்கள்",
"disconnect": "ஒன்றாக இசையை துண்டிக்கவும்",
"empty-user": "இணைக்கப்பட்ட பயனர்கள் இல்லை",
"host": "இசை ஒன்றாக புரவலன்",
"join": "ஒன்றாக இசையில் சேரவும்",
"permission": {
"all": "பிளேலிச்ட் மற்றும் பிளேயரைக் கட்டுப்படுத்த விருந்தினர்களை அனுமதிக்கவும்",
"host-only": "ஓச்டால் மட்டுமே பிளேலிச்ட் மற்றும் பிளேயரை கட்டுப்படுத்த முடியும்",
"playlist": "பிளேலிச்ட்டைக் கட்டுப்படுத்த விருந்தினர்களை அனுமதிக்கவும்"
},
"set-permission": "கட்டுப்பாட்டு அனுமதியை மாற்றவும்",
"status": {
"disconnected": "துண்டிக்கப்பட்டது",
"guest": "விருந்தினராக இணைக்கப்பட்டுள்ளது",
"host": "ஓச்டாக இணைக்கப்பட்டுள்ளது"
}
},
"name": "இசை ஒன்றாக [பீட்டா]",
"toast": {
"add-song-failed": "பாடல் சேர்க்கத் தவறிவிட்டது",
"closed": "இசை ஒன்றாக மூடப்பட்டது",
"disconnected": "இசை ஒன்றாக துண்டிக்கப்பட்டது",
"host-failed": "ஒன்றாக இசையை புரவலன் செய்யத் தவறிவிட்டது",
"id-copied": "இடைநிலைப்பலகைக்கு புரவலன் ஐடி நகலெடுக்கப்பட்டது",
"id-copy-failed": "புரவலன் ஐடியை இடைநிலைப்பலகைக்கு நகலெடுப்பதில் தோல்வி",
"join-failed": "ஒன்றாக இசையில் சேரத் தவறிவிட்டது",
"joined": "ஒன்றாக இசையில் சேர்ந்தார்",
"permission-changed": "இசை ஒன்றாக இசைவு \"{{permission}}\" என மாற்றப்பட்டது",
"remove-song-failed": "பாடலை அகற்றுவதில் தோல்வி",
"user-connected": "{{name}} ஒன்றாக இசையில் சேர்ந்தார்",
"user-disconnected": "{{name}}} இடது இசையை ஒன்றாக"
}
},
"navigation": {
"description": "உங்களுக்கு பிடித்த உலாவியைப் போலவே இடைமுகத்தில் நேரடியாக ஒருங்கிணைக்கப்பட்ட அடுத்த/பின் வழிசெலுத்தல் அம்புகள்",
"name": "வானோடல்"
},
"no-google-login": {
"description": "இடைமுகத்திலிருந்து Google உள்நுழைவு பொத்தான்கள் மற்றும் இணைப்புகளை அகற்று",
"name": "கூகிள் உள்நுழைவு இல்லை"
},
"notifications": {
"description": "ஒரு பாடல் இயக்கத் தொடங்கும் போது அறிவிப்பைக் காண்பி (விண்டோசில் ஊடாடும் அறிவிப்புகள் கிடைக்கின்றன)",
"menu": {
"interactive": "ஊடாடும் அறிவிப்புகள்",
"interactive-settings": {
"label": "ஊடாடும் அமைப்புகள்",
"submenu": {
"hide-button-text": "பொத்தான் உரையை மறைக்கவும்",
"refresh-on-play-pause": "விளையாட்டு/இடைநிறுத்தத்தில் புதுப்பிக்கவும்",
"tray-controls": "தட்டு சொடுக்கு செய்யவும்/மூடு"
}
},
"priority": "அறிவிப்பு முன்னுரிமை",
"toast-style": "சிற்றுண்டி நடை",
"unpause-notification": "பொருத்தமற்ற அறிவிப்பைக் காட்டு"
},
"name": "அறிவிப்புகள்"
},
"picture-in-picture": {
"description": "பயன்பாட்டை பட-பட பயன்முறைக்கு மாற்ற அனுமதிக்கிறது",
"menu": {
"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": "ச்க்ரோப்ளிங் ஆதரவைச் சேர்க்கவும் (முதலியன.",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm உடன் அங்கீகரிக்கத் தவறிவிட்டது\n அடுத்த மறுதொடக்கம் வரை பாப்அப்பை மறைக்கவும்.",
"title": "ஏற்பு தோல்வியடைந்தது"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm பநிஇ அமைப்புகள்"
},
"listenbrainz": {
"token": "WeskBrainz பயனர் கிள்ளாக்கை உள்ளிடவும்"
},
"scrobble-other-media": "மற்ற ஊடகங்களை வெல்லுங்கள்"
},
"name": "ச்க்ரோபிளர்",
"prompt": {
"lastfm": {
"api-key": "Last.fm பநிஇ key",
"api-secret": "Last.fm பநிஇ மறைபொருள்"
},
"listenbrainz": {
"token": {
"label": "உங்கள் கயிட் பிரைன்ச் பயனர் கிள்ளாக்கை உள்ளிடவும்:",
"title": "கேளுங்கள் பிரெய்ன்ச் கிள்ளாக்கு"
}
}
}
},
"shortcuts": {
"description": "பிளேபேக்கிற்கான உலகளாவிய ஆட்கீசை அமைக்க அனுமதிக்கிறது (நாடகம்/இடைநிறுத்தம்/அடுத்த/முந்தைய) மீடியா விசைகளை மீறுவதன் மூலம் மீடியா ஓ.எச்.டி.",
"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": "ம n னங்களைத் தவிர்க்கவும்"
},
"sponsorblock": {
"description": "அறிமுகம்/அவுட்ரோ போன்ற இசை அல்லாத பகுதிகள் அல்லது பாடல் இசைக்காத இசை வீடியோக்களின் பகுதிகளை தானாகவே தவிர்க்கிறது",
"name": "ஒப்புரவாளர் தொகுதி"
},
"synced-lyrics": {
"description": "எல்.ஆர்.சி.எல்.ஐ.பி போன்ற வழங்குநர்களைப் பயன்படுத்தி பாடல்களுக்கு ஒத்திசைக்கப்பட்ட பாடல்களை வழங்குகிறது.",
"errors": {
"fetch": "The பாடல் வரிகளைப் பெறும்போது பிழை ஏற்பட்டது.\n தயவுசெய்து பின்னர் மீண்டும் முயற்சிக்கவும்.",
"not-found": "Ling இந்த பாடலுக்கு வரிகள் எதுவும் கிடைக்கவில்லை."
},
"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": "உங்கள் சாளரங்கள் பணிப்பட்டியிலிருந்து பிளேபேக்கைக் கட்டுப்படுத்தவும்",
"name": "பணிப்பட்டு மீடியா கட்டுப்பாடு"
},
"touchbar": {
"description": "MACOS பயனர்களுக்கான டச்ச்பார் விட்செட்டை சேர்க்கிறது",
"name": "டக்பார்"
},
"tuna-obs": {
"description": "OBS இன் சொருகி டுனாவுடன் ஒருங்கிணைப்பு",
"name": "டுனா குறிப்பு"
},
"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

@ -39,29 +39,29 @@
"clearing-cache-after-20s": "กำลังล้างแคชแอป" "clearing-cache-after-20s": "กำลังล้างแคชแอป"
}, },
"window": { "window": {
"tried-to-render-offscreen": "หน้าต่างพยายามแสดงผลเกินขนาดหน้าจอ windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}" "tried-to-render-offscreen": "หน้าต่างพยายามแสดงผลเกินขนาดหน้าจอ ขนาดหน้าต่าง={{windowSize}}, ขนาดหน้าจอ={{displaySize}}, ตำแหน่ง={{position}}"
} }
}, },
"dialog": { "dialog": {
"hide-menu-enabled": { "hide-menu-enabled": {
"detail": "เมนูถูกซ่อนไว้ กด'Alt' เพื่อแสดงเมนู (หรือ 'Escape' หากอยู่ในเมนูแอป)", "detail": "เมนูถูกซ่อนไว้ กด'Alt' เพื่อแสดงเมนู (หรือ 'Escape' หากกำลังใช้เมนูบนแอป)",
"message": "การซ่อนเมนูถูกเปิดใช้งาน", "message": "การซ่อนเมนูเปิดใช้งานอยู่",
"title": "เปิดใช้งานการซ่อนเมนู" "title": "เปิดใช้งานการซ่อนเมนู"
}, },
"need-to-restart": { "need-to-restart": {
"buttons": { "buttons": {
"later": "ภายหลัง", "later": "รีสตาร์ตภายหลัง",
"restart-now": "รีสตาร์ตอนนี้" "restart-now": "รีสตาร์ตอนนี้"
}, },
"detail": "\"{{pluginName}}\" ปลั๊กอินต้องการการรีสตาร์เพื่อแสดงผล", "detail": "ปลั๊กอิน \"{{pluginName}}\" ต้องการการรีสตาร์เพื่อจะทำงานได้",
"message": "\"{{pluginName}}\" ต้องการรีสตาร์", "message": "\"{{pluginName}}\" ต้องการรีสตาร์",
"title": "แนะนำให้รีสตาร์" "title": "แนะนำให้รีสตาร์"
}, },
"unresponsive": { "unresponsive": {
"buttons": { "buttons": {
"quit": "ออก", "quit": "ออก",
"relaunch": "เปิดใหม่", "relaunch": "ปิดแล้วเปิดใหม่",
"wait": "รอซักครู่" "wait": "รอให้ตอบสนอง"
}, },
"detail": "ขออภัยในความไม่สะดวก! โปรดเลือกสิ่งที่ต้องการจะทำ:", "detail": "ขออภัยในความไม่สะดวก! โปรดเลือกสิ่งที่ต้องการจะทำ:",
"message": "แอปพลิเคชันไม่ตอบสนอง", "message": "แอปพลิเคชันไม่ตอบสนอง",
@ -73,7 +73,7 @@
"download": "ดาวน์โหลด", "download": "ดาวน์โหลด",
"ok": "ตกลง" "ok": "ตกลง"
}, },
"detail": "มีเวอร์ชันใหม่ให้ดาวน์โหลดแล้วที่ {{downloadLink}}", "detail": "มีเวอร์ชันใหม่ให้ใช้งานได้สามารถดาวน์โหลดได้ที่ {{downloadLink}}",
"message": "มีเวอร์ชันใหม่ให้ใช้งานแล้ว", "message": "มีเวอร์ชันใหม่ให้ใช้งานแล้ว",
"title": "อัปเดตพร้อมใช้งาน" "title": "อัปเดตพร้อมใช้งาน"
} }
@ -87,7 +87,7 @@
"go-back": "ก่อนหน้า", "go-back": "ก่อนหน้า",
"go-forward": "ถัดไป", "go-forward": "ถัดไป",
"quit": "ออก", "quit": "ออก",
"restart": "รีสตาร์แอป" "restart": "รีสตาร์แอป"
} }
}, },
"options": { "options": {
@ -96,23 +96,23 @@
"advanced-options": { "advanced-options": {
"label": "ตัวเลือกขั้นสูง", "label": "ตัวเลือกขั้นสูง",
"submenu": { "submenu": {
"auto-reset-app-cache": "รีเซตแอปแคชเมื่อเริ่มแอป", "auto-reset-app-cache": "รีเซตแคชของแอปเมื่อเริ่มแอป",
"disable-hardware-acceleration": "ปิดการใช้งานตัวเร่งประสิทธิภาพด้วยฮาร์ดแวร์", "disable-hardware-acceleration": "ปิดการใช้งานตัวเร่งประสิทธิภาพด้วยฮาร์ดแวร์",
"edit-config-json": "แก้ไข config.json", "edit-config-json": "แก้ไข config.json",
"override-user-agent": "แทนที่ User-Agent", "override-user-agent": "แทนที่ User-Agent",
"restart-on-config-changes": "รีสตาร์เมื่อมีการเปลี่ยนแปลงคอนฟิก", "restart-on-config-changes": "รีสตาร์เมื่อมีการเปลี่ยนแปลงคอนฟิก",
"set-proxy": { "set-proxy": {
"label": "ตั้งค่าพร็อกซี่", "label": "ตั้งค่าพร็อกซี่",
"prompt": { "prompt": {
"label": "ใส่ที่อยู่พร็อกซี่: (ปล่อยให้ว่างเพื่อปิดใช้งาน)", "label": "ใส่ที่อยู่ของพร็อกซี่: (เว้นว่างเพื่อปิดใช้งาน)",
"placeholder": "ตัวอย่าง: SOCKS5://127.0.0.1:9999", "placeholder": "ตัวอย่าง: SOCKS5://127.0.0.1:9999",
"title": "ตั้งค่าพร็อกซี่" "title": "ตั้งค่าพร็อกซี่"
} }
}, },
"toggle-dev-tools": "เปิด-ปิด DevTools" "toggle-dev-tools": "เปิด/ปิดเครื่องมือสำหรับนักพัฒนา"
} }
}, },
"always-on-top": "อยู่ด้านบนตลอดเวลา", "always-on-top": "อยู่ด้านบนหน้าต่างอื่นตลอดเวลา",
"auto-update": "อัปเดตอัตโนมัติ", "auto-update": "อัปเดตอัตโนมัติ",
"hide-menu": { "hide-menu": {
"dialog": { "dialog": {
@ -123,17 +123,17 @@
}, },
"language": { "language": {
"dialog": { "dialog": {
"message": "ภาษาจะเปลี่ยนหลังจากทำการรีสตาร์", "message": "ภาษาจะเปลี่ยนหลังจากทำการรีสตาร์",
"title": "ภาษาถูกเปลี่ยนแล้ว" "title": "ภาษาถูกเปลี่ยนแล้ว"
}, },
"label": "ภาษา", "label": "ภาษา",
"submenu": { "submenu": {
"to-help-translate": "ต้องการช่วยแปล? คลิกที่นี่" "to-help-translate": "ต้องการช่วยแปลภาษา? คลิกที่นี่"
} }
}, },
"resume-on-start": "เล่นเพลงล่าสุดต่อ เมื่อแอปเริ่มต้น", "resume-on-start": "เล่นเพลงที่เล่นล่าสุดต่อ เมื่อเปิดแอป",
"single-instance-lock": "ล็อกการทำงานเพียงรายการเดียว", "single-instance-lock": "ล็อกไม่ให้เปิดซำ้ซ้อน",
"start-at-login": "เริ่มต้นที่การเข้าสู่ระบบ", "start-at-login": "เริ่มต้นเมื่อเข้าสู่ระบบ",
"starting-page": { "starting-page": {
"label": "หน้าเริ่มต้น", "label": "หน้าเริ่มต้น",
"unset": "ยกเลิกการตั้งค่า" "unset": "ยกเลิกการตั้งค่า"
@ -148,7 +148,7 @@
} }
}, },
"visual-tweaks": { "visual-tweaks": {
"label": "การปรับแต่งหน้าตาแอป", "label": "ปรับแต่งหน้าตาแอป",
"submenu": { "submenu": {
"like-buttons": { "like-buttons": {
"default": "ค่าเริ่มต้น", "default": "ค่าเริ่มต้น",
@ -169,7 +169,7 @@
"label": "ธีม", "label": "ธีม",
"submenu": { "submenu": {
"import-css-file": "นำเข้าไฟล์ CSS ที่กำหนดเอง", "import-css-file": "นำเข้าไฟล์ CSS ที่กำหนดเอง",
"no-theme": "ไม่มีธีม" "no-theme": "ไม่ใช้ธีม"
} }
} }
} }
@ -187,28 +187,28 @@
"force-reload": "บังคับโหลดใหม่", "force-reload": "บังคับโหลดใหม่",
"reload": "โหลดใหม่", "reload": "โหลดใหม่",
"reset-zoom": "ขนาดจริง", "reset-zoom": "ขนาดจริง",
"toggle-fullscreen": "สลับเต็มหน้าจอ", "toggle-fullscreen": "เปิด/ปิดโหมดเต็มหน้าจอ",
"zoom-in": "ซูมเข้า", "zoom-in": "ซูมเข้า",
"zoom-out": "ซูมออก" "zoom-out": "ซูมออก"
} }
} }
}, },
"tray": { "tray": {
"next": "่อไป", "next": "่อไป",
"play-pause": "เล่น/พัก", "play-pause": "เล่น/หยุดชั่วคราว",
"previous": "ก่อนหน้า", "previous": "ก่อนหน้า",
"quit": "ออก", "quit": "ออก",
"restart": "รีสตาร์แอป", "restart": "รีสตาร์แอป",
"show": "แสดงหน้าต่าง", "show": "แสดงหน้าต่าง",
"tooltip": { "tooltip": {
"default": "ยูทุปมิวสิค", "default": "YouTube Music",
"with-song-info": "ยูทูปมิวสิค: {{artist}} - {{title}}" "with-song-info": "YouTube Music: {{artist}} - {{title}}"
} }
} }
}, },
"plugins": { "plugins": {
"ad-speedup": { "ad-speedup": {
"description": "หากมีการเล่นโฆษณา เสียงจะถูกปิดและตั้งค่าความเร็วในการเล่นเป็น 16x", "description": "หากมีโฆษณาเล่นขึ้น เสียงจะถูกปิดและตั้งความเร็วในการเล่นเป็น 16 เท่า",
"name": "เพิ่มความเร็วโฆษณา" "name": "เพิ่มความเร็วโฆษณา"
}, },
"adblocker": { "adblocker": {
@ -219,7 +219,7 @@
"name": "ตัวบล็อกโฆษณา" "name": "ตัวบล็อกโฆษณา"
}, },
"album-actions": { "album-actions": {
"description": "เพิ่ม ยกเลิกไม่ชอบ, ไม่ชอบ, 'ถูกใจ', และ 'ยกเลิกถูกใจ' เพื่อให้สามารถใช้งานกับเพลงทั้งหมดในรายการเพลงหรืออัลบั้ม", "description": "เพิ่ม ยกเลิกไม่ชอบ, ไม่ชอบ, ถูกใจ, และ ยกเลิกถูกใจ ที่มีผลกับเพลงทั้งหมดในรายการเพลงหรืออัลบั้ม",
"name": "การกระทำที่เกี่ยวกับอัลบั้ม" "name": "การกระทำที่เกี่ยวกับอัลบั้ม"
}, },
"album-color-theme": { "album-color-theme": {
@ -228,14 +228,14 @@
"color-mix-ratio": { "color-mix-ratio": {
"label": "สัดส่วนการผสมสี", "label": "สัดส่วนการผสมสี",
"submenu": { "submenu": {
"percent": "{{ratio}}เปอร์เซ็น" "percent": "{{ratio}}%"
} }
} }
}, },
"name": "ธีมสีของอัลบั้ม" "name": "ธีมสีของอัลบั้ม"
}, },
"ambient-mode": { "ambient-mode": {
"description": "เอฟเฟกต์แสงจะใช้สีอ่อนๆจากวีดิโอมาเป็พื้นหลังสกรีน", "description": "เอฟเฟกต์แสงที่ดึงสีอ่อนๆจากวีดิโอมาบนพื้นหลังแอป",
"menu": { "menu": {
"blur-amount": { "blur-amount": {
"label": "ระดับความเบลอ", "label": "ระดับความเบลอ",
@ -268,9 +268,9 @@
} }
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "การเปลี่ยนแบบสมูท", "label": "ความเรียบการเปลี่ยน",
"submenu": { "submenu": {
"during": "ระหว่าง {{interpolationTime}} วินาที" "during": "ในระยะเวลา {{interpolationTime}} วินาที"
} }
}, },
"use-fullscreen": { "use-fullscreen": {
@ -279,6 +279,13 @@
}, },
"name": "โหมดสภาพแวดล้อม" "name": "โหมดสภาพแวดล้อม"
}, },
"amuse": {
"description": "เพิ่มการรองรับ Youtube Music สำหรับ Widget Amuse Now Playing ของ 6K Labs",
"name": "Amuse",
"response": {
"query": "API Server ของ Amuse ทำงานอยู่ ส่ง GET ไปที่ /query เพื่อขอข้อมูลเกี่ยวกับเพลง"
}
},
"api-server": { "api-server": {
"description": "เพิ่มเซิร์ฟเวอร์ API เพื่อควบคุมการเล่น", "description": "เพิ่มเซิร์ฟเวอร์ API เพื่อควบคุมการเล่น",
"dialog": { "dialog": {
@ -287,7 +294,38 @@
"allow": "อนุญาต", "allow": "อนุญาต",
"deny": "ปฏิเสธ" "deny": "ปฏิเสธ"
}, },
"message": "อนุญาตให้ {{ID}} ({{origin}}) เข้าถึง API หรือไม่?" "message": "อนุญาตให้ {{ID}} ({{origin}}) เข้าถึง API หรือไม่?",
"title": "คำขอลงชื่อเข้าใช้งาน API"
}
},
"menu": {
"auth-strategy": {
"label": "วิธีการลงชื่อเข้าใช้งาน",
"submenu": {
"auth-at-first": {
"label": "ลงชื่อเข้าใช้งานในคำขอแรก"
},
"none": {
"label": "ไม่ต้องลงชื่อเข้าใช้งาน"
}
}
},
"hostname": {
"label": "ชื่อโฮสต์ (Hostname)"
},
"port": {
"label": "พอร์ต (Port) ของ Server"
}
},
"name": "เซิร์ฟเวอร์ API [เบต้า]",
"prompt": {
"hostname": {
"label": "ใส่ชื่อโฮสต์ (Hostname) เช่น 0.0.0.0 สำหรับเซิร์ฟเวอร์ API:",
"title": "ชื่อโฮสต์ (Hostname)"
},
"port": {
"label": "ใส่พอร์ต (Port) ในการเข้าถึงเซิร์ฟเวอร์ API:",
"title": "พอร์ต (Port) ของ Server"
} }
} }
}, },
@ -300,11 +338,11 @@
"name": "เบลอแถบนำทาง" "name": "เบลอแถบนำทาง"
}, },
"bypass-age-restrictions": { "bypass-age-restrictions": {
"description": "ข้ามการตรวจสอบอายุของยูทูป", "description": "ข้ามการตรวจสอบอายุของ YouTube",
"name": "ข้ามข้อจำกัดอายุ" "name": "ข้ามข้อจำกัดอายุ"
}, },
"captions-selector": { "captions-selector": {
"description": "ตัวเลือกคำบรรยายสำหรับเพลงในYoutube Music", "description": "ตัวเลือกคำบรรยายสำหรับเพลงใน YouTube Music",
"menu": { "menu": {
"autoload": "เลือกคำบรรยายที่ใช้ครั้งล่าสุดโดยอัตโนมัติ", "autoload": "เลือกคำบรรยายที่ใช้ครั้งล่าสุดโดยอัตโนมัติ",
"disable-captions": "ไม่มีคำบรรยายเป็นค่าเริ่มต้น" "disable-captions": "ไม่มีคำบรรยายเป็นค่าเริ่มต้น"
@ -348,19 +386,19 @@
} }
}, },
"disable-autoplay": { "disable-autoplay": {
"description": "เริ่มเพลงในโหมดหยุด", "description": "เริ่มเพลงในโหมดหยุดชั่วคราว",
"menu": { "menu": {
"apply-once": "ใช้เฉพาะเมื่อเริ่มต้น" "apply-once": "ใช้เฉพาะเมื่อเริ่มต้นแอป"
}, },
"name": "ปิดใช้งานการเล่นอัตโนมัติ" "name": "ปิดใช้งานการเล่นอัตโนมัติ"
}, },
"discord": { "discord": {
"backend": { "backend": {
"already-connected": "พยายามเชื่อมต่อกับการเชื่อมต่อที่ทำงานอยู่", "already-connected": "กำลังพยายามเชื่อมต่อด้วยการเชื่อมต่อที่มีอยู่",
"connected": "เชื่อมต่อกับดิสคอร์ดแล้ว", "connected": "เชื่อมต่อกับดิสคอร์ดแล้ว",
"disconnected": "ตัดการเชื่อมต่อออกจากดิสคอร์ด" "disconnected": "ไม่มีการเชื่อมต่อกับดิสคอร์ดอยู่"
}, },
"description": "แสดงให้เพื่อนเห็นว่าคุณกำลังฟังอะไรด้วย Rich Presence", "description": "แสดงให้เพื่อนเห็นว่าคุณกำลังฟังอะไรด้วย Rich Presence บนดิสคอร์ด",
"menu": { "menu": {
"auto-reconnect": "เชื่อมต่อใหม่โดยอัตโนมัติ", "auto-reconnect": "เชื่อมต่อใหม่โดยอัตโนมัติ",
"clear-activity": "ล้างกิจกรรม", "clear-activity": "ล้างกิจกรรม",
@ -369,10 +407,10 @@
"disconnected": "ตัดการเชื่อมต่อ", "disconnected": "ตัดการเชื่อมต่อ",
"hide-duration-left": "ซ่อนระยะเวลาที่เหลือ", "hide-duration-left": "ซ่อนระยะเวลาที่เหลือ",
"hide-github-button": "ซ่อนปุ่มลิงก์ GitHub", "hide-github-button": "ซ่อนปุ่มลิงก์ GitHub",
"play-on-youtube-music": "เล่นบนยูทูปมิวสุค", "play-on-youtube-music": "เล่นบน YouTube Music",
"set-inactivity-timeout": "ตั้งระยะเวลาไม่มีกิจกรรม" "set-inactivity-timeout": "ตั้งระยะเวลาไม่มีกิจกรรม"
}, },
"name": "Discord Rich Presence", "name": "แสดงกิจกรรมบนดิสคอร์ด",
"prompt": { "prompt": {
"set-inactivity-timeout": { "set-inactivity-timeout": {
"label": "ป้อนระยะเวลาไม่มีกิจกรรมเป็นวินาที:", "label": "ป้อนระยะเวลาไม่มีกิจกรรมเป็นวินาที:",
@ -426,6 +464,21 @@
"description": "ดาวน์โหลด MP3 / เสียงต้นฉบับโดยตรงจากอินเทอร์เฟซ", "description": "ดาวน์โหลด MP3 / เสียงต้นฉบับโดยตรงจากอินเทอร์เฟซ",
"menu": { "menu": {
"choose-download-folder": "เลือกโฟลเดอร์ดาวน์โหลด", "choose-download-folder": "เลือกโฟลเดอร์ดาวน์โหลด",
"download-finish-settings": {
"label": "ดาวน์โหลดเมื่อเล่นเสร็จ",
"prompt": {
"last-percent": "หลังจาก x เปอร์เซ็นต์",
"last-seconds": "x วินาทีล่าสุด",
"title": "ตั่งค่าเวลาที่จะดาวน์โหลด"
},
"submenu": {
"advanced": "การตั้งค่าขั้นสูง",
"enabled": "เปิดใช้งาน",
"mode": "โหมดเวลา",
"percent": "โหมดเปอร์เซ็นต์",
"seconds": "โหมดวินาที"
}
},
"download-playlist": "ดาวน์โหลดเพลย์ลิสต์", "download-playlist": "ดาวน์โหลดเพลย์ลิสต์",
"presets": "พรีเซ็ต", "presets": "พรีเซ็ต",
"skip-existing": "ข้ามไฟล์ที่มีอยู่แล้ว" "skip-existing": "ข้ามไฟล์ที่มีอยู่แล้ว"
@ -438,12 +491,24 @@
"button": "ดาวน์โหลด" "button": "ดาวน์โหลด"
} }
}, },
"equalizer": {
"description": "เพิ่มอีควอไลเซอร์ให้ที่เล่นเพลง",
"menu": {
"presets": {
"label": "การตั้งค่าล่วงหน้า",
"list": {
"bass-booster": "เพิ่มเบส"
}
}
},
"name": "อีควอไลเซอร์"
},
"exponential-volume": { "exponential-volume": {
"description": "ทำให้ตัวเลือกความดังมีลักษณะเอ็กซ์โปเนนเชียล เพื่อให้ง่ายต่อการเลือกระดับความดังที่ต่ำลง", "description": "ทำให้ตัวเลือกความดังมีลักษณะเอ็กซ์โปเนนเชียล เพื่อให้ง่ายต่อการเลือกระดับความดังที่ต่ำลง",
"name": "ระดับเสียงแบบเอ็กซโปเนนเชียล" "name": "ระดับเสียงแบบเอ็กซโปเนนเชียล"
}, },
"in-app-menu": { "in-app-menu": {
"description": "ให้เมนูบาร์ดูทันสมัย มืดหรือเป็นสีของอัลบั้มอย่างน่าสนใจ", "description": "ให้เแถบเมนูดูทันสมัย มืดหรือเป็นสีของอัลบั้มอย่างน่าสนใจ",
"menu": { "menu": {
"hide-dom-window-controls": "ซ่อนตัวควบคุมหน้าต่าง DOM" "hide-dom-window-controls": "ซ่อนตัวควบคุมหน้าต่าง DOM"
}, },
@ -530,6 +595,7 @@
} }
}, },
"priority": "ลำดับความสำคัญของการแจ้งเตือน", "priority": "ลำดับความสำคัญของการแจ้งเตือน",
"toast-style": "แบบไม่ถาวร",
"unpause-notification": "แสดงการแจ้งเตือนเมื่อหยุดพัก" "unpause-notification": "แสดงการแจ้งเตือนเมื่อหยุดพัก"
}, },
"name": "การแจ้งเตือน" "name": "การแจ้งเตือน"
@ -549,8 +615,222 @@
} }
}, },
"save-window-position": "บันทึกตำแหน่งหน้าต่าง", "save-window-position": "บันทึกตำแหน่งหน้าต่าง",
"save-window-size": "บันทึกขนาดหน้าต่าง" "save-window-size": "บันทึกขนาดหน้าต่าง",
"use-native-pip": "ใช้โหมดภาพซ้อนภาพของเบราเซอร์"
},
"name": "โหมดภาพซ้อนภาพ",
"templates": {
"button": "เปิดโหมดภาพซ้อนภาพ"
} }
},
"playback-speed": {
"description": "ฟังเพลงได้ทั้งช้าและเร็ว เพิ่มที่เลื่อนปรับความเร็วของเพลง",
"name": "ความเร็วเพลง",
"templates": {
"button": "ความเร็ว"
}
},
"precise-volume": {
"description": "ควบคุมระดับเสียงได้อย่างแม่นยำด้วยที่เลื่อนเมาส์หรือปุ่มลัด พร้อมด้วยหน้าจอแสดงข้อมูลและขั้นระดับเสียงที่ปรับแต่งได้",
"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": "รองรับการบันทึกการเล่นเพลง (เช่น last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "เกิดปัญหาระหว่างเข้าใช้งาน Last.fm\nซ่อนข้อความนี้จนการรีสตาร์ตครั้งถัดไป",
"title": "เกิดปัญหาในการเข้าใช้งาน"
}
}
},
"menu": {
"lastfm": {
"api-settings": "การตั้งค่า API Last.fm"
},
"listenbrainz": {
"token": "ใส่ user token ของ ListenBrainz"
},
"scrobble-other-media": "บันทึกการเล่นสื่ออื่นๆ"
},
"name": "บันทึกการเล่น (Scrobbler)",
"prompt": {
"lastfm": {
"api-key": "API Key ของ Last.fm",
"api-secret": "API secret ของ Last.fm"
},
"listenbrainz": {
"token": {
"label": "ใส่ user token ListenBrainz ของคุณ:",
"title": "token ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "อนุญาตให้ตั้งปุ่มลัดทั่วระบบสำหรับการเล่น (เล่น/หยุดชั่วคราว/ถัดไป/ก่อนหน้า) และปิดการแสดงผลสื่อโดยทับปุ่มควบคุมสื่อ เปิด Ctrl/CMD + F เพื่อค้นหา เปิดการใช้งานการควบคุมเพลงผ่าน MPRIS สำหรับ Linux และปุ่มลัดที่กำหนดเองได้สำหรับผู้ใช้ขั้นสูง",
"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": "ข้ามช่วงที่ไม่ใช่เพลงเช่น intro/outro หรือ ช่วงที่ไม่มีเพลงเล่นใน mv โดยอัตโนมัติ",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "ให้เนื้อเพลงที่ตรงกับเวลาของเพลง ผ่านผู้ให้บริการเช่น LRClib",
"errors": {
"fetch": "⚠️\tเกิดปัญหาในการดึงเนื้อเพลง\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 ของ Windows",
"name": "ควบคุมสื่อผ่าน Taskbar"
},
"touchbar": {
"description": "เพิ่ม Widget บน TouchBar สำหรับผู้ใช้ macOS",
"name": "TouchBar"
},
"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,13 @@
}, },
"name": "Ambiyans Modu" "name": "Ambiyans Modu"
}, },
"amuse": {
"description": "6K Labs'ın Amuse oynatma widget'ı için YouTube Music desteği ekler",
"name": "Amuse",
"response": {
"query": "Amuse API sunucusu çalışıyor. Şarkı bilgilerini almak için GET /query kullanabilirsiniz."
}
},
"api-server": { "api-server": {
"description": "APİ ekle ve oynatıcıyı kontrol et", "description": "APİ ekle ve oynatıcıyı kontrol et",
"dialog": { "dialog": {
@ -484,6 +491,18 @@
"button": "İndir" "button": "İndir"
} }
}, },
"equalizer": {
"description": "Oynatıcıya ekolayzer desteği ekler",
"menu": {
"presets": {
"label": "Ön Ayarlar",
"list": {
"bass-booster": "Bass güçlendirici"
}
}
},
"name": "Ekolayzer"
},
"exponential-volume": { "exponential-volume": {
"description": "Ses seviyesi kaydırıcısını üstel hale getirir, böylece daha düşük ses seviyelerini seçmek daha kolay olur.", "description": "Ses seviyesi kaydırıcısını üstel hale getirir, böylece daha düşük ses seviyelerini seçmek daha kolay olur.",
"name": "Üstel Ses Seviyesi" "name": "Üstel Ses Seviyesi"
@ -714,8 +733,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "LRClib gibi sağlayıcıları kullanarak şarkılara senkronize şarkı sözleri sağlar.", "description": "LRClib gibi sağlayıcıları kullanarak şarkılara senkronize şarkı sözleri sağlar.",
"errors": { "errors": {
"fetch": "⚠️ - Şarkı sözleri getirilirken bir hata oluştu. Lütfen daha sonra tekrar deneyin.", "fetch": "⚠️ \tŞarkı sözleri alınırken bir hata oluştu.\n\tLütfen daha sonra tekrar deneyin.",
"not-found": "⚠️ - Bu şarkı için şarkı sözü bulunamadı." "not-found": "⚠️ Bu şarkı için şarkı sözleri bulunamadı."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -725,6 +744,10 @@
"line-effect": { "line-effect": {
"label": "Çizgi etkisi", "label": "Çizgi etkisi",
"submenu": { "submenu": {
"fancy": {
"label": "Süslü",
"tooltip": "Mevcut satırda büyük, uygulama benzeri efektler kullan"
},
"focus": { "focus": {
"label": "odak", "label": "odak",
"tooltip": "Yalnızca geçerli satırı beyaz yapın" "tooltip": "Yalnızca geçerli satırı beyaz yapın"

View File

@ -279,6 +279,13 @@
}, },
"name": "Режим навколишнього середовища" "name": "Режим навколишнього середовища"
}, },
"amuse": {
"description": "Додає підтримку YouTube Music для віджета Amuse now playing від 6K Labs",
"name": "Amuse",
"response": {
"query": "Сервер Amuse API запущено. Запит GET /query для отримання інформації про пісню."
}
},
"api-server": { "api-server": {
"description": "Додає API сервер для контролю плеєра", "description": "Додає API сервер для контролю плеєра",
"dialog": { "dialog": {
@ -484,6 +491,18 @@
"button": "Завантажити" "button": "Завантажити"
} }
}, },
"equalizer": {
"description": "Додає еквалайзер до програвача",
"menu": {
"presets": {
"label": "Пресети",
"list": {
"bass-booster": "Підсилювач басів"
}
}
},
"name": "Еквалайзер"
},
"exponential-volume": { "exponential-volume": {
"description": "Робить регулятор гучності експоненціальним, що полегшує вибір тихих рівнів гучності.", "description": "Робить регулятор гучності експоненціальним, що полегшує вибір тихих рівнів гучності.",
"name": "Експоненціальна гучність" "name": "Експоненціальна гучність"
@ -714,8 +733,8 @@
"synced-lyrics": { "synced-lyrics": {
"description": "Додає синхронізовані тексти до пісень використовуючи провайдери, такі як LRClib.", "description": "Додає синхронізовані тексти до пісень використовуючи провайдери, такі як LRClib.",
"errors": { "errors": {
"fetch": "⚠️ - При завантаженні тексту сталась помилка. Спробуйте ще раз пізніше.", "fetch": "⚠️ - При завантаженні слів пісні сталась помилка. Спробуйте пізніше.",
"not-found": "⚠️ - До цієї пісні текст не знайдено." "not-found": "⚠️ До цієї пісні текст не знайдено."
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {
@ -725,6 +744,10 @@
"line-effect": { "line-effect": {
"label": "Лінійний ефект", "label": "Лінійний ефект",
"submenu": { "submenu": {
"fancy": {
"label": "Fancy",
"tooltip": "Використовуйте великі, додаткоподібні ефекти на поточному рядку"
},
"focus": { "focus": {
"label": "Зосереджитись", "label": "Зосереджитись",
"tooltip": "Зробити білим лише поточний рядок" "tooltip": "Зробити білим лише поточний рядок"

View File

@ -279,6 +279,12 @@
}, },
"name": "Chế độ Môi trường xung quanh" "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": { "api-server": {
"description": "Thêm máy chủ API để điều khiển trình phát", "description": "Thêm máy chủ API để điều khiển trình phát",
"dialog": { "dialog": {
@ -299,7 +305,7 @@
"label": "Xác thực ngay yêu cầu đầu tiên" "label": "Xác thực ngay yêu cầu đầu tiên"
}, },
"none": { "none": {
"label": "Không/Chưa xác thực (Need context)" "label": "Không xác thực"
} }
} }
}, },

View File

@ -199,11 +199,7 @@
"previous": "上一首", "previous": "上一首",
"quit": "退出", "quit": "退出",
"restart": "重启应用", "restart": "重启应用",
"show": "显示窗口", "show": "显示窗口"
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
} }
}, },
"plugins": { "plugins": {
@ -279,6 +275,12 @@
}, },
"name": "沉浸模式" "name": "沉浸模式"
}, },
"amuse": {
"description": "为 6K Labs 的 Amuse 正在播放小部件添加 YouTube Music 支持",
"response": {
"query": "Amuse API服务器已在运行。使用 /query 以获取歌曲信息。"
}
},
"api-server": { "api-server": {
"description": "添加一个 API 服务器来控制播放器", "description": "添加一个 API 服务器来控制播放器",
"dialog": { "dialog": {
@ -727,7 +729,7 @@
"description": "透过 LRClib 等服务提供滚动歌词显示。", "description": "透过 LRClib 等服务提供滚动歌词显示。",
"errors": { "errors": {
"fetch": "⚠️ - 获取歌词时发生错误。请稍后再试。", "fetch": "⚠️ - 获取歌词时发生错误。请稍后再试。",
"not-found": "⚠️ - 未找到此歌曲的歌词。" "not-found": "⚠️ 未找到此歌曲的歌词。"
}, },
"menu": { "menu": {
"default-text-string": { "default-text-string": {

View File

@ -683,6 +683,7 @@
"listenbrainz": { "listenbrainz": {
"token": "輸入 ListenBrainz 使用者憑證" "token": "輸入 ListenBrainz 使用者憑證"
}, },
"scrobble-alternative-title": "使用另類歌曲標題",
"scrobble-other-media": "紀錄其他媒體文件" "scrobble-other-media": "紀錄其他媒體文件"
}, },
"name": "Scrobbler", "name": "Scrobbler",

View File

@ -134,14 +134,6 @@ if (is.linux()) {
// Overrides WM_CLASS for X11 to correspond to icon filename // Overrides WM_CLASS for X11 to correspond to icon filename
app.setName('com.github.th_ch.youtube_music'); 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 // Stops chromium from launching its own MPRIS service
if (config.plugins.isEnabled('shortcuts')) { if (config.plugins.isEnabled('shortcuts')) {
app.commandLine.appendSwitch('disable-features', 'MediaSessionService'); app.commandLine.appendSwitch('disable-features', 'MediaSessionService');
@ -833,7 +825,7 @@ app.whenReady().then(async () => {
// Optimized for Mac OS X // Optimized for Mac OS X
if (is.macOS() && !config.get('options.appVisible')) { if (is.macOS() && !config.get('options.appVisible')) {
app.dock.hide(); app.dock?.hide();
} }
let forceQuit = false; let forceQuit = false;

View File

@ -68,7 +68,7 @@ export const mainMenuTemplate = async (
win: BrowserWindow, win: BrowserWindow,
): Promise<MenuTemplate> => { ): Promise<MenuTemplate> => {
const innerRefreshMenu = () => refreshMenu(win); const innerRefreshMenu = () => refreshMenu(win);
const { navigationHistory } = win.webContents;
await loadAllMenuPlugins(win); await loadAllMenuPlugins(win);
const menuResult = Object.entries(getAllMenuTemplate()).map( const menuResult = Object.entries(getAllMenuTemplate()).map(
@ -610,16 +610,16 @@ export const mainMenuTemplate = async (
{ {
label: t('main.menu.navigation.submenu.go-back'), label: t('main.menu.navigation.submenu.go-back'),
click() { click() {
if (win.webContents.canGoBack()) { if (navigationHistory.canGoBack()) {
win.webContents.goBack(); navigationHistory.goBack();
} }
}, },
}, },
{ {
label: t('main.menu.navigation.submenu.go-forward'), label: t('main.menu.navigation.submenu.go-forward'),
click() { click() {
if (win.webContents.canGoForward()) { if (navigationHistory.canGoForward()) {
win.webContents.goForward(); navigationHistory.goForward();
} }
}, },
}, },

View File

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

View File

@ -27,6 +27,7 @@ export const backend = createBackend<BackendType, APIServerConfig>({
ctx.ipc.on('ytmd:player-api-loaded', () => { ctx.ipc.on('ytmd:player-api-loaded', () => {
ctx.ipc.send('ytmd:setup-time-changed-listener'); ctx.ipc.send('ytmd:setup-time-changed-listener');
ctx.ipc.send('ytmd:setup-repeat-changed-listener'); ctx.ipc.send('ytmd:setup-repeat-changed-listener');
ctx.ipc.send('ytmd:setup-volume-changed-listener');
}); });
ctx.ipc.on( ctx.ipc.on(
@ -34,6 +35,11 @@ export const backend = createBackend<BackendType, APIServerConfig>({
(mode: RepeatMode) => (this.currentRepeatMode = mode), (mode: RepeatMode) => (this.currentRepeatMode = mode),
); );
ctx.ipc.on(
'ytmd:volume-changed',
(newVolume: number) => (this.volume = newVolume),
);
this.run(config.hostname, config.port); this.run(config.hostname, config.port);
}, },
stop() { stop() {
@ -95,6 +101,7 @@ export const backend = createBackend<BackendType, APIServerConfig>({
ctx, ctx,
() => this.songInfo, () => this.songInfo,
() => this.currentRepeatMode, () => this.currentRepeatMode,
() => this.volume,
); );
registerAuth(this.app, ctx); registerAuth(this.app, ctx);

View File

@ -173,7 +173,24 @@ const routes = {
}, },
}, },
}), }),
getShuffleState: createRoute({
method: 'get',
path: `/api/${API_VERSION}/shuffle`,
summary: 'get shuffle state',
description: 'Get the current shuffle state',
responses: {
200: {
description: 'Success',
content: {
'application/json': {
schema: z.object({
state: z.boolean().nullable(),
}),
},
},
},
},
}),
shuffle: createRoute({ shuffle: createRoute({
method: 'post', method: 'post',
path: `/api/${API_VERSION}/shuffle`, path: `/api/${API_VERSION}/shuffle`,
@ -245,6 +262,24 @@ const routes = {
}, },
}, },
}), }),
getVolumeState: createRoute({
method: 'get',
path: `/api/${API_VERSION}/volume`,
summary: 'get volume state',
description: 'Get the current volume state of the player',
responses: {
200: {
description: 'Success',
content: {
'application/json': {
schema: z.object({
state: z.number(),
}),
},
},
},
},
}),
setFullscreen: createRoute({ setFullscreen: createRoute({
method: 'post', method: 'post',
path: `/api/${API_VERSION}/fullscreen`, path: `/api/${API_VERSION}/fullscreen`,
@ -496,6 +531,7 @@ export const register = (
{ window }: BackendContext<APIServerConfig>, { window }: BackendContext<APIServerConfig>,
songInfoGetter: () => SongInfo | undefined, songInfoGetter: () => SongInfo | undefined,
repeatModeGetter: () => RepeatMode | undefined, repeatModeGetter: () => RepeatMode | undefined,
volumeGetter: () => number | undefined,
) => { ) => {
const controller = getSongControls(window); const controller = getSongControls(window);
@ -562,6 +598,25 @@ export const register = (
ctx.status(204); ctx.status(204);
return ctx.body(null); return ctx.body(null);
}); });
app.openapi(routes.getShuffleState, async (ctx) => {
const stateResponsePromise = new Promise<boolean>((resolve) => {
ipcMain.once(
'ytmd:get-shuffle-response',
(_, isShuffled: boolean | undefined) => {
return resolve(!!isShuffled);
},
);
controller.requestShuffleInformation();
});
const isShuffled = await stateResponsePromise;
ctx.status(200);
return ctx.json({ state: isShuffled });
});
app.openapi(routes.shuffle, (ctx) => { app.openapi(routes.shuffle, (ctx) => {
controller.shuffle(); controller.shuffle();
@ -587,6 +642,10 @@ export const register = (
ctx.status(204); ctx.status(204);
return ctx.body(null); return ctx.body(null);
}); });
app.openapi(routes.getVolumeState, (ctx) => {
ctx.status(200);
return ctx.json({ state: volumeGetter() ?? 0 });
});
app.openapi(routes.setFullscreen, (ctx) => { app.openapi(routes.setFullscreen, (ctx) => {
const { state } = ctx.req.valid('json'); const { state } = ctx.req.valid('json');
controller.setFullscreen(state); controller.setFullscreen(state);
@ -660,8 +719,8 @@ export const register = (
app.openapi(routes.queueInfo, queueInfo); app.openapi(routes.queueInfo, queueInfo);
app.openapi(routes.addSongToQueue, (ctx) => { app.openapi(routes.addSongToQueue, (ctx) => {
const { videoId } = ctx.req.valid('json'); const { videoId, insertPosition } = ctx.req.valid('json');
controller.addSongToQueue(videoId); controller.addSongToQueue(videoId, insertPosition);
ctx.status(204); ctx.status(204);
return ctx.body(null); return ctx.body(null);

View File

@ -6,6 +6,10 @@ export const QueueParamsSchema = z.object({
export const AddSongToQueueSchema = z.object({ export const AddSongToQueueSchema = z.object({
videoId: z.string(), videoId: z.string(),
insertPosition: z
.enum(['INSERT_AT_END', 'INSERT_AFTER_CURRENT_VIDEO'])
.optional()
.default('INSERT_AT_END'),
}); });
export const MoveSongInQueueSchema = z.object({ export const MoveSongInQueueSchema = z.object({
toIndex: z.number(), toIndex: z.number(),

View File

@ -13,6 +13,7 @@ export type BackendType = {
oldConfig?: APIServerConfig; oldConfig?: APIServerConfig;
songInfo?: SongInfo; songInfo?: SongInfo;
currentRepeatMode?: RepeatMode; currentRepeatMode?: RepeatMode;
volume?: number;
init: (ctx: BackendContext<APIServerConfig>) => Promise<void>; init: (ctx: BackendContext<APIServerConfig>) => Promise<void>;
run: (hostname: string, port: number) => void; run: (hostname: string, port: number) => void;

View File

@ -38,6 +38,12 @@ const info: Info = {
*/ */
const refreshCallbacks: (() => void)[] = []; const refreshCallbacks: (() => void)[] = [];
const truncateString = (str: string, length: number): string => {
if (str.length > length)
return `${str.substring(0, length - 3)}...`;
return str;
}
const resetInfo = () => { const resetInfo = () => {
info.ready = false; info.ready = false;
clearTimeout(clearActivity); clearTimeout(clearActivity);
@ -154,15 +160,14 @@ export const backend = createBackend<
// @see https://discord.com/developers/docs/topics/gateway#activity-object // @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 // 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 const hangulFillerUnicodeCharacter = '\u3164'; // This is an empty character
if (songInfo.title.length < 2) { const paddedInfoKeys: (keyof SongInfo)[] = ['title', 'artist', 'album'];
songInfo.title += hangulFillerUnicodeCharacter.repeat( for (const key of paddedInfoKeys) {
2 - songInfo.title.length, const keyLength = (songInfo[key] as string)?.length;
); if (keyLength < 2) {
} (songInfo[key] as string) += hangulFillerUnicodeCharacter.repeat(
if (songInfo.artist.length < 2) { 2 - keyLength,
songInfo.artist += hangulFillerUnicodeCharacter.repeat( );
2 - songInfo.title.length, }
);
} }
// see https://github.com/th-ch/youtube-music/issues/1664 // see https://github.com/th-ch/youtube-music/issues/1664
@ -185,8 +190,8 @@ export const backend = createBackend<
const activityInfo: SetActivity = { const activityInfo: SetActivity = {
type: ActivityType.Listening, type: ActivityType.Listening,
details: songInfo.title, details: truncateString(songInfo.title, 128),
state: songInfo.artist, state: truncateString(songInfo.artist, 128),
largeImageKey: songInfo.imageSrc ?? '', largeImageKey: songInfo.imageSrc ?? '',
largeImageText: songInfo.album ?? '', largeImageText: songInfo.album ?? '',
buttons, buttons,

View File

@ -3,26 +3,22 @@ import { join } from 'node:path';
import { randomBytes } from 'node:crypto'; import { randomBytes } from 'node:crypto';
import { app, BrowserWindow, dialog, ipcMain } from 'electron'; import { app, BrowserWindow, dialog, ipcMain } from 'electron';
import { import { Innertube, UniversalCache, Utils, YTNodes } from 'youtubei.js';
ClientType,
Innertube,
UniversalCache,
Utils,
YTNodes,
} from 'youtubei.js';
import is from 'electron-is'; import is from 'electron-is';
import filenamify from 'filenamify'; import filenamify from 'filenamify';
import { Mutex } from 'async-mutex'; import { Mutex } from 'async-mutex';
import { createFFmpeg } from '@ffmpeg.wasm/main'; import { createFFmpeg } from '@ffmpeg.wasm/main';
import NodeID3, { TagConstants } from 'node-id3'; import NodeID3, { TagConstants } from 'node-id3';
import { Window } from 'happy-dom';
import { BG, type BgConfig } from 'bgutils-js';
import { import {
cropMaxWidth, cropMaxWidth,
getFolder, getFolder,
sendFeedback as sendFeedback_, sendFeedback as sendFeedback_,
setBadge, setBadge,
} from './utils'; } from './utils';
import { fetchFromGenius } from '@/plugins/lyrics-genius/main'; import { fetchFromGenius } from '@/plugins/lyrics-genius/main';
import { isEnabled } from '@/config/plugins'; import { isEnabled } from '@/config/plugins';
import registerCallback, { import registerCallback, {
@ -33,21 +29,17 @@ import registerCallback, {
SongInfoEvent, SongInfoEvent,
} from '@/providers/song-info'; } from '@/providers/song-info';
import { getNetFetchAsFetch } from '@/plugins/utils/main'; import { getNetFetchAsFetch } from '@/plugins/utils/main';
import { t } from '@/i18n'; import { t } from '@/i18n';
import { DefaultPresetList, type Preset, YoutubeFormatList } from '../types'; import { DefaultPresetList, type Preset, YoutubeFormatList } from '../types';
import type { DownloaderPluginConfig } from '../index'; import type { DownloaderPluginConfig } from '../index';
import type { BackendContext } from '@/types/contexts'; import type { BackendContext } from '@/types/contexts';
import type { FormatOptions } from 'youtubei.js/dist/src/types/FormatUtils'; import type { FormatOptions } from 'youtubei.js/dist/src/types/FormatUtils';
import type PlayerErrorMessage from 'youtubei.js/dist/src/parser/classes/PlayerErrorMessage'; import type PlayerErrorMessage from 'youtubei.js/dist/src/parser/classes/PlayerErrorMessage';
import type { Playlist } from 'youtubei.js/dist/src/parser/ytmusic'; import type { Playlist } from 'youtubei.js/dist/src/parser/ytmusic';
import type { VideoInfo } from 'youtubei.js/dist/src/parser/youtube'; import type { VideoInfo } from 'youtubei.js/dist/src/parser/youtube';
import type TrackInfo from 'youtubei.js/dist/src/parser/ytmusic/TrackInfo'; import type TrackInfo from 'youtubei.js/dist/src/parser/ytmusic/TrackInfo';
import type { GetPlayerResponse } from '@/types/get-player-response'; import type { GetPlayerResponse } from '@/types/get-player-response';
type CustomSongInfo = SongInfo & { trackId?: string }; type CustomSongInfo = SongInfo & { trackId?: string };
@ -63,10 +55,20 @@ let yt: Innertube;
let win: BrowserWindow; let win: BrowserWindow;
let playingUrl: string; let playingUrl: string;
const isYouTubePremium = () => const isYouTubeMusicPremium = async () => {
win.webContents.executeJavaScript( const upgradeBtnIconPathData = (await win.webContents.executeJavaScript(
'!document.querySelector(\'#endpoint[href="/music_premium"]\')', 'document.querySelector(\'iron-iconset-svg[name="yt-sys-icons"] #youtube_music_monochrome\')?.firstChild?.getAttribute("d")?.substring(0, 15)',
) as Promise<boolean>; )) 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) => { const sendError = (error: Error, source?: string) => {
win.setProgressBar(-1); // Close progress bar win.setProgressBar(-1); // Close progress bar
@ -119,6 +121,66 @@ export const onMainLoad = async ({
generate_session_locally: true, generate_session_locally: true,
fetch: getNetFetchAsFetch(), fetch: getNetFetchAsFetch(),
}); });
const requestKey = 'O43z0dpjhgX20SCx4KAo';
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
const window = new Window({
width,
height,
console,
});
const document = window.document;
Object.assign(globalThis, {
window,
document,
});
const bgConfig: BgConfig = {
fetch: getNetFetchAsFetch(),
globalObj: globalThis,
identifier: visitorData,
requestKey,
};
const bgChallenge = await BG.Challenge.create(bgConfig);
const interpreterJavascript =
bgChallenge?.interpreterJavascript
.privateDoNotAccessOrElseSafeScriptWrappedValue;
if (interpreterJavascript) {
// This is a workaround to run the interpreterJavascript code
// Maybe there is a better way to do this (e.g. https://github.com/Siubaak/sval ?)
// eslint-disable-next-line @typescript-eslint/no-implied-eval,@typescript-eslint/no-unsafe-call
new Function(interpreterJavascript)();
const poTokenResult = await BG.PoToken.generate({
program: bgChallenge.program,
globalName: bgChallenge.globalName,
bgConfig,
}).finally(() => {
cleanUp(globalThis);
});
yt.session.po_token = poTokenResult.poToken;
} else {
cleanUp(globalThis);
}
} catch {
cleanUp(globalThis);
}
}
ipc.handle('download-song', (url: string) => downloadSong(url)); ipc.handle('download-song', (url: string) => downloadSong(url));
ipc.on('ytmd:video-src-changed', (data: GetPlayerResponse) => { ipc.on('ytmd:video-src-changed', (data: GetPlayerResponse) => {
playingUrl = data.microformat.microformatDataRenderer.urlCanonical; playingUrl = data.microformat.microformatDataRenderer.urlCanonical;
@ -318,7 +380,7 @@ async function downloadSongUnsafe(
} }
const downloadOptions: FormatOptions = { 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. quality: 'best', // Best, bestefficiency, 144p, 240p, 480p, 720p and so on.
format: 'any', // Media container format format: 'any', // Media container format
}; };
@ -577,7 +639,12 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
try { try {
playlist = await yt.music.getPlaylist(playlistId); playlist = await yt.music.getPlaylist(playlistId);
if (playlist?.items) { if (playlist?.items) {
items.push(...playlist.items.as(YTNodes.MusicResponsiveListItem)); const filteredItems = playlist.items.filter(
(item): item is YTNodes.MusicResponsiveListItem =>
item instanceof YTNodes.MusicResponsiveListItem,
);
items.push(...filteredItems);
} }
} catch (error: unknown) { } catch (error: unknown) {
sendError( sendError(
@ -612,9 +679,13 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
while (playlist.has_continuation) { while (playlist.has_continuation) {
playlist = await playlist.getContinuation(); playlist = await playlist.getContinuation();
if (playlist?.items) {
items.push(...playlist.items.as(YTNodes.MusicResponsiveListItem)); const filteredItems = playlist.items.filter(
} (item): item is YTNodes.MusicResponsiveListItem =>
item instanceof YTNodes.MusicResponsiveListItem,
);
items.push(...filteredItems);
} }
if (items.length === 1) { if (items.length === 1) {
@ -776,13 +847,7 @@ const getMetadata = (info: TrackInfo): CustomSongInfo => ({
// This is used to bypass age restrictions // This is used to bypass age restrictions
const getAndroidTvInfo = async (id: string): Promise<VideoInfo> => { const getAndroidTvInfo = async (id: string): Promise<VideoInfo> => {
const innertube = await Innertube.create({
client_type: ClientType.TV_EMBEDDED,
generate_session_locally: true,
retrieve_player: true,
fetch: getNetFetchAsFetch(),
});
// GetInfo 404s with the bypass, so we use getBasicInfo instead // GetInfo 404s with the bypass, so we use getBasicInfo instead
// that's fine as we only need the streaming data // that's fine as we only need the streaming data
return await innertube.getBasicInfo(id, 'TV_EMBEDDED'); return await yt.getBasicInfo(id, 'TV_EMBEDDED');
}; };

View File

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

View File

@ -22,27 +22,5 @@ export default createPlugin({
node.remove(); node.remove();
} }
} }
// Remove the library button
const libraryIconPath =
'M16,6v2h-2v5c0,1.1-0.9,2-2,2s-2-0.9-2-2s0.9-2,2-2c0.37,0,0.7,0.11,1,0.28V6H16z M18,20H4V6H3v15h15V20z M21,3H6v15h15V3z M7,4h13v13H7V4z';
const observer = new MutationObserver(() => {
const menuEntries = document.querySelectorAll(
'#items ytmusic-guide-entry-renderer',
);
menuEntries.forEach((item) => {
const icon = item.querySelector('path');
if (icon) {
observer.disconnect();
if (icon.getAttribute('d') === libraryIconPath) {
item.remove();
}
}
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true,
});
}, },
}); });

View File

@ -12,6 +12,12 @@ export interface ScrobblerPluginConfig {
* @default true * @default true
*/ */
scrobbleOtherMedia: boolean; scrobbleOtherMedia: boolean;
/**
* Use alternative titles for scrobbling (Useful for non-roman song titles)
*
* @default false
*/
alternativeTitles: boolean;
scrobblers: { scrobblers: {
lastfm: { lastfm: {
/** /**
@ -71,6 +77,7 @@ export interface ScrobblerPluginConfig {
export const defaultConfig: ScrobblerPluginConfig = { export const defaultConfig: ScrobblerPluginConfig = {
enabled: false, enabled: false,
scrobbleOtherMedia: true, scrobbleOtherMedia: true,
alternativeTitles: false,
scrobblers: { scrobblers: {
lastfm: { lastfm: {
enabled: false, enabled: false,

View File

@ -96,6 +96,15 @@ export const onMenu = async ({
setConfig(config); setConfig(config);
}, },
}, },
{
label: t('plugins.scrobbler.menu.scrobble-alternative-title'),
type: 'checkbox',
checked: Boolean(config.alternativeTitles),
click(item) {
config.alternativeTitles = item.checked;
setConfig(config);
},
},
{ {
label: 'Last.fm', label: 'Last.fm',
submenu: [ submenu: [

View File

@ -127,8 +127,13 @@ export class LastFmScrobbler extends ScrobblerBase {
await this.createSession(config, setConfig); await this.createSession(config, setConfig);
} }
const title =
config.alternativeTitles && songInfo.alternativeTitle !== undefined
? songInfo.alternativeTitle
: songInfo.title;
const postData: LastFmSongData = { const postData: LastFmSongData = {
track: songInfo.title, track: title,
duration: songInfo.songDuration, duration: songInfo.songDuration,
artist: songInfo.artist, artist: songInfo.artist,
...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video ...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video

View File

@ -48,7 +48,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
return; return;
} }
const body = createRequestBody('playing_now', songInfo); const body = createRequestBody('playing_now', songInfo, config);
submitListen(body, config); submitListen(body, config);
} }
@ -64,7 +64,7 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
return; return;
} }
const body = createRequestBody('single', songInfo); const body = createRequestBody('single', songInfo, config);
body.payload[0].listened_at = Math.trunc(Date.now() / 1000); body.payload[0].listened_at = Math.trunc(Date.now() / 1000);
submitListen(body, config); submitListen(body, config);
@ -74,10 +74,16 @@ export class ListenbrainzScrobbler extends ScrobblerBase {
function createRequestBody( function createRequestBody(
listenType: string, listenType: string,
songInfo: SongInfo, songInfo: SongInfo,
config: ScrobblerPluginConfig,
): ListenbrainzRequestBody { ): ListenbrainzRequestBody {
const title =
config.alternativeTitles && songInfo.alternativeTitle !== undefined
? songInfo.alternativeTitle
: songInfo.title;
const trackMetadata = { const trackMetadata = {
artist_name: songInfo.artist, artist_name: songInfo.artist,
track_name: songInfo.title, track_name: title,
release_name: songInfo.album ?? undefined, release_name: songInfo.album ?? undefined,
additional_info: { additional_info: {
media_player: 'YouTube Music Desktop App', media_player: 'YouTube Music Desktop App',

View File

@ -1,7 +1,7 @@
declare module '@jellybrick/mpris-service' { declare module '@jellybrick/mpris-service' {
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { interface as dbusInterface } from 'dbus-next'; import { interface as dbusInterface } from '@jellybrick/dbus-next';
interface RootInterfaceOptions { interface RootInterfaceOptions {
identity?: string; identity?: string;
@ -86,7 +86,7 @@ declare module '@jellybrick/mpris-service' {
supportedMimeTypes: string[]; supportedMimeTypes: string[];
canQuit: boolean; canQuit: boolean;
canRaise: boolean; canRaise: boolean;
canSetFullscreen?: boolean; canUsePlayerControls?: boolean;
desktopEntry?: string; desktopEntry?: string;
hasTrackList: boolean; hasTrackList: boolean;

View File

@ -77,7 +77,7 @@ function setupMPRIS() {
instance.canRaise = true; instance.canRaise = true;
instance.canQuit = false; instance.canQuit = false;
instance.canSetFullscreen = true; instance.canUsePlayerControls = true;
instance.supportedUriSchemes = ['http', 'https']; instance.supportedUriSchemes = ['http', 'https'];
instance.desktopEntry = 'youtube-music'; instance.desktopEntry = 'youtube-music';
return instance; return instance;
@ -93,6 +93,7 @@ function registerMPRIS(win: BrowserWindow) {
shuffle, shuffle,
switchRepeat, switchRepeat,
setFullscreen, setFullscreen,
requestShuffleInformation,
requestFullscreenInformation, requestFullscreenInformation,
requestQueueInformation, requestQueueInformation,
} = songControls; } = songControls;
@ -126,8 +127,10 @@ function registerMPRIS(win: BrowserWindow) {
win.webContents.send('ytmd:setup-time-changed-listener', 'mpris'); win.webContents.send('ytmd:setup-time-changed-listener', 'mpris');
win.webContents.send('ytmd:setup-repeat-changed-listener', 'mpris'); win.webContents.send('ytmd:setup-repeat-changed-listener', 'mpris');
win.webContents.send('ytmd:setup-volume-changed-listener', 'mpris'); win.webContents.send('ytmd:setup-volume-changed-listener', 'mpris');
win.webContents.send('ytmd:setup-shuffle-changed-listener', 'mpris');
win.webContents.send('ytmd:setup-fullscreen-changed-listener', 'mpris'); win.webContents.send('ytmd:setup-fullscreen-changed-listener', 'mpris');
win.webContents.send('ytmd:setup-autoplay-changed-listener', 'mpris'); win.webContents.send('ytmd:setup-autoplay-changed-listener', 'mpris');
requestShuffleInformation();
requestFullscreenInformation(); requestFullscreenInformation();
requestQueueInformation(); requestQueueInformation();
}); });
@ -156,8 +159,16 @@ function registerMPRIS(win: BrowserWindow) {
requestQueueInformation(); requestQueueInformation();
}); });
ipcMain.on('ytmd:shuffle-changed', (_, shuffleEnabled: boolean) => {
if (player.shuffle === undefined || !player.canUsePlayerControls) {
return;
}
player.shuffle = shuffleEnabled ?? !player.shuffle;
});
ipcMain.on('ytmd:fullscreen-changed', (_, changedTo: boolean) => { ipcMain.on('ytmd:fullscreen-changed', (_, changedTo: boolean) => {
if (player.fullscreen === undefined || !player.canSetFullscreen) { if (player.fullscreen === undefined || !player.canUsePlayerControls) {
return; return;
} }
@ -168,7 +179,7 @@ function registerMPRIS(win: BrowserWindow) {
ipcMain.on( ipcMain.on(
'ytmd:set-fullscreen', 'ytmd:set-fullscreen',
(_, isFullscreen: boolean | undefined) => { (_, isFullscreen: boolean | undefined) => {
if (!player.canSetFullscreen || isFullscreen === undefined) { if (!player.canUsePlayerControls || isFullscreen === undefined) {
return; return;
} }
@ -179,7 +190,7 @@ function registerMPRIS(win: BrowserWindow) {
ipcMain.on( ipcMain.on(
'ytmd:fullscreen-changed-supported', 'ytmd:fullscreen-changed-supported',
(_, isFullscreenSupported: boolean) => { (_, isFullscreenSupported: boolean) => {
player.canSetFullscreen = isFullscreenSupported; player.canUsePlayerControls = isFullscreenSupported;
}, },
); );
ipcMain.on('ytmd:autoplay-changed', (_) => { ipcMain.on('ytmd:autoplay-changed', (_) => {
@ -272,6 +283,12 @@ function registerMPRIS(win: BrowserWindow) {
player.on('position', seekTo); player.on('position', seekTo);
player.on('shuffle', (enableShuffle) => { player.on('shuffle', (enableShuffle) => {
if (!player.canUsePlayerControls || enableShuffle === undefined) {
return;
}
player.shuffle = enableShuffle;
if (enableShuffle) { if (enableShuffle) {
shuffle(); shuffle();
requestQueueInformation(); requestQueueInformation();

View File

@ -20,7 +20,8 @@ export default createPlugin({
showTimeCodes: false, showTimeCodes: false,
defaultTextString: '♪', defaultTextString: '♪',
lineEffect: 'fancy', lineEffect: 'fancy',
} satisfies SyncedLyricsPluginConfig, romanization: true,
} satisfies SyncedLyricsPluginConfig as SyncedLyricsPluginConfig,
menu, menu,
renderer, renderer,

View File

@ -1,7 +1,6 @@
import { MenuItemConstructorOptions } from 'electron';
import { t } from '@/i18n'; import { t } from '@/i18n';
import type { MenuItemConstructorOptions } from 'electron';
import type { MenuContext } from '@/types/contexts'; import type { MenuContext } from '@/types/contexts';
import type { SyncedLyricsPluginConfig } from './types'; import type { SyncedLyricsPluginConfig } from './types';
@ -136,6 +135,17 @@ export const menu = async (
}, },
], ],
}, },
{
label: t('plugins.synced-lyrics.menu.romanization.label'),
toolTip: t('plugins.synced-lyrics.menu.romanization.tooltip'),
type: 'checkbox',
checked: config.romanization,
click(item) {
ctx.setConfig({
romanization: item.checked,
});
},
},
{ {
label: t('plugins.synced-lyrics.menu.show-time-codes.label'), label: t('plugins.synced-lyrics.menu.show-time-codes.label'),
toolTip: t('plugins.synced-lyrics.menu.show-time-codes.tooltip'), toolTip: t('plugins.synced-lyrics.menu.show-time-codes.tooltip'),

View File

@ -30,15 +30,16 @@ export class LyricsGenius implements LyricProvider {
title: titleA, title: titleA,
primary_artist: { name: artistA }, primary_artist: { name: artistA },
}, },
}, }, {
{
result: { result: {
title: titleB, title: titleB,
primary_artist: { name: artistB }, primary_artist: { name: artistB },
}, },
}) => { }) => {
const pointsA = (titleA === title ? 1 : 0) + (artistA.includes(artist) ? 1 : 0); const pointsA = (titleA === title ? 1 : 0) +
const pointsB = (titleB === title ? 1 : 0) + (artistB.includes(artist) ? 1 : 0); (artistA.includes(artist) ? 1 : 0);
const pointsB = (titleB === title ? 1 : 0) +
(artistB.includes(artist) ? 1 : 0);
return pointsB - pointsA; return pointsB - pointsA;
}, },
@ -51,14 +52,21 @@ export class LyricsGenius implements LyricProvider {
const { result: { path } } = closestHit; const { result: { path } } = closestHit;
const html = await fetch(`${this.baseUrl}${path}`).then((res) => res.text()); const html = await fetch(`${this.baseUrl}${path}`).then((res) =>
res.text()
);
const doc = this.domParser.parseFromString(html, 'text/html'); const doc = this.domParser.parseFromString(html, 'text/html');
const preloadedStateScript = Array.prototype.find.call(doc.querySelectorAll('script'), (script: HTMLScriptElement) => { const preloadedStateScript = Array.prototype.find.call(
return script.textContent?.includes('window.__PRELOADED_STATE__'); doc.querySelectorAll('script'),
}) as HTMLScriptElement; (script: HTMLScriptElement) => {
return script.textContent?.includes('window.__PRELOADED_STATE__');
},
) as HTMLScriptElement;
const preloadedState = preloadedStateScript.textContent?.match(preloadedStateRegex)?.[1]?.replace(/\\"/g, '"'); const preloadedState = preloadedStateScript.textContent?.match(
preloadedStateRegex,
)?.[1]?.replace(/\\"/g, '"');
const lyricsHtml = preloadedState?.match(preloadHtmlRegex)?.[1] const lyricsHtml = preloadedState?.match(preloadHtmlRegex)?.[1]
?.replace(/\\\//g, '/') ?.replace(/\\\//g, '/')
@ -67,12 +75,19 @@ export class LyricsGenius implements LyricProvider {
?.replace(/\\'/g, "'") ?.replace(/\\'/g, "'")
?.replace(/\\"/g, '"'); ?.replace(/\\"/g, '"');
if (!lyricsHtml) throw new Error('Failed to extract lyrics from preloaded state.'); const hasUnreleasedPlaceholder = preloadedState &&
/lyricsPlaceholderReason.{1,5}unreleased/.test(preloadedState);
if (!lyricsHtml) {
if (hasUnreleasedPlaceholder) return null;
throw new Error('Failed to extract lyrics from preloaded state.');
}
const lyricsDoc = this.domParser.parseFromString(lyricsHtml, 'text/html'); const lyricsDoc = this.domParser.parseFromString(lyricsHtml, 'text/html');
const lyrics = lyricsDoc.body.innerText; const lyrics = lyricsDoc.body.innerText;
if (lyrics.trim().toLowerCase().replace(/[[\]]/g, '') === 'instrumental') return null; if (lyrics.trim().toLowerCase().replace(/[[\]]/g, '') === 'instrumental') {
return null;
}
return { return {
title: closestHit.result.title, title: closestHit.result.title,

View File

@ -1,4 +1,4 @@
import { createSignal, For, Match, Show, Switch } from 'solid-js'; import { createEffect, createSignal, For, Match, Show, Switch } from 'solid-js';
import { SyncedLine } from './SyncedLine'; import { SyncedLine } from './SyncedLine';
@ -6,6 +6,7 @@ import { ErrorDisplay } from './ErrorDisplay';
import { LoadingKaomoji } from './LoadingKaomoji'; import { LoadingKaomoji } from './LoadingKaomoji';
import { PlainLyrics } from './PlainLyrics'; import { PlainLyrics } from './PlainLyrics';
import { hasJapaneseInString, hasKoreanInString } from '../utils';
import { currentLyrics, lyricsStore } from '../../providers'; import { currentLyrics, lyricsStore } from '../../providers';
export const [debugInfo, setDebugInfo] = createSignal<string>(); export const [debugInfo, setDebugInfo] = createSignal<string>();
@ -13,6 +14,20 @@ export const [currentTime, setCurrentTime] = createSignal<number>(-1);
// prettier-ignore // prettier-ignore
export const LyricsContainer = () => { export const LyricsContainer = () => {
const [hasJapanese, setHasJapanese] = createSignal<boolean>(false);
const [hasKorean, setHasKorean] = createSignal<boolean>(false);
createEffect(() => {
const data = currentLyrics()?.data;
if (data) {
setHasKorean(hasKoreanInString(data));
setHasJapanese(hasJapaneseInString(data));
} else {
setHasKorean(false);
setHasJapanese(false);
}
});
return ( return (
<div class="lyric-container"> <div class="lyric-container">
<Switch> <Switch>
@ -42,12 +57,12 @@ export const LyricsContainer = () => {
<Switch> <Switch>
<Match when={currentLyrics().data?.lines}> <Match when={currentLyrics().data?.lines}>
<For each={currentLyrics().data?.lines}> <For each={currentLyrics().data?.lines}>
{(item) => <SyncedLine line={item} />} {(item) => <SyncedLine line={item} hasJapanese={hasJapanese()} hasKorean={hasKorean()} />}
</For> </For>
</Match> </Match>
<Match when={currentLyrics().data?.lyrics}> <Match when={currentLyrics().data?.lyrics}>
<PlainLyrics lyrics={currentLyrics().data?.lyrics!} /> <PlainLyrics lyrics={currentLyrics().data!.lyrics!} hasJapanese={hasJapanese()} hasKorean={hasKorean()} />
</Match> </Match>
</Switch> </Switch>
</div> </div>

View File

@ -1,28 +1,91 @@
import { createMemo, For } from 'solid-js'; import { createEffect, createMemo, createSignal, For, Show } from 'solid-js';
import {
canonicalize,
romanizeChinese,
romanizeHangul,
romanizeJapanese,
romanizeJapaneseOrHangul,
simplifyUnicode,
} from '../utils';
import { config } from '../renderer';
interface PlainLyricsProps { interface PlainLyricsProps {
lyrics: string; lyrics: string;
hasJapanese: boolean;
hasKorean: boolean;
} }
export const PlainLyrics = (props: PlainLyricsProps) => { export const PlainLyrics = (props: PlainLyricsProps) => {
const lines = createMemo(() => props.lyrics.split('\n')); const lines = props.lyrics.split('\n').filter((line) => line.trim());
const [romanizedLines, setRomanizedLines] = createSignal<
Record<string, string>
>({});
const combinedLines = createMemo(() => {
const out = [];
for (let i = 0; i < lines.length; i++) {
out.push([lines[i], romanizedLines()[i]]);
}
return out;
});
createEffect(async () => {
if (!config()?.romanization) return;
for (let i = 0; i < lines.length; i++) {
let romanized: string;
if (props.hasJapanese) {
if (props.hasKorean)
romanized = await romanizeJapaneseOrHangul(lines[i]);
else romanized = await romanizeJapanese(lines[i]);
} else if (props.hasKorean) romanized = romanizeHangul(lines[i]);
else romanized = romanizeChinese(lines[i]);
setRomanizedLines((prev) => ({
...prev,
[i]: canonicalize(romanized),
}));
}
});
return ( return (
<div class="plain-lyrics"> <div class="plain-lyrics">
<For each={lines()}> <For each={combinedLines()}>
{(line) => { {([line, romanized]) => {
if (line.trim() === '') { return (
return <br />; <div
} else { class={`${
return ( line.match(/^\[.+\]$/s) ? 'lrc-header' : ''
} text-lyrics description ytmusic-description-shelf-renderer`}
style={{
'display': 'flex',
'flex-direction': 'column',
}}
>
<yt-formatted-string <yt-formatted-string
class="text-lyrics description ytmusic-description-shelf-renderer"
text={{ text={{
runs: [{ text: line }], runs: [{ text: line }],
}} }}
/> />
); <Show
} when={
config()?.romanization &&
simplifyUnicode(line) !== simplifyUnicode(romanized)
}
>
<yt-formatted-string
class="romaji"
text={{
runs: [{ text: romanized }],
}}
/>
</Show>
</div>
);
}} }}
</For> </For>
</div> </div>

View File

@ -1,22 +1,33 @@
import { createEffect, createMemo, For } from 'solid-js'; import { createEffect, createMemo, For, Show, createSignal } from 'solid-js';
import { currentTime } from './LyricsContainer'; import { currentTime } from './LyricsContainer';
import { config } from '../renderer'; import { config } from '../renderer';
import { _ytAPI } from '..'; import { _ytAPI } from '..';
import {
canonicalize,
romanizeChinese,
romanizeHangul,
romanizeJapanese,
romanizeJapaneseOrHangul,
simplifyUnicode,
} from '../utils';
import type { LineLyrics } from '../../types'; import type { LineLyrics } from '../../types';
interface SyncedLineProps { interface SyncedLineProps {
line: LineLyrics; line: LineLyrics;
hasJapanese: boolean;
hasKorean: boolean;
} }
export const SyncedLine = ({ line }: SyncedLineProps) => { export const SyncedLine = (props: SyncedLineProps) => {
const status = createMemo(() => { const status = createMemo(() => {
const current = currentTime(); const current = currentTime();
if (line.timeInMs >= current) return 'upcoming'; if (props.line.timeInMs >= current) return 'upcoming';
if (current - line.timeInMs >= line.duration) return 'previous'; if (current - props.line.timeInMs >= props.line.duration) return 'previous';
return 'current'; return 'current';
}); });
@ -28,8 +39,28 @@ export const SyncedLine = ({ line }: SyncedLineProps) => {
}); });
const text = createMemo(() => { const text = createMemo(() => {
if (line.text.trim()) return line.text; if (!props.line.text.trim()) {
return config()?.defaultTextString ?? ''; return config()?.defaultTextString ?? '';
}
return props.line.text;
});
const [romanization, setRomanization] = createSignal('');
createEffect(async () => {
if (!config()?.romanization) return;
const input = canonicalize(text());
let result: string;
if (props.hasJapanese) {
if (props.hasKorean) result = await romanizeJapaneseOrHangul(input);
else result = await romanizeJapanese(input);
} else if (props.hasKorean) result = romanizeHangul(input);
else result = romanizeChinese(input);
setRomanization(canonicalize(result));
}); });
if (!text()) { if (!text()) {
@ -47,35 +78,79 @@ export const SyncedLine = ({ line }: SyncedLineProps) => {
ref={ref} ref={ref}
class={`synced-line ${status()}`} class={`synced-line ${status()}`}
onClick={() => { onClick={() => {
_ytAPI?.seekTo(line.timeInMs / 1000); _ytAPI?.seekTo(props.line.timeInMs / 1000);
}} }}
> >
<div class="text-lyrics description ytmusic-description-shelf-renderer"> <div dir="auto" class="description ytmusic-description-shelf-renderer">
<yt-formatted-string <yt-formatted-string
text={{ text={{
runs: [{ text: config()?.showTimeCodes ? `[${line.time}] ` : '' }], runs: [
{ text: config()?.showTimeCodes ? `[${props.line.time}] ` : '' },
],
}} }}
/> />
<For each={text().split(' ')}> <div
{(word, index) => { class="text-lyrics"
return ( ref={(div: HTMLDivElement) => {
<span // TODO: Investigate the animation, even though the duration is properly set, all lines have the same animation duration
style={{ div.style.setProperty(
'transition-delay': `${index() * 0.05}s`, '--lyrics-duration',
'animation-delay': `${index() * 0.05}s`, `${props.line.duration / 1000}s`,
'--lyrics-duration:': `${line.duration / 1000}s;`, 'important',
}}
>
<yt-formatted-string
text={{
runs: [{ text: `${word} ` }],
}}
/>
</span>
); );
}} }}
</For> style={{ 'display': 'flex', 'flex-direction': 'column' }}
>
<span>
<For each={text().split(' ')}>
{(word, index) => {
return (
<span
style={{
'transition-delay': `${index() * 0.05}s`,
'animation-delay': `${index() * 0.05}s`,
}}
>
<yt-formatted-string
text={{
runs: [{ text: `${word} ` }],
}}
/>
</span>
);
}}
</For>
</span>
<Show
when={
config()?.romanization &&
simplifyUnicode(text()) !== simplifyUnicode(romanization())
}
>
<span class="romaji">
<For each={romanization().split(' ')}>
{(word, index) => {
return (
<span
style={{
'transition-delay': `${index() * 0.05}s`,
'animation-delay': `${index() * 0.05}s`,
}}
>
<yt-formatted-string
text={{
runs: [{ text: `${word} ` }],
}}
/>
</span>
);
}}
</For>
</span>
</Show>
</div>
</div> </div>
</div> </div>
); );

View File

@ -38,7 +38,10 @@ createEffect(() => {
root.style.setProperty('--lyrics-active-offset', '0'); root.style.setProperty('--lyrics-active-offset', '0');
break; break;
case 'scale': case 'scale':
root.style.setProperty('--lyrics-font-size', '1.4rem'); root.style.setProperty(
'--lyrics-font-size',
'clamp(1.4rem, 1.1vmax, 3rem)',
);
root.style.setProperty( root.style.setProperty(
'--lyrics-line-height', '--lyrics-line-height',
'var(--ytmusic-body-line-height)', 'var(--ytmusic-body-line-height)',
@ -58,7 +61,10 @@ createEffect(() => {
root.style.setProperty('--lyrics-active-offset', '0'); root.style.setProperty('--lyrics-active-offset', '0');
break; break;
case 'offset': case 'offset':
root.style.setProperty('--lyrics-font-size', '1.4rem'); root.style.setProperty(
'--lyrics-font-size',
'clamp(1.4rem, 1.1vmax, 3rem)',
);
root.style.setProperty( root.style.setProperty(
'--lyrics-line-height', '--lyrics-line-height',
'var(--ytmusic-body-line-height)', 'var(--ytmusic-body-line-height)',
@ -78,7 +84,10 @@ createEffect(() => {
root.style.setProperty('--lyrics-active-offset', '5%'); root.style.setProperty('--lyrics-active-offset', '5%');
break; break;
case 'focus': case 'focus':
root.style.setProperty('--lyrics-font-size', '1.4rem'); root.style.setProperty(
'--lyrics-font-size',
'clamp(1.4rem, 1.1vmax, 3rem)',
);
root.style.setProperty( root.style.setProperty(
'--lyrics-line-height', '--lyrics-line-height',
'var(--ytmusic-body-line-height)', 'var(--ytmusic-body-line-height)',

View File

@ -1,8 +1,20 @@
import { render } from 'solid-js/web'; import { render } from 'solid-js/web';
import KuromojiAnalyzer from 'kuroshiro-analyzer-kuromoji';
import Kuroshiro from 'kuroshiro';
import { romanize as esHangulRomanize } from 'es-hangul';
import hanja from 'hanja';
import pinyin from 'pinyin/esm/pinyin';
import { lazy } from 'lazy-var';
import { waitForElement } from '@/utils/wait-for-element'; import { waitForElement } from '@/utils/wait-for-element';
import { LyricsRenderer, setIsVisible } from './renderer'; import { LyricsRenderer, setIsVisible } from './renderer';
import type { LyricResult } from '@/plugins/synced-lyrics/types';
export const selectors = { export const selectors = {
head: '#tabsContent > .tab-header:nth-of-type(2)', head: '#tabsContent > .tab-header:nth-of-type(2)',
body: { body: {
@ -33,3 +45,148 @@ export const tabStates: Record<string, () => void> = {
setIsVisible(false); setIsVisible(false);
}, },
}; };
export const canonicalize = (text: string) => {
return (
text
// `hi there` => `hi there`
.replaceAll(/\s+/g, ' ')
// `( a )` => `(a)`
.replaceAll(/([([]) ([^ ])/g, (_, symbol, a) => `${symbol}${a}`)
.replaceAll(/([^ ]) ([)\]])/g, (_, a, symbol) => `${a}${symbol}`)
// `can ' t` => `can't`
.replaceAll(
/([Ii]) (') ([^ ])|(n) (') (t)(?= |$)|(t) (') (s)|([^ ]) (') (re)|([^ ]) (') (ve)|([^ ]) (-) ([^ ])/g,
(m, ...groups) => {
for (let i = 0; i < groups.length; i += 3) {
if (groups[i]) {
return groups.slice(i, i + 3).join('');
}
}
return m;
},
)
// `Stayin ' still` => `Stayin' still`
.replaceAll(/in ' ([^ ])/g, (_, char) => `in' ${char}`)
.replaceAll("in ',", "in',")
.replaceAll(", ' cause", ", 'cause")
// `hi , there` => `hi, there`
.replaceAll(/([^ ]) ([.,!?])/g, (_, a, symbol) => `${a}${symbol}`)
// `hi " there "` => `hi "there"`
.replaceAll(
/"([^"]+)"/g,
(_, content) =>
`"${typeof content === 'string' ? content.trim() : content}"`,
)
.trim()
);
};
export const simplifyUnicode = (text?: string) =>
text
? text
.replaceAll(/\u0020|\u00A0|[\u2000-\u200A]|\u202F|\u205F|\u3000/g, ' ')
.trim()
: text;
// Japanese Shinjitai
const shinjitai = [
20055, 20081, 20120, 20124, 20175, 26469, 20341, 20206, 20253, 20605, 20385,
20537, 20816, 20001, 20869, 23500, 28092, 20956, 21104, 21091, 21092, 21172,
21234, 21169, 21223, 21306, 24059, 21363, 21442, 21782, 21336, 22107, 21427,
22065, 22287, 22269, 22258, 20870, 22259, 22243, 37326, 23597, 22679, 22549,
22311, 22593, 22730, 22732, 22766, 22769, 23551, 22885, 22888, 23330, 23398,
23517, 23455, 20889, 23515, 23453, 23558, 23554, 23550, 23626, 23631, 23646,
23792, 23777, 23798, 23731, 24012, 24035, 24111, 24182, 24259, 24195, 24193,
24382, 24357, 24367, 24452, 24467, 24500, 24499, 24658, 24693, 24746, 24745,
24910, 24808, 24540, 25040, 24651, 25126, 25135, 25144, 25147, 25173, 25244,
25309, 25375, 25407, 25522, 25531, 25594, 25436, 25246, 25731, 25285, 25312,
25369, 25313, 25666, 25785, 21454, 21177, 21465, 21189, 25968, 26029, 26179,
26217, 26172, 26278, 26241, 26365, 20250, 26465, 26719, 26628, 27097, 27010,
27005, 27004, 26530, 27096, 27178, 26727, 26908, 26716, 27177, 27431, 27475,
27497, 27508, 24112, 27531, 27579, 27572, 27598, 27671, 28169, 28057, 27972,
27973, 28167, 28179, 28201, 28382, 28288, 28300, 28508, 28171, 27810, 28287,
28168, 27996, 27818, 28381, 28716, 28286, 28948, 28783, 28988, 21942, 28809,
20105, 28858, 29344, 29366, 29421, 22888, 29420, 29471, 29539, 29486, 24321,
29942, 30011, 24403, 30067, 30185, 30196, 30330, 26479, 30423, 23613, 30495,
30740, 30741, 30783, 31192, 31108, 31109, 31036, 31074, 31095, 31216, 31282,
38964, 31298, 31311, 31331, 31363, 20006, 31883, 31992, 32076, 32209, 32210,
32257, 30476, 32294, 32207, 32333, 32260, 32117, 32331, 32153, 32154, 32330,
27424, 32566, 22768, 32884, 31899, 33075, 32966, 33235, 21488, 19982, 26087,
33398, 33624, 33550, 33804, 19975, 33931, 22290, 34219, 34101, 33464, 34220,
33446, 20966, 34394, 21495, 34509, 34411, 34635, 34453, 34542, 34907, 35013,
35090, 35226, 35239, 35251, 35302, 35617, 35388, 35379, 35465, 35501, 22793,
35698, 35715, 35914, 33398, 20104, 24336, 22770, 38972, 36059, 36341, 36527,
36605, 36620, 36578, 24321, 36766, 24321, 36965, 36883, 36933, 36794, 37070,
37111, 37204, 21307, 37284, 37271, 37304, 37320, 37682, 37549, 37676, 37806,
37444, 37619, 37489, 38306, 38501, 38543, 38522, 38560, 21452, 38609, 35207,
38666, 38745, 39003, 38997, 32763, 20313, 39173, 39366, 39442, 39366, 39443,
39365, 39620, 20307, 39658, 38360, 40335, 40206, 40568, 22633, 40614, 40633,
40634, 40644, 40658, 40665, 28857, 20826, 25993, 25998, 27503, 40802, 31452,
20096,
].map((codePoint) => String.fromCodePoint(codePoint));
const shinjitaiRegex = new RegExp(`[${shinjitai.join('')}]`);
const kuroshiro = lazy(async () => {
const _kuroshiro = new Kuroshiro();
await _kuroshiro.init(
new KuromojiAnalyzer({
dictPath: 'https://cdn.jsdelivr.net/npm/kuromoji@0.1.2/dict/',
}),
);
return _kuroshiro;
});
const hasJapanese = (lines: string[]) =>
lines.some(
(line) => Kuroshiro.Util.hasKana(line) || shinjitaiRegex.test(line),
);
// tests for Hangul characters, sufficient for our use case
const hasKorean = (lines: string[]) =>
lines.some((line) => /[ㄱ-ㅎㅏ-ㅣ가-힣]+/.test(line));
export const hasJapaneseInString = (lyric: LyricResult) => {
if (!lyric || (!lyric.lines && !lyric.lyrics)) return false;
const lines = Array.isArray(lyric.lines)
? lyric.lines.map(({ text }) => text)
: lyric.lyrics!.split('\n');
return hasJapanese(lines);
};
export const hasKoreanInString = (lyric: LyricResult) => {
if (!lyric || (!lyric.lines && !lyric.lyrics)) return false;
const lines = Array.isArray(lyric.lines)
? lyric.lines.map(({ text }) => text)
: lyric.lyrics!.split('\n');
return hasKorean(lines);
};
export const romanizeJapanese = async (line: string) =>
(await kuroshiro.get()).convert(line, {
to: 'romaji',
mode: 'spaced',
});
export const romanizeHangul = (line: string) =>
esHangulRomanize(hanja.translate(line, 'SUBSTITUTION'));
export const romanizeJapaneseOrHangul = async (line: string) =>
romanizeHangul(await romanizeJapanese(line));
export const romanizeChinese = (line: string) =>
pinyin(line, {
heteronym: true,
segment: true,
group: true,
})
.flat()
.join(' ');

View File

@ -8,6 +8,17 @@
display: block !important; display: block !important;
} }
/* Hide the scrollbar in the lyrics-tab */
#tab-renderer[page-type='MUSIC_PAGE_TYPE_TRACK_LYRICS'] {
scrollbar-width: none;
}
@property --lyrics-duration {
syntax: '<time>';
inherits: false;
initial-value: 2s;
}
/* Variables are overridden by selected line effect */ /* Variables are overridden by selected line effect */
:root { :root {
/* Layout */ /* Layout */
@ -15,9 +26,10 @@
--lyrics-padding: 0; --lyrics-padding: 0;
/* Typography */ /* Typography */
--lyrics-font-family: Satoshi, Avenir, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, --lyrics-font-family: Satoshi, Avenir, -apple-system, BlinkMacSystemFont,
Open Sans, Helvetica Neue, sans-serif; Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue,
--lyrics-font-size: 1.4rem; sans-serif;
--lyrics-font-size: clamp(1.4rem, 1.1vmax, 3rem);
--lyrics-line-height: var(--ytmusic-body-line-height); --lyrics-line-height: var(--ytmusic-body-line-height);
--lyrics-width: 100%; --lyrics-width: 100%;
@ -33,12 +45,15 @@
--lyrics-active-scale: 1; --lyrics-active-scale: 1;
--lyrics-active-offset: 0; --lyrics-active-offset: 0;
--lyrics-duration: 2s;
/* Animations */ /* Animations */
--lyrics-animations: lyrics-glow var(--lyrics-glow-duration) forwards, lyrics-wobble var(--lyrics-wobble-duration) forwards; --lyrics-animations: lyrics-glow var(--lyrics-glow-duration) forwards,
lyrics-wobble var(--lyrics-wobble-duration) forwards;
--lyrics-scale-duration: 0.166s; --lyrics-scale-duration: 0.166s;
--lyrics-opacity-transition: 0.33s; --lyrics-opacity-transition: 0.33s;
--lyrics-glow-duration: var(--lyrics-duration, 2s); --lyrics-glow-duration: var(--lyrics-duration);
--lyrics-wobble-duration: calc(var(--lyrics-duration, 2s) / 2); --lyrics-wobble-duration: calc(var(--lyrics-duration) / 2);
/* Colors */ /* Colors */
--glow-color: rgba(255, 255, 255, 0.5); --glow-color: rgba(255, 255, 255, 0.5);
@ -56,9 +71,29 @@
.synced-line { .synced-line {
width: var(--lyrics-width, 100%); width: var(--lyrics-width, 100%);
& > .text-lyrics { & .text-lyrics {
cursor: pointer; cursor: pointer;
} }
& .text-lyrics > .romaji {
color: var(--ytmusic-text-secondary) !important;
font-size: calc(var(--lyrics-font-size) * 0.7) !important;
font-style: italic !important;
}
}
.plain-lyrics .romaji {
color: var(--ytmusic-text-secondary) !important;
font-size: calc(var(--lyrics-font-size) * 0.7) !important;
font-style: italic !important;
}
.plain-lyrics .lrc-header {
color: var(--ytmusic-color-grey5) !important;
scale: 0.9;
height: fit-content;
padding: 0;
padding-block: 0.2em;
} }
.synced-lyrics { .synced-lyrics {
@ -83,9 +118,7 @@
padding-bottom: var(--lyrics-padding); padding-bottom: var(--lyrics-padding);
scale: var(--lyrics-inactive-scale); scale: var(--lyrics-inactive-scale);
translate: var(--lyrics-inactive-offset); translate: var(--lyrics-inactive-offset);
transition: transition: scale var(--lyrics-scale-duration), translate 0.3s ease-in-out;
scale var(--lyrics-scale-duration),
translate 0.3s ease-in-out;
display: block; display: block;
text-align: left; text-align: left;
@ -93,30 +126,24 @@
transform-origin: 0 50%; transform-origin: 0 50%;
} }
.text-lyrics > span { .text-lyrics > span > span {
display: inline-block; display: inline-block;
white-space: pre-wrap; white-space: pre-wrap;
opacity: var(--lyrics-inactive-opacity); opacity: var(--lyrics-inactive-opacity);
transition: opacity var(--lyrics-opacity-transition); transition: opacity var(--lyrics-opacity-transition);
} }
.previous > .text-lyrics { .current .text-lyrics {
}
.current > .text-lyrics {
font-weight: var(--lyrics-active-font-weight) !important; font-weight: var(--lyrics-active-font-weight) !important;
scale: var(--lyrics-active-scale); scale: var(--lyrics-active-scale);
translate: var(--lyrics-active-offset); translate: var(--lyrics-active-offset);
} }
.current > .text-lyrics > span { .current .text-lyrics > span > span {
opacity: var(--lyrics-active-opacity); opacity: var(--lyrics-active-opacity);
animation: var(--lyrics-animations); animation: var(--lyrics-animations);
} }
.upcoming > .text-lyrics {
}
.lyrics-renderer { .lyrics-renderer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -1,4 +1,4 @@
import { SongInfo } from '@/providers/song-info'; import type { SongInfo } from '@/providers/song-info';
export type SyncedLyricsPluginConfig = { export type SyncedLyricsPluginConfig = {
enabled: boolean; enabled: boolean;
@ -7,6 +7,7 @@ export type SyncedLyricsPluginConfig = {
defaultTextString: string; defaultTextString: string;
showLyricsEvenIfInexact: boolean; showLyricsEvenIfInexact: boolean;
lineEffect: LineEffect; lineEffect: LineEffect;
romanization: boolean;
}; };
export type LineLyricsStatus = 'previous' | 'current' | 'upcoming'; export type LineLyricsStatus = 'previous' | 'current' | 'upcoming';

View File

@ -0,0 +1,78 @@
import style from './style.css?inline';
import { createPlugin } from '@/utils';
import { t } from '@/i18n';
const handlePlay = (e: MouseEvent) => {
if (!(e.target instanceof HTMLElement)) return;
if (
e.target.closest('ytmusic-play-button-renderer') &&
!e.target.closest('ytmusic-player-page')
) {
document.body.classList.add('unobtrusive-player--did-play');
}
if (
e.target.closest('ytmusic-player-bar') &&
!document.body.classList.contains('unobtrusive-player--auto-closing')
) {
document.body.classList.remove('unobtrusive-player--did-play');
}
};
const handleVideoDataChange = () => {
const isPlayerPageOpen =
document
.querySelector('ytmusic-app-layout')
?.attributes.getNamedItem('player-ui-state')?.value ===
'PLAYER_PAGE_OPEN';
if (
document.body.classList.contains('unobtrusive-player--did-play') &&
isPlayerPageOpen
) {
document.body.classList.add('unobtrusive-player--auto-closing');
document
.querySelector<HTMLButtonElement>('.toggle-player-page-button')
?.click();
// prevent animation flickering
setTimeout(() => {
document.body.classList.remove('unobtrusive-player--auto-closing');
}, 500);
}
};
export default createPlugin({
name: () => t('plugins.unobtrusive-player.name'),
description: () => t('plugins.unobtrusive-player.description'),
addedVersion: '3.8.x',
restartNeeded: false,
config: {
enabled: false,
},
stylesheets: [style],
renderer: {
start: () => {
document.body.classList.add('unobtrusive-player');
document.addEventListener('click', handlePlay);
},
onPlayerApiReady: () => {
// Close player page when video changes while
// `unobtrusive-player--did-play` className is present.
document.addEventListener('videodatachange', handleVideoDataChange);
},
stop: () => {
document.removeEventListener('click', handlePlay);
document.removeEventListener('videodatachange', handleVideoDataChange);
[
'unobtrusive-player',
'unobtrusive-player--did-play',
'unobtrusive-player--auto-closing',
].forEach((className) => document.body.classList.remove(className));
},
},
});

View File

@ -0,0 +1,27 @@
body.unobtrusive-player.unobtrusive-player--did-play {
overflow: visible !important;
& ytmusic-player-page,
ytmusic-player-page * {
visibility: hidden !important;
}
& #content {
visibility: visible !important;
}
&
ytmusic-app-layout:not(.content-scrolled)
#nav-bar-background.ytmusic-app-layout,
ytmusic-app-layout:not(.content-scrolled) #nav-bar-divider.ytmusic-app-layout,
ytmusic-app-layout[is-bauhaus-sidenav-enabled][player-page-open]:not(
.content-scrolled
)
#mini-guide-background.ytmusic-app-layout {
opacity: 0 !important;
}
& .toggle-player-page-button {
transform: rotate(180deg) !important;
}
}

View File

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

View File

@ -62,6 +62,9 @@ export default (win: BrowserWindow) => {
win.webContents.send('ytmd:seek-by', seconds); win.webContents.send('ytmd:seek-by', seconds);
} }
}, },
requestShuffleInformation: () => {
win.webContents.send('ytmd:get-shuffle');
},
shuffle: () => win.webContents.send('ytmd:shuffle'), shuffle: () => win.webContents.send('ytmd:shuffle'),
switchRepeat: (n: ArgsType<number> = 1) => { switchRepeat: (n: ArgsType<number> = 1) => {
const repeat = parseNumberFromArgsType(n); const repeat = parseNumberFromArgsType(n);
@ -97,11 +100,15 @@ export default (win: BrowserWindow) => {
}); });
}, },
// Queue // Queue
addSongToQueue: (videoId: string) => { addSongToQueue: (videoId: string, queueInsertPosition: string) => {
const videoIdValue = parseStringFromArgsType(videoId); const videoIdValue = parseStringFromArgsType(videoId);
if (videoIdValue === null) return; if (videoIdValue === null) return;
win.webContents.send('ytmd:add-to-queue', videoIdValue); win.webContents.send(
'ytmd:add-to-queue',
videoIdValue,
queueInsertPosition,
);
}, },
moveSongInQueue: ( moveSongInQueue: (
fromIndex: ArgsType<number>, fromIndex: ArgsType<number>,

View File

@ -87,6 +87,28 @@ export const setupVolumeChangedListener = singleton((api: YoutubePlayer) => {
window.ipcRenderer.send('ytmd:volume-changed', api.getVolume()); window.ipcRenderer.send('ytmd:volume-changed', api.getVolume());
}); });
export const setupShuffleChangedListener = singleton(() => {
const playerBar = document.querySelector('ytmusic-player-bar');
if (!playerBar) {
window.ipcRenderer.send('ytmd:shuffle-changed-supported', false);
return;
}
const observer = new MutationObserver(() => {
window.ipcRenderer.send(
'ytmd:shuffle-changed',
(playerBar?.attributes.getNamedItem('shuffle-on') ?? null) !== null,
);
});
observer.observe(playerBar, {
attributes: true,
childList: false,
subtree: false,
});
});
export const setupFullScreenChangedListener = singleton(() => { export const setupFullScreenChangedListener = singleton(() => {
const playerBar = document.querySelector('ytmusic-player-bar'); const playerBar = document.querySelector('ytmusic-player-bar');
@ -139,6 +161,10 @@ export default (api: YoutubePlayer) => {
setupVolumeChangedListener(api); setupVolumeChangedListener(api);
}); });
window.ipcRenderer.on('ytmd:setup-shuffle-changed-listener', () => {
setupShuffleChangedListener();
});
window.ipcRenderer.on('ytmd:setup-fullscreen-changed-listener', () => { window.ipcRenderer.on('ytmd:setup-fullscreen-changed-listener', () => {
setupFullScreenChangedListener(); setupFullScreenChangedListener();
}); });

View File

@ -28,6 +28,7 @@ export enum MediaType {
export interface SongInfo { export interface SongInfo {
title: string; title: string;
alternativeTitle?: string;
artist: string; artist: string;
views: number; views: number;
uploadDate?: string; uploadDate?: string;
@ -68,6 +69,7 @@ const handleData = async (
// Fill songInfo with empty values // Fill songInfo with empty values
const songInfo: SongInfo = { const songInfo: SongInfo = {
title: '', title: '',
alternativeTitle: '',
artist: '', artist: '',
views: 0, views: 0,
uploadDate: '', uploadDate: '',
@ -91,6 +93,9 @@ const handleData = async (
new URL(microformat.urlCanonical).searchParams.get('list') ?? ''; new URL(microformat.urlCanonical).searchParams.get('list') ?? '';
// Used for options.resumeOnStart // Used for options.resumeOnStart
config.set('url', microformat.urlCanonical); config.set('url', microformat.urlCanonical);
songInfo.alternativeTitle = microformat.linkAlternates.find(
(link) => link.title,
)?.title;
} }
const { videoDetails } = data; const { videoDetails } = data;

View File

@ -80,6 +80,20 @@ async function onApiLoaded() {
>('ytmusic-player-bar') >('ytmusic-player-bar')
?.queue.shuffle(); ?.queue.shuffle();
}); });
const isShuffled = () => {
const isShuffled =
document
.querySelector<HTMLElement>('ytmusic-player-bar')
?.attributes.getNamedItem('shuffle-on') ?? null;
return isShuffled !== null;
};
window.ipcRenderer.on('ytmd:get-shuffle', () => {
window.ipcRenderer.send('ytmd:get-shuffle-response', isShuffled());
});
window.ipcRenderer.on( window.ipcRenderer.on(
'ytmd:update-like', 'ytmd:update-like',
(_, status: 'LIKE' | 'DISLIKE' = 'LIKE') => { (_, status: 'LIKE' | 'DISLIKE' = 'LIKE') => {
@ -143,9 +157,9 @@ async function onApiLoaded() {
window.ipcRenderer.on('ytmd:toggle-mute', (_) => { window.ipcRenderer.on('ytmd:toggle-mute', (_) => {
document document
.querySelector< .querySelector<
HTMLElement & { onVolumeTap: () => void } HTMLElement & { onVolumeClick: () => void }
>('ytmusic-player-bar') >('ytmusic-player-bar')
?.onVolumeTap(); ?.onVolumeClick();
}); });
window.ipcRenderer.on('ytmd:get-queue', () => { window.ipcRenderer.on('ytmd:get-queue', () => {
@ -157,46 +171,61 @@ async function onApiLoaded() {
} satisfies QueueResponse); } satisfies QueueResponse);
}); });
window.ipcRenderer.on('ytmd:add-to-queue', (_, videoId: string) => { window.ipcRenderer.on(
const queue = document.querySelector<QueueElement>('#queue'); 'ytmd:add-to-queue',
const app = document.querySelector<YouTubeMusicAppElement>('ytmusic-app'); (_, videoId: string, queueInsertPosition: string) => {
if (!app) return; const queue = document.querySelector<QueueElement>('#queue');
const app = document.querySelector<YouTubeMusicAppElement>('ytmusic-app');
if (!app) return;
const store = queue?.queue.store.store; const store = queue?.queue.store.store;
if (!store) return; if (!store) return;
app.networkManager app.networkManager
.fetch('/music/get_queue', { .fetch('/music/get_queue', {
queueContextParams: store.getState().queue.queueContextParams, queueContextParams: store.getState().queue.queueContextParams,
queueInsertPosition: 'INSERT_AT_END', queueInsertPosition,
videoIds: [videoId], videoIds: [videoId],
}) })
.then((result) => { .then((result) => {
if ( if (
result && result &&
typeof result === 'object' && typeof result === 'object' &&
'queueDatas' in result && 'queueDatas' in result &&
Array.isArray(result.queueDatas) Array.isArray(result.queueDatas)
) { ) {
queue?.dispatch({ const queueItems = store.getState().queue.items;
type: 'ADD_ITEMS', const queueItemsLength = queueItems.length ?? 0;
payload: { queue?.dispatch({
nextQueueItemId: store.getState().queue.nextQueueItemId, type: 'ADD_ITEMS',
index: store.getState().queue.items.length ?? 0, payload: {
items: result.queueDatas nextQueueItemId: store.getState().queue.nextQueueItemId,
.map((it) => index:
typeof it === 'object' && it && 'content' in it queueInsertPosition === 'INSERT_AFTER_CURRENT_VIDEO'
? it.content ? queueItems.findIndex(
: null, (it) =>
) (
.filter(Boolean), it.playlistPanelVideoRenderer ||
shuffleEnabled: false, it.playlistPanelVideoWrapperRenderer
shouldAssignIds: true, ?.primaryRenderer.playlistPanelVideoRenderer
}, )?.selected,
}); ) + 1 || queueItemsLength
} : queueItemsLength,
}); items: result.queueDatas
}); .map((it) =>
typeof it === 'object' && it && 'content' in it
? it.content
: null,
)
.filter(Boolean),
shuffleEnabled: false,
shouldAssignIds: true,
},
});
}
});
},
);
window.ipcRenderer.on( window.ipcRenderer.on(
'ytmd:move-in-queue', 'ytmd:move-in-queue',
(_, fromIndex: number, toIndex: number) => { (_, fromIndex: number, toIndex: number) => {

View File

@ -0,0 +1,12 @@
// Stolen from https://github.com/hexenq/kuroshiro-analyzer-kuromoji/pull/7
// Credit goes to https://github.com/ALOHACREPES345
declare class KuromojiAnalyzer {
constructor(dictPath?: { dictPath: string });
init(): Promise<void>;
parse(str: string): Promise<unknown>;
}
declare module 'kuroshiro-analyzer-kuromoji' {
export = KuromojiAnalyzer;
}

40
src/ts-declarations/kuroshiro.d.ts vendored Normal file
View File

@ -0,0 +1,40 @@
// Stolen from https://github.com/hexenq/kuroshiro/pull/93
// Credit goes to https://github.com/ALOHACREPES345 and https://github.com/lcsvcn
declare class Kuroshiro {
constructor();
_analyzer: import('kuroshiro-analyzer-kuromoji') | null;
init(analyzer: import('kuroshiro-analyzer-kuromoji')): Promise<void>;
convert(
str: string,
options?: {
to?: 'hiragana' | 'katakana' | 'romaji';
mode?: 'normal' | 'spaced' | 'okurigana' | 'furigana';
romajiSystem?: 'nippon' | 'passport' | 'hepburn';
delimiter_start?: string;
delimiter_end?: string;
},
): Promise<string>;
static Util: {
isHiragana: (ch: string) => boolean;
isKatakana: (ch: string) => boolean;
isKana: (ch: string) => boolean;
isKanji: (ch: string) => boolean;
isJapanese: (ch: string) => boolean;
hasHiragana: (str: string) => boolean;
hasKatakana: (str: string) => boolean;
hasKana: (str: string) => boolean;
hasKanji: (str: string) => boolean;
hasJapanese: (str: string) => boolean;
kanaToHiragana: (str: string) => string;
kanaToKatakana: (str: string) => string;
kanaToRomaji: (
str: string,
system: 'nippon' | 'passport' | 'hepburn',
) => string;
};
}
declare module 'kuroshiro' {
export = Kuroshiro;
}

View File

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

View File

@ -7,17 +7,17 @@ import { Project } from 'ts-morph';
const snakeToCamel = (text: string) => const snakeToCamel = (text: string) =>
text.replace(/-(\w)/g, (_, letter: string) => letter.toUpperCase()); 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 = ( export const pluginVirtualModuleGenerator = (
mode: 'main' | 'preload' | 'renderer', 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 srcPath = resolve(__dirname, '..', 'src');
const plugins = globSync([ const plugins = globSync([
'src/plugins/*/index.{js,ts}', 'src/plugins/*/index.{js,ts}',
@ -35,35 +35,39 @@ export const pluginVirtualModuleGenerator = (
return { name, path }; return { name, path };
}); });
const src = project.createSourceFile('vm:pluginIndexes', (writer) => { const src = globalProject.createSourceFile(
// prettier-ignore 'vm:pluginIndexes',
for (const { name, path } of plugins) { (writer) => {
// prettier-ignore
for (const { name, path } of plugins) {
const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/'); const relativePath = relative(resolve(srcPath, '..'), path).replace(/\\/g, '/');
writer.writeLine(`import ${snakeToCamel(name)}Plugin, { pluginStub as ${snakeToCamel(name)}PluginStub } from "./${relativePath}";`); writer.writeLine(`import ${snakeToCamel(name)}Plugin, { pluginStub as ${snakeToCamel(name)}PluginStub } from "./${relativePath}";`);
} }
writer.blankLine(); writer.blankLine();
// Context-specific exports // Context-specific exports
writer.writeLine(`export const ${mode}Plugins = {`); writer.writeLine(`export const ${mode}Plugins = {`);
for (const { name } of plugins) { for (const { name } of plugins) {
const checkMode = mode === 'main' ? 'backend' : mode; const checkMode = mode === 'main' ? 'backend' : mode;
// HACK: To avoid situation like importing renderer plugins in main // HACK: To avoid situation like importing renderer plugins in main
writer.writeLine( writer.writeLine(
` ...(${snakeToCamel(name)}Plugin['${checkMode}'] ? { "${name}": ${snakeToCamel(name)}Plugin } : {}),`, ` ...(${snakeToCamel(name)}Plugin['${checkMode}'] ? { "${name}": ${snakeToCamel(name)}Plugin } : {}),`,
); );
} }
writer.writeLine('};'); writer.writeLine('};');
writer.blankLine(); writer.blankLine();
// All plugins export (stub only) // Omit<Plugin, 'backend' | 'preload' | 'renderer'> // All plugins export (stub only) // Omit<Plugin, 'backend' | 'preload' | 'renderer'>
writer.writeLine('export const allPlugins = {'); writer.writeLine('export const allPlugins = {');
for (const { name } of plugins) { for (const { name } of plugins) {
writer.writeLine(` "${name}": ${snakeToCamel(name)}PluginStub,`); writer.writeLine(` "${name}": ${snakeToCamel(name)}PluginStub,`);
} }
writer.writeLine('};'); writer.writeLine('};');
writer.blankLine(); writer.blankLine();
}); },
{ overwrite: true },
);
return src.getText(); 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 { resolve, basename, dirname } from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
@ -8,10 +8,34 @@ import {
ts, ts,
ObjectLiteralExpression, ObjectLiteralExpression,
VariableDeclarationKind, VariableDeclarationKind,
Node,
type ObjectLiteralElementLike,
} from 'ts-morph'; } from 'ts-morph';
import type { PluginOption } from 'vite'; 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 ( export default function (
mode: 'backend' | 'preload' | 'renderer' | 'none', mode: 'backend' | 'preload' | 'renderer' | 'none',
): PluginOption { ): PluginOption {
@ -22,131 +46,96 @@ export default function (
return { return {
name: 'ytm-plugin-loader', name: 'ytm-plugin-loader',
async load(id) { load(id) {
if (!pluginFilter(id)) return null; if (!pluginFilter(id)) return null;
const __dirname = dirname(fileURLToPath(import.meta.url)); // Read file asynchronously
const fileContent = readFileSync(id, 'utf8');
const project = new Project({ // Create or update source file in the global project instance
tsConfigFilePath: resolve(__dirname, '..', 'tsconfig.json'), const src = globalProject.createSourceFile(
skipAddingFilesFromTsConfig: true,
skipLoadingLibFiles: true,
skipFileDependencyResolution: true,
});
const src = project.createSourceFile(
'_pf' + basename(id), '_pf' + basename(id),
await readFile(id, 'utf8'), fileContent,
{ overwrite: true },
); );
const exports = src.getExportedDeclarations(); const exports = src.getExportedDeclarations();
let objExpr: ObjectLiteralExpression | undefined = undefined; let objExpr: ObjectLiteralExpression | undefined;
for (const [name, [expr]] of exports) { // Identify the default export as an object literal, or via a 'createPlugin' call
if (name !== 'default') continue; for (const [exportName, declarations] of exports) {
if (exportName !== 'default') continue;
switch (expr.getKind()) { const expr = declarations[0];
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;
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]; const arg = callExpr.getArguments()[0];
if (arg.getKind() !== ts.SyntaxKind.ObjectLiteralExpression) if (arg.getKind() === ts.SyntaxKind.ObjectLiteralExpression) {
continue; objExpr = arg.asKindOrThrow(
ts.SyntaxKind.ObjectLiteralExpression,
objExpr = arg.asKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression); );
break; break;
}
} }
} }
} }
if (!objExpr) return null; if (!objExpr) return null;
const properties = objExpr.getProperties(); // Build a map of property names to their AST nodes for fast lookup
const propertyNames = properties.map((prop) => { const propMap = new Map<string, ObjectLiteralElementLike>();
switch (prop.getKind()) { for (const prop of objExpr.getProperties()) {
case ts.SyntaxKind.PropertyAssignment: const name = getPropertyName(prop);
return prop if (name) propMap.set(name, 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');
}
});
const contexts = ['backend', 'preload', 'renderer', 'menu']; const contexts = ['backend', 'preload', 'renderer', 'menu'];
for (const ctx of contexts) { for (const ctx of contexts) {
if (mode === 'none') { if (mode === 'none' && propMap.has(ctx)) {
const index = propertyNames.indexOf(ctx); propMap.get(ctx)?.remove();
if (index === -1) continue;
objExpr.getProperty(propertyNames[index])?.remove();
continue; continue;
} }
if (ctx === mode || (ctx === 'menu' && mode === 'backend')) continue;
if (ctx === mode) continue; if (propMap.has(ctx)) propMap.get(ctx)?.remove();
if (ctx === 'menu' && mode === 'backend') continue;
const index = propertyNames.indexOf(ctx);
if (index === -1) continue;
objExpr.getProperty(propertyNames[index])?.remove();
} }
const stubObjExpr = src // Add an exported variable 'pluginStub' with the modified object literal's text
.addVariableStatement({ const varStmt = src.addVariableStatement({
isExported: true, isExported: true,
declarationKind: VariableDeclarationKind.Const, declarationKind: VariableDeclarationKind.Const,
declarations: [ declarations: [
{ {
name: 'pluginStub', name: 'pluginStub',
initializer: (writer) => writer.write(objExpr.getText()), 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');
}
}); });
const stubObjExpr = varStmt
.getDeclarations()[0]
.getInitializerIfKindOrThrow(ts.SyntaxKind.ObjectLiteralExpression);
if (mode === 'backend') contexts.pop(); // Similarly build a map for the stub properties
for (const ctx of contexts) { const stubMap = new Map<string, ObjectLiteralElementLike>();
const index = stubPropertyNames.indexOf(ctx); for (const prop of stubObjExpr.getProperties()) {
if (index === -1) continue; 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 { return {

381
web/youtube-music-hu.svg Normal file
View File

@ -0,0 +1,381 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 800 300" width="800" height="300"><script xmlns="" id="eppiocemhmnlbhjplcgkofciiegomcon"/><script xmlns=""/><script xmlns=""/>
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml" bis_skin_checked="1">
<style>
.container {
width: 100%;
position: relative;
overflow: hidden;
}
a {
text-decoration: none;
}
h1.main, p.demos {
-webkit-animation-delay: 18s;
-moz-animation-delay: 18s;
-ms-animation-delay: 18s;
animation-delay: 18s;
}
.container {
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 0;
}
.content {
position: absolute;
width: 100%;
height: 100%;
left: 0px;
top: 0px;
z-index: 1000;
}
.container h2 {
position: absolute;
top: 50%;
line-height: 100px;
height: 90px;
margin-top: -90px;
font-size: 90px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple
Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
width: 100%;
text-align: center;
color: transparent;
-webkit-animation: blurFadeInOut 3s ease-in backwards;
-moz-animation: blurFadeInOut 3s ease-in backwards;
-ms-animation: blurFadeInOut 3s ease-in backwards;
animation: blurFadeInOut 3s ease-in backwards;
}
.container h2.frame-1 {
-webkit-animation-delay: 0s;
-moz-animation-delay: 0s;
-ms-animation-delay: 0s;
animation-delay: 0s;
}
.container h2.frame-2 {
-webkit-animation-delay: 3s;
-moz-animation-delay: 3s;
-ms-animation-delay: 3s;
animation-delay: 3s;
}
.container h2.frame-3 {
-webkit-animation-delay: 6s;
-moz-animation-delay: 6s;
-ms-animation-delay: 6s;
animation-delay: 6s;
}
.container h2.frame-4 {
-webkit-animation-delay: 9s;
-moz-animation-delay: 9s;
-ms-animation-delay: 9s;
animation-delay: 9s;
}
.container h2.frame-5 {
-webkit-animation: none;
-moz-animation: none;
-ms-animation: none;
animation: none;
color: transparent;
text-shadow: 0px 0px 1px #fff;
}
.container h2.frame-5 span {
-webkit-animation: blurFadeIn 3s ease-in 12s backwards;
-moz-animation: blurFadeIn 1s ease-in 12s backwards;
-ms-animation: blurFadeIn 3s ease-in 12s backwards;
animation: blurFadeIn 3s ease-in 12s backwards;
color: transparent;
text-shadow: 0px 0px 1px #fff;
}
.container h2.frame-5 span:nth-child(2) {
-webkit-animation-delay: 13s;
-moz-animation-delay: 13s;
-ms-animation-delay: 13s;
animation-delay: 13s;
}
.container h2.frame-5 span:nth-child(3) {
-webkit-animation-delay: 14s;
-moz-animation-delay: 14s;
-ms-animation-delay: 14s;
animation-delay: 14s;
}
.circle-link {
position: absolute;
left: 50%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple
Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
bottom: 50px;
margin-left: -100px;
text-align: center;
line-height: 200px;
width: 200px;
height: 200px;
background: #cc0000;
color: #fff;
font-size: 25px;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
-webkit-animation: fadeInRotate 0.8s ease 16s backwards;
-moz-animation: fadeInRotate 0.8s ease 16s backwards;
-ms-animation: fadeInRotate 0.8s ease 16s backwards;
animation: fadeInRotate 0.8s ease 16s backwards;
-webkit-transform: scale(1) rotate(0deg);
-moz-transform: scale(1) rotate(0deg);
-o-transform: scale(1) rotate(0deg);
-ms-transform: scale(1) rotate(0deg);
transform: scale(1) rotate(0deg);
background-repeat: no-repeat;
background-position: -250px -250px, 0 0;
background-image: -webkit-linear-gradient(
top left,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.2) 37%,
rgba(255, 255, 255, 0.8) 45%,
rgba(255, 255, 255, 0.0) 50%
);
background-image: -moz-linear-gradient(
0 0,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.2) 37%,
rgba(255, 255, 255, 0.8) 45%,
rgba(255, 255, 255, 0.0) 50%
);
background-image: -o-linear-gradient(
0 0,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.2) 37%,
rgba(255, 255, 255, 0.8) 45%,
rgba(255, 255, 255, 0.0) 50%
);
background-image: linear-gradient(
0 0,
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0.2) 37%,
rgba(255, 255, 255, 0.8) 45%,
rgba(255, 255, 255, 0.0) 50%
);
-moz-background-size: 250% 250%, 100% 100%;
background-size: 250% 250%, 100% 100%;
-webkit-transition: background-position 0s ease;
-moz-transition: background-position 0s ease;
-o-transition: background-position 0s ease;
transition: background-position 0s ease;
}
.circle-link:hover {
background-position: 0 0, 0 0;
-webkit-transition-duration: 0.5s;
-moz-transition-duration: 0.5s;
transition-duration: 0.5s;
}
@-webkit-keyframes blurFadeInOut {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
-webkit-transform: scale(1.3);
}
20%, 75% {
opacity: 1;
color: #cc0000;
text-shadow: 0px 0px 1px #fff;
-webkit-transform: scale(1);
}
100% {
opacity: 0;
text-shadow: 0px 0px 50px #fff;
-webkit-transform: scale(0);
}
}
@-webkit-keyframes blurFadeIn {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
-webkit-transform: scale(1.3);
}
50% {
opacity: 0.5;
color: #cc0000;
text-shadow: 0px 0px 10px #fff;
-webkit-transform: scale(1.1);
}
100% {
opacity: 1;
text-shadow: 0px 0px 1px #fff;
-webkit-transform: scale(1);
}
}
@-webkit-keyframes fadeInBack {
0% {
opacity: 0;
-webkit-transform: scale(0);
}
50% {
opacity: 0.4;
-webkit-transform: scale(2);
}
100% {
opacity: 0.2;
-webkit-transform: scale(5);
}
}
@-webkit-keyframes fadeInRotate {
0% {
opacity: 0;
-webkit-transform: scale(0) rotate(360deg);
}
100% {
opacity: 1;
-webkit-transform: scale(1) rotate(0deg);
}
}
@-moz-keyframes blurFadeInOut {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
-moz-transform: scale(1.3);
}
20%, 75% {
opacity: 1;
color: #cc0000;
text-shadow: 0px 0px 1px #fff;
-moz-transform: scale(1);
}
100% {
opacity: 0;
text-shadow: 0px 0px 50px #fff;
-moz-transform: scale(0);
}
}
@-moz-keyframes blurFadeIn {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
-moz-transform: scale(1.3);
}
100% {
opacity: 1;
text-shadow: 0px 0px 1px #fff;
-moz-transform: scale(1);
}
}
@-moz-keyframes fadeInBack {
0% {
opacity: 0;
-moz-transform: scale(0);
}
50% {
opacity: 0.4;
-moz-transform: scale(2);
}
100% {
opacity: 0.2;
-moz-transform: scale(5);
}
}
@-moz-keyframes fadeInRotate {
0% {
opacity: 0;
-moz-transform: scale(0) rotate(360deg);
}
100% {
opacity: 1;
-moz-transform: scale(1) rotate(0deg);
}
}
@keyframes blurFadeInOut {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
transform: scale(1.3);
}
20%, 75% {
opacity: 1;
color: #cc0000;
text-shadow: 0px 0px 1px #fff;
transform: scale(1);
}
100% {
opacity: 0;
text-shadow: 0px 0px 50px #fff;
transform: scale(0);
}
}
@keyframes blurFadeIn {
0% {
opacity: 0;
color: #cc0000;
text-shadow: 0px 0px 40px #fff;
transform: scale(1.3);
}
50% {
opacity: 0.5;
color: #cc0000;
text-shadow: 0px 0px 10px #fff;
transform: scale(1.1);
}
100% {
opacity: 1;
text-shadow: 0px 0px 1px #fff;
transform: scale(1);
}
}
@keyframes fadeInBack {
0% {
opacity: 0;
transform: scale(0);
}
50% {
opacity: 0.4;
transform: scale(2);
}
100% {
opacity: 0.2;
transform: scale(5);
}
}
@keyframes fadeInRotate {
0% {
opacity: 0;
transform: scale(0) rotate(360deg);
}
100% {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
</style>
<div class="container" bis_skin_checked="1">
<div class="content" bis_skin_checked="1">
<h2 class="frame-1">YouTube Music Asztali Alkalmazás</h2>
<h2 class="frame-2">Beépített reklámblokkolóval</h2>
<h2 class="frame-3">És beépített letöltővel</h2>
<h2 class="frame-4">Többplatformos</h2>
<h2 class="frame-5">
<span>Ingyenes,</span>
<span>Nyílt forráskódú</span>
</h2>
<a class="circle-link" href="https://github.com/th-ch/youtube-music/releases/latest">
Letöltés
</a>
</div>
</div>
</div>
</foreignObject>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB