Compare commits

...

127 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
65 changed files with 5416 additions and 1842 deletions

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), [🇭🇺](./docs/readme/README-hu.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: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -2,8 +2,39 @@
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) #### [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) - 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 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) - chore(deps): update dependency @babel/runtime to v7.26.9 [`#2980`](https://github.com/th-ch/youtube-music/pull/2980)

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 :**

View File

@ -21,7 +21,7 @@
</a> </a>
</div> </div>
Olvasd el más nyelveken: [🏴 Angol](./blob/master/README.md), [🇰🇷 Korea](./docs/readme/README-ko.md), [🇮🇸 Izland](./docs/readme/README-is.md), [🇪🇸 Spanyol](./docs/readme/README-es.md), [🇷🇺 Orosz](./docs/readme/README-ru.md) 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:** **Electron keretrendszerre épülő alkalmazás a YouTube Music számára, amely a következőket kínálja:**

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

@ -21,7 +21,7 @@
</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 с поддержкой:**

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';

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.3", "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",
@ -218,21 +218,21 @@
}, },
"engines": { "engines": {
"node": ">=18", "node": ">=18",
"pnpm": ">=8" "pnpm": ">=10"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"vite": "6.1.0", "vite": "6.2.3",
"node-gyp": "11.1.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.9" "@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@26.0.6": "patches/app-builder-lib@26.0.6.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": [] "neverBuiltDependencies": []
}, },
@ -245,97 +245,105 @@
"@foobar404/wave": "2.0.5", "@foobar404/wave": "2.0.5",
"@ghostery/adblocker-electron": "2.5.0", "@ghostery/adblocker-electron": "2.5.0",
"@ghostery/adblocker-electron-preload": "2.5.0", "@ghostery/adblocker-electron-preload": "2.5.0",
"@hono/node-server": "1.13.8", "@hono/node-server": "1.14.0",
"@hono/swagger-ui": "0.5.0", "@hono/swagger-ui": "0.5.1",
"@hono/zod-openapi": "0.18.4", "@hono/zod-openapi": "0.19.2",
"@hono/zod-validator": "0.4.3", "@hono/zod-validator": "0.4.3",
"@jellybrick/dbus-next": "0.10.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.5", "@jellybrick/mpris-service": "2.1.5",
"@jimp/plugin-color": "1.6.0", "@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.1.3", "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": "5.0.0", "color": "5.0.0",
"conf": "13.1.0", "conf": "13.1.0",
"custom-electron-prompt": "1.5.8", "custom-electron-prompt": "1.5.8",
"deepmerge-ts": "7.1.4", "deepmerge-ts": "7.1.5",
"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.1", "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-average-color": "9.5.0",
"fast-equals": "5.2.2", "fast-equals": "5.2.2",
"filenamify": "6.0.0", "filenamify": "6.0.0",
"happy-dom": "17.1.0", "hanja": "1.1.4",
"hono": "4.7.1", "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.2", "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.7", "node-id3": "0.2.8",
"peerjs": "1.5.4", "peerjs": "1.5.4",
"pinyin": "4.0.0-alpha.2",
"segmentit": "2.0.3",
"semver": "7.7.1", "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.4", "solid-js": "1.9.5",
"solid-styled-components": "0.28.5", "solid-styled-components": "0.28.5",
"solid-transition-group": "0.3.0", "solid-transition-group": "0.3.0",
"ts-morph": "25.0.1", "ts-morph": "25.0.1",
"vudio": "2.1.1", "vudio": "2.1.1",
"x11": "2.3.0", "x11": "2.3.0",
"youtubei.js": "13.0.0", "youtubei.js": "13.3.0",
"zod": "3.24.2" "zod": "3.24.2"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.20.0", "@eslint/js": "9.23.0",
"@playwright/test": "1.50.1", "@malept/flatpak-bundler": "0.4.0",
"@stylistic/eslint-plugin-js": "3.1.0", "@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/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.9", "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.119", "discord-api-types": "0.37.119",
"electron": "34.2.0", "electron": "35.1.0",
"electron-builder": "26.0.6", "electron-builder": "26.0.12",
"electron-builder-squirrel-windows": "26.0.6", "electron-builder-squirrel-windows": "26.0.12",
"electron-devtools-installer": "4.0.0", "electron-devtools-installer": "4.0.0",
"electron-vite": "3.0.0", "electron-vite": "3.1.0",
"esbuild": "0.25.0", "esbuild": "0.25.1",
"eslint": "9.20.1", "eslint": "9.23.0",
"eslint-config-prettier": "10.0.1", "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.8.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.3", "eslint-plugin-prettier": "5.2.5",
"glob": "11.0.1", "glob": "11.0.1",
"node-gyp": "11.1.0", "node-gyp": "11.1.0",
"playwright": "1.50.1", "playwright": "1.51.1",
"rollup": "4.34.7", "rollup": "4.37.0",
"typescript": "5.7.3", "typescript": "5.8.2",
"typescript-eslint": "8.24.0", "typescript-eslint": "8.28.0",
"utf-8-validate": "6.0.5", "utf-8-validate": "6.0.5",
"vite": "6.1.0", "vite": "6.2.3",
"vite-plugin-inspect": "10.2.1", "vite-plugin-inspect": "11.0.0",
"vite-plugin-resolve": "2.5.2", "vite-plugin-resolve": "2.5.2",
"vite-plugin-solid": "2.11.1", "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

2434
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

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

@ -683,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",

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}}%"
} }
@ -280,7 +280,7 @@
"name": "Modo ambiente" "name": "Modo ambiente"
}, },
"amuse": { "amuse": {
"description": "Agrega soporte de YouTube Music para el widget Amuse de reproduciendo ahora de 6K Labs", "description": "Agrega soporte a YouTube Music para el widget \"reproduciendo\" de Amuse por 6K Labs",
"name": "Amuse", "name": "Amuse",
"response": { "response": {
"query": "El servidor API de Amuse se está ejecutando. Usa GET /query para obtener información de la canción." "query": "El servidor API de Amuse se está ejecutando. Usa GET /query para obtener información de la canción."
@ -294,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"
} }
}, },
@ -303,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"
@ -334,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",
@ -350,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": {
@ -372,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"
} }
} }
}, },
@ -410,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:",
@ -433,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"
} }
}, },
@ -445,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"
}, },
@ -504,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": {
@ -519,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",
@ -539,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",
@ -549,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": {
@ -562,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",
@ -601,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": {
@ -610,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": {
@ -631,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",
@ -648,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"
} }
} }
@ -700,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"
@ -733,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": {
@ -758,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",
@ -778,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": {
@ -789,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

@ -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

@ -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": {
@ -727,7 +734,7 @@
"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": "⚠️\tUne erreur s'est produite en allant chercher les paroles.\n\tMerci 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

@ -86,7 +86,8 @@
"copy-current-url": "העתק את כתובת ה-URL", "copy-current-url": "העתק את כתובת ה-URL",
"go-back": "חזור אחורה", "go-back": "חזור אחורה",
"go-forward": "לך קדימה", "go-forward": "לך קדימה",
"quit": "יציאה" "quit": "יציאה",
"restart": "הפעל מחדש את היישום"
} }
}, },
"options": { "options": {
@ -96,10 +97,96 @@
"label": "אפשרויות מתקדמות", "label": "אפשרויות מתקדמות",
"submenu": { "submenu": {
"auto-reset-app-cache": "אפס את מטמון האפליקציה כאשר האפליקציה מתחילה", "auto-reset-app-cache": "אפס את מטמון האפליקציה כאשר האפליקציה מתחילה",
"disable-hardware-acceleration": "השבת האצת החומרה" "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

@ -269,6 +269,19 @@
}, },
"smoothness-transition": { "smoothness-transition": {
"label": "चिकनाई संक्रमण" "label": "चिकनाई संक्रमण"
},
"use-fullscreen": {
"label": "पूर्णस्क्रीन का उपयोग"
}
}
},
"api-server": {
"dialog": {
"request": {
"buttons": {
"allow": "अनुमति दें",
"deny": "मना करना"
}
} }
} }
}, },

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",
@ -683,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",

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"

View File

@ -1,4 +1,16 @@
{ {
"common": {
"console": {
"plugins": {
"execute-failed": "პლაგინის დაყენების შეცდომა {{pluginName}}::{{contextName}}",
"executed-at-ms": "პლაგინი {{pluginName}}::{{contextName}} გაეშვა {{ms}} მილიწამში",
"initialize-failed": "პლაგინის ინიციალიზაცია ვერ მოხდა\"{{pluginName}}\"",
"load-all": "იტვირთება ყველა პლაგინი",
"load-failed": "პლაგინის ჩატვირთვა ვერ მოხდა \"{{pluginName}}\"",
"loaded": "პლაგინი \"{{pluginName}}\" ჩაიტვირთა"
}
}
},
"language": { "language": {
"code": "ka", "code": "ka",
"local-name": "ქართული", "local-name": "ქართული",

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

@ -683,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",

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

@ -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

@ -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": {
@ -281,7 +277,6 @@
}, },
"amuse": { "amuse": {
"description": "为 6K Labs 的 Amuse 正在播放小部件添加 YouTube Music 支持", "description": "为 6K Labs 的 Amuse 正在播放小部件添加 YouTube Music 支持",
"name": "Amuse",
"response": { "response": {
"query": "Amuse API服务器已在运行。使用 /query 以获取歌曲信息。" "query": "Amuse API服务器已在运行。使用 /query 以获取歌曲信息。"
} }
@ -734,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

@ -825,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

@ -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);
@ -184,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

@ -639,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(
@ -674,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) {

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

@ -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 dir="auto" 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

@ -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,8 +26,9 @@
--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,
sans-serif;
--lyrics-font-size: clamp(1.4rem, 1.1vmax, 3rem); --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

@ -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

@ -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

@ -130,7 +130,7 @@ export default function (
const stubContexts = const stubContexts =
mode === 'backend' mode === 'backend'
? contexts.filter((ctx) => ctx !== 'backend') ? contexts.filter((ctx) => ctx !== 'menu')
: contexts; : contexts;
for (const ctx of stubContexts) { for (const ctx of stubContexts) {
if (stubMap.has(ctx)) { if (stubMap.has(ctx)) {