Compare commits

...

511 Commits

Author SHA1 Message Date
85e5e1814a Bump version to 3.3.3 2024-03-24 00:37:13 +09:00
88c84a50d0 chore(deps): update dependency electron to v29.1.5 (#1876)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-24 00:24:06 +09:00
0004fb3fc8 chore(deps): update dependency typescript to v5.4.3 (#1877)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-24 00:22:34 +09:00
9cbaf5797b chore(deps): update dependency discord-api-types to v0.37.76 (#1878)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-24 00:22:28 +09:00
1df75ae82f chore(deps): update dependency vite to v5.2.4 (#1881)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-24 00:22:22 +09:00
4d86af5437 Ambient Plugin cleanup (#1880) 2024-03-24 00:22:15 +09:00
ba0876fd8b chore(i18n): Translated using Weblate (Thai)
Currently translated at 69.5% (238 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2024-03-21 19:01:58 +01:00
a3a3fca694 chore(i18n): Translated using Weblate (Thai)
Currently translated at 69.2% (237 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2024-03-20 18:50:45 +01:00
de4396936d chore(deps): update dependency vite to v5.2.2 (#1875)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-21 00:58:59 +09:00
164575296f fix(deps): update dependency solid-js to v1.8.16 (#1873)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-20 17:36:36 +09:00
7e8cbfc4c0 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 97.3% (333 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2024-03-19 16:01:50 +01:00
679938ccf7 fix: add support for Wayland
fix #1864
2024-03-19 21:11:10 +09:00
5a6d681bf4 chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.3.1 (#1868)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 18:10:26 +09:00
62304b723e chore(deps): update dependency discord-api-types to v0.37.75 (#1867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 18:10:04 +09:00
c89bb4606f chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 12.8% (44 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-03-18 12:01:57 +01:00
14c50e0d57 chore(deps): update pnpm to v8.15.5 (#1865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-18 13:37:14 +09:00
f7e9cf9a29 fix: Fix Miniplayer image size (#1863) 2024-03-18 02:46:44 +09:00
4bb3f41828 fix(style): fixed image/video alignment when toggle is active (#1862) 2024-03-18 02:46:23 +09:00
e4759ebe25 chore(i18n): Translated using Weblate (Lithuanian)
Currently translated at 84.7% (290 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/lt/
2024-03-17 11:13:36 +01:00
ce33a92f02 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-03-17 11:13:36 +01:00
dd44c07450 chore(i18n): Translated using Weblate (Russian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-03-17 11:13:36 +01:00
15a5b7a820 chore(i18n): Translated using Weblate (German)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-03-17 11:13:36 +01:00
41b7e095eb chore: Update README-is.md (#1858) 2024-03-17 11:53:15 +09:00
f34a297fcf chore(deps): update dependency vite-plugin-solid to v2.10.2 (#1859)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-17 11:52:59 +09:00
9b2c1a320b fix: Ambient Mode intialization improvement (#1857) 2024-03-17 11:52:46 +09:00
70ed6f8e6c 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/
2024-03-17 02:01:51 +01:00
5a2489f0bf chore(i18n): Translated using Weblate (Dutch)
Currently translated at 4.9% (17 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nl/
2024-03-17 02:01:50 +01:00
a7d035022a chore(i18n): Translated using Weblate (Thai)
Currently translated at 69.0% (236 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2024-03-17 02:01:50 +01:00
b879a70b24 chore(i18n): Added translation using Weblate (Dutch) 2024-03-16 14:48:17 +01:00
ec4e9a1d47 chore(deps): bump follow-redirects from 1.15.5 to 1.15.6 (#1856)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 14:45:05 +09:00
d9c52c0a7f chore(README): Nicer Readme 2.0 (#1833) 2024-03-15 14:43:57 +09:00
81ecf18231 chore(deps): update dependency discord-api-types to v0.37.74 (#1854)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-15 14:40:22 +09:00
b0b12a075d chore(deps): update dependency esbuild to v0.20.2 (#1855)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-15 14:40:16 +09:00
54c428083c Improve ambient mode (#1853) 2024-03-15 14:39:31 +09:00
60228a387a chore(deps): update dependency electron to v29.1.4 (#1852)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-14 18:32:17 +09:00
3e04baef00 chore(deps): update dependency electron to v29.1.3 (#1851)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-14 13:34:42 +09:00
573bcba1a0 chore(i18n): Translated using Weblate (Bulgarian)
Currently translated at 25.7% (88 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/bg/
2024-03-13 18:01:58 +01:00
ae2fad5db3 chore(i18n): Translated using Weblate (French)
Currently translated at 95.6% (327 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-03-13 18:01:56 +01:00
c8fc12569c chore(deps): update dependency rollup to v4.13.0 (#1850)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-13 08:00:29 +09:00
df8efe3fa4 chore(i18n): Translated using Weblate (Bulgarian)
Currently translated at 11.1% (38 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/bg/
2024-03-12 17:01:53 +01:00
HKi
251131b9b5 chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 99.4% (340 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-03-12 17:01:53 +01:00
35fb61087a fix(deps): update dependency electron-store to v8.2.0 (#1843)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:45:40 +09:00
cbec88ff47 chore(deps): update dependency electron to v29.1.1 (#1841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:43:13 +09:00
f4319616a6 fix(deps): update dependency i18next to v23.10.1 (#1842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:43:04 +09:00
1534b7a67f chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.2.0 (#1848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:05:33 +09:00
cbfcc9d140 chore(deps): update dependency vite to v5.1.6 (#1847)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:05:27 +09:00
60d10a9222 fix(deps): update dependency async-mutex to v0.5.0 (#1849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 07:05:18 +09:00
17e090d5c5 chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 8.4% (29 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-03-11 07:01:55 +01:00
fa6b4fa83b chore(i18n): Translated using Weblate (Japanese)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-03-11 07:01:54 +01:00
e4b5244d95 fix(deps): update dependency ts-morph to v22 (#1846)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-11 08:27:01 +09:00
04dc5d6314 chore(i18n): Added translation using Weblate (Hungarian) 2024-03-10 16:54:07 +01:00
33ccb03f90 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-03-08 23:01:58 +01:00
80011ed3aa chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-03-07 20:01:57 +01:00
3e43cf5959 chore(deps): update dependency discord-api-types to v0.37.73 (#1840)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-08 04:00:53 +09:00
bbd590dde8 chore(deps): update dependency rollup to v4.12.1 (#1837)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 19:47:53 +09:00
0975a951e4 chore: Changed a single word (README-is.md) (#1836) 2024-03-07 05:27:39 +09:00
8b78f227a7 chore(deps): update dependency typescript to v5.4.2 (#1838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 05:27:06 +09:00
5a93a04b61 chore(deps): update dependency electron-vite to v2.1.0 (#1823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:47:51 +09:00
b971eb4191 chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.1.1 (#1829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:41:23 +09:00
403e825b8d chore(deps): update dependency vite to v5.1.5 (#1831)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:41:15 +09:00
9164eba88c Revert "chore(deps): update dependency electron-builder to v24.13.3" (#1818) 2024-03-03 04:56:49 +09:00
bb83bbac38 chore(deps): update dependency electron-builder to v24.13.3 (#1774)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-03 04:50:28 +09:00
651a641b22 chore: Update bug_report.yml 2024-03-02 23:56:23 +09:00
441b5fc8dd fix(style): fix navigation bar items are not working
resolve #1381
resolve #1396
resolve #1649
2024-03-02 23:51:18 +09:00
4fba9445d1 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 66.6% (228 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2024-03-02 08:07:24 +01:00
3fb5e01ca5 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-03-02 08:07:24 +01:00
09b2b0d507 chore(deps): update playwright monorepo to v1.42.1 (#1816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-02 15:31:55 +09:00
a9be35481a chore(i18n): Translated using Weblate (Romanian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ro/
2024-03-01 15:00:24 +01:00
c871506a69 chore(i18n): Translated using Weblate (Romanian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ro/
2024-03-01 15:00:24 +01:00
8e6790d366 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 66.0% (226 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2024-03-01 15:00:22 +01:00
46620c5ec9 fix(tray): fix tray icon ratio in macOS 2024-03-01 03:20:37 +09:00
5f090169da fix: Add scale ratio for tray icons (#1811) 2024-03-01 03:14:51 +09:00
2205150b86 chore(i18n): Translated using Weblate (Romanian)
Currently translated at 19.5% (67 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ro/
2024-02-29 14:48:03 +01:00
3c4bb8a8fc chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-02-29 14:48:03 +01:00
77d0e71529 chore(i18n): Added translation using Weblate (Romanian) 2024-02-29 13:18:59 +01:00
cf974e2d62 chore(i18n): Translated using Weblate (Icelandic)
Currently translated at 98.8% (338 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/is/
2024-02-29 01:02:08 +01:00
ee03db4745 fix(README-is): image path 2024-02-28 14:59:36 +09:00
efd2061058 Icelandic translation of the readme file (#1806) 2024-02-28 14:58:32 +09:00
e7ed20f62f chore(deps): update dependency electron to v29.1.0 (#1808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-28 14:58:25 +09:00
36d4c08a56 chore(deps): update playwright monorepo to v1.42.0 (#1805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-28 14:57:10 +09:00
2a939e615c chore(deps): update dependency eslint to v8.57.0 (#1793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-27 04:39:40 +09:00
9825165286 chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.1.0 (#1800)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-27 04:30:11 +09:00
55c934ac7c fix: remove possible memory leak 2024-02-27 02:42:55 +09:00
c7715115ee chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-02-26 18:01:55 +01:00
e93b5e8135 chore(deps): update dependency discord-api-types to v0.37.71 (#1799)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-27 01:20:07 +09:00
fd6ba1eda1 fix(downloader): fix memory leak reported in #1791 2024-02-26 19:14:13 +09:00
34f5411aec chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-02-25 13:02:04 +01:00
2b74ec2ef8 chore(i18n): Translated using Weblate (German)
Currently translated at 99.7% (341 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-02-25 13:02:03 +01:00
14dd0e8e03 chore(deps): update pnpm to v8.15.4 (#1795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-25 17:40:19 +09:00
b0156261b7 chore(deps): update dependency @types/semver to v7.5.8 (#1797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-25 17:40:12 +09:00
05d520f1c1 chore(i18n): Translated using Weblate (Icelandic)
Currently translated at 98.8% (338 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/is/
2024-02-23 15:02:00 +01:00
ccd44c79e8 fix: center the pause icon (#1786) 2024-02-23 22:56:40 +09:00
7be48ab05e fix(deps): update dependency @cliqz/adblocker-electron to v1.26.16 (#1788)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-23 22:56:19 +09:00
2d40b410b5 fix(deps): update dependency @cliqz/adblocker-electron-preload to v1.26.16 (#1789)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-23 22:47:34 +09:00
f54df86eec fix(deps): update dependency youtubei.js to v9.1.0 (#1790)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-23 20:55:24 +09:00
1be476de54 fix(deps): update dependency i18next to v23.10.0 (#1785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 22:17:30 +09:00
82fa8719a9 chore(i18n): Translated using Weblate (Icelandic)
Currently translated at 97.0% (332 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/is/
2024-02-22 11:02:05 +01:00
7600620c4a chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-02-22 11:02:03 +01:00
c5217f3e1e chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-02-22 11:02:03 +01:00
706279852a chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-02-22 11:02:03 +01:00
3a6274504f fix(ytm-bugs): fixed a scrollbar-color bug that affected Chromium 121 and later
fix #1737
2024-02-22 12:53:34 +09:00
3aa9398481 chore(deps): update dependency electron to v29 (#1773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 11:58:40 +09:00
7cca435b1d chore(deps): update dependency vite to v5.1.4 (#1778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 00:10:41 +09:00
241b5800d1 chore(deps): bump ip from 2.0.0 to 2.0.1 (#1777)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-21 11:02:47 +09:00
8abb8acdd3 chore(i18n): Translated using Weblate (Icelandic)
Currently translated at 19.0% (65 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/is/
2024-02-21 02:54:14 +01:00
ef8226c091 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-02-21 02:54:13 +01:00
7484e1bf9a chore(i18n): Added translation using Weblate (Icelandic) 2024-02-20 23:55:29 +01:00
2919fd54b7 Update changelog for v3.3.2 2024-02-20 12:07:35 +00:00
9eeb1c986a release 3.3.2 2024-02-20 20:59:48 +09:00
d37cd2418c fix: fix bugs in MPRIS, and improve MPRIS (#1760)
Co-authored-by: JellyBrick <shlee1503@naver.com>
Co-authored-by: Totto <32566573+Totto16@users.noreply.github.com>
2024-02-20 20:50:55 +09:00
8bd05f525d chore(deps): rollback dependency electron-builder to v24.9.1 2024-02-20 15:24:27 +09:00
47b23b414c chore(deps): update dependency electron-builder to v24.13.1 2024-02-20 14:43:04 +09:00
6f70d179c7 fix: fixed an issue that caused infinite loops when using Music Together
fix #1752
2024-02-20 12:57:49 +09:00
62a86e9267 fix(deps): update dependency electron-updater to v6.1.8 (#1770)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-20 12:55:26 +09:00
6358a2d0b1 chore(deps): update dependency electron-builder to v24.12.0 (#1771)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-20 12:55:17 +09:00
273633c2ce chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (342 of 342 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-02-20 04:15:04 +01:00
8b1209ef73 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-02-20 03:55:03 +01:00
47505e9748 chore(i18n): Translated using Weblate (German)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-02-20 03:55:03 +01:00
5178cc6bd8 feat(scrobblers): use BrowserWindow instead of shell.openExternal (#1758) 2024-02-20 11:54:57 +09:00
d9a27fff42 chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.0.2 (#1763)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-20 11:54:37 +09:00
9e6560b814 chore(i18n): Translated using Weblate (Italian)
Currently translated at 99.7% (339 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-02-19 19:01:59 +01:00
afdb19a742 chore(deps): update dependency esbuild to v0.20.1 (#1759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-19 18:23:04 +09:00
0ae5b668f5 fix(in-app-menu): default config 2024-02-19 17:06:01 +09:00
10533e28fa fix: error.html path 2024-02-19 16:53:32 +09:00
6189e67819 fix(deps): update dependency i18next to v23.9.0 (#1754)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-19 14:29:22 +09:00
f9ad505e40 fix: scrobbler migration 2024-02-19 14:27:24 +09:00
9b011101ed Update changelog for v3.3.1 2024-02-18 12:43:37 +00:00
a6ed8bf3aa release 3.3.1 (HOTFIX) 2024-02-18 21:36:04 +09:00
87acf4cf04 hotfix: in-app-menu position issue 2024-02-18 21:35:41 +09:00
b6fe2afd75 chore: Update README.md 2024-02-18 20:57:38 +09:00
6d9bb8eb1c Update changelog for v3.3.0 2024-02-18 11:40:17 +00:00
192fd0620f release 3.3.0 2024-02-18 20:32:45 +09:00
00d0b31980 fix(scrobbler): remove snake_case 2024-02-18 20:21:19 +09:00
5edb2131d2 fix(in-app-menu): implement auto close 2024-02-18 20:00:52 +09:00
4657aeca45 fix: apply fix from eslint 2024-02-18 11:58:26 +09:00
9f5651a8ba fix: fix upgrade button
fix #1199
2024-02-18 10:50:36 +09:00
570dcfee29 fix: revert fbc02a494a 2024-02-18 10:50:15 +09:00
2c130ce80d chore(mpris): use override keyword 2024-02-18 10:34:29 +09:00
8457115105 fix(mpris): fix mpris invalid position
- fix #1726
2024-02-18 10:26:45 +09:00
fbc02a494a fix(in-app-menu): simplified if-statement 2024-02-18 09:50:20 +09:00
7e2c254ecf fix(in-app-menu): should be disabled by default in linux env 2024-02-18 09:47:05 +09:00
11936a889e fix(deps): update dependency i18next to v23.8.3 (#1751)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-18 07:33:35 +09:00
f33970addd import fixed ./constants (#1748) 2024-02-18 07:33:11 +09:00
2c02b7193d chore(deps): update dependency rollup to v4.12.0 (#1743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-17 10:08:33 +09:00
3f80b598ae chore(deps): bump undici from 5.28.2 to 5.28.3 (#1747)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-17 10:07:19 +09:00
477068ed49 chore(deps): update dependency vite to v5.1.3 (#1742)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-16 08:44:31 +09:00
b4083874ac fix: invalid podcast artist name
🤦
2024-02-16 08:41:00 +09:00
c5d0673b2f chore(deps): update dependency vite-plugin-solid to v2.10.1 (#1734)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:32:18 +09:00
9ccc44474b chore(deps): update dependency discord-api-types to v0.37.70 (#1740)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:31:50 +09:00
98e341f122 chore(deps): update dependency electron to v28.2.3 (#1736)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:29:11 +09:00
b23eba51dd chore(deps): update pnpm to v8.15.3 (#1739)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:28:47 +09:00
980005a58c chore(deps): update dependency rollup to v4.11.0 (#1738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:28:41 +09:00
aba58b1d34 fix(deps): update dependency solid-js to v1.8.15 (#1735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:28:17 +09:00
bb6a127d22 chore(deps): update dependency vite to v5.1.2 (#1733)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 20:32:18 +09:00
ac6e30a6b6 chore(i18n): Translated using Weblate (Polish)
Currently translated at 98.2% (334 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-02-14 19:01:58 +01:00
3f23282eed chore(deps): update dependency vite-plugin-solid to v2.10.0 (#1732)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-14 20:36:09 +09:00
199a77819c chore(deps): update pnpm to v8.15.2 (#1729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-14 01:16:33 +09:00
89a53b2854 Update Copyright - 2024 (#1730) 2024-02-14 01:06:26 +09:00
c57bf79b08 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-02-12 23:42:44 +01:00
eabb3392b4 fix: discord RPC (fix #1664) 2024-02-13 07:41:32 +09:00
c78cc3a38d chore(deps): update dependency @typescript-eslint/eslint-plugin to v7 (#1728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 07:10:13 +09:00
011ffd538b fix(deps): update dependency @floating-ui/dom to v1.6.3 (#1727)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-13 06:41:43 +09:00
f386576196 chore(deps): update dependency electron to v28.2.2 (#1717)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-12 05:07:22 +09:00
bab3526f0f chore(deps): update dependency vite to v5.1.1 (#1718)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-12 05:07:14 +09:00
115923b422 chore(deps): update dependency @types/semver to v7.5.7 (#1724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-12 05:07:07 +09:00
fefa8c8750 fix(deps): update dependency @floating-ui/dom to v1.6.2 (#1725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-12 05:07:01 +09:00
3aa80c0f01 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-02-11 04:02:12 +01:00
aea219994a chore(deps): update dependency rollup to v4.10.0 (#1719)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-11 00:36:55 +09:00
74e22ccecd chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-02-09 17:44:03 +01:00
db09cf5ffb chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 58.8% (200 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-02-07 14:01:55 +01:00
cc1d13f203 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-02-07 14:01:54 +01:00
0cd1ce6a79 fix(deps): update dependency solid-js to v1.8.14 (#1713)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 18:00:05 +09:00
95254fc2ff chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.21.0 (#1711) 2024-02-06 05:20:13 +09:00
205376aadf fix(deps): update dependency semver to v7.6.0 (#1712) 2024-02-06 05:20:04 +09:00
6f057bfbfc fix(in-app-menu): remove unused style 2024-02-06 03:09:16 +09:00
bb39481666 fix(plugins): fix many bugs (in-app-menu, album-color-theme, blur-nav-bar) 2024-02-06 02:02:08 +09:00
ddb9968195 fix: workarounds for region restrict 2024-02-06 01:30:36 +09:00
a309729fa4 fix: revert electron version to v28 2024-02-06 01:30:09 +09:00
ba7e065ba6 fix: remove sign-in button (fix #1199) 2024-02-06 00:34:43 +09:00
ee05893d4c feat(album-color-theme): change nav-bar style 2024-02-06 00:00:32 +09:00
febc63edef fix(in-app-menu): fix app crash in production 2024-02-05 23:14:00 +09:00
b3c05c8647 refactor(in-app-menu): refactor in-app-menu plugin (#1710)
Co-authored-by: JellyBrick <shlee1503@naver.com>
2024-02-05 22:26:25 +09:00
cd8701d0e5 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-02-05 02:02:48 +01:00
3b41edb62d chore(i18n): Translated using Weblate (Japanese)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-02-05 02:02:38 +01:00
ab3b8495df chore(i18n): Translated using Weblate (Czech)
Currently translated at 89.7% (305 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-02-05 02:02:37 +01:00
b04cd79bcf chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 52.0% (177 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-02-02 15:01:47 +01:00
c864e5764a chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-02-02 15:01:47 +01:00
1f71df6c41 chore(i18n): Translated using Weblate (Russian)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-02-02 15:01:47 +01:00
0decda57ab chore(deps): update playwright monorepo to v1.41.2 (#1706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 17:47:46 +09:00
5bfd3a4562 chore(deps): update dependency electron to v29.0.0-beta.5 (#1707)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 17:47:36 +09:00
d4af820ae8 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (340 of 340 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-02-01 14:50:56 +01:00
3ec25b7779 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (338 of 338 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-02-01 14:12:03 +01:00
a9ee12b05e chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (338 of 338 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-02-01 14:12:03 +01:00
a612d1c1fd feat(album-color-theme): support album color theme in all pages (#1685) 2024-02-01 22:11:57 +09:00
fb48d24e0d fix(deps): update dependency youtubei.js to v9.0.2 (#1704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-01 15:55:16 +09:00
38d19d9ea7 fix(deps): update dependency i18next to v23.8.2 (#1702)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-01 01:55:17 +09:00
4950abc399 fix(PiP): fix multiple handler 2024-01-31 18:40:36 +09:00
e3ad804dc4 feat: Support disabling scrobbling for non-music content (#1665)
Co-authored-by: JellyBrick <shlee1503@naver.com>
2024-01-31 17:41:55 +09:00
A L
f2f15bc3cc chore(i18n): Translated using Weblate (Bulgarian)
Currently translated at 5.0% (17 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/bg/
2024-01-30 23:01:21 +01:00
4624a1022a fix(deps): update dependency youtubei.js to v9 (#1682)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 19:04:03 +09:00
A L
cc169da6d4 chore(i18n): Added translation using Weblate (Bulgarian) 2024-01-30 10:10:26 +01:00
c58ed21661 chore(deps): update dependency electron to v29.0.0-beta.4 (#1698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 09:16:36 +09:00
c483733bc3 fix(deps): update dependency i18next to v23.8.1 (#1694)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 09:13:41 +09:00
9738f2f6ae chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.20.0 (#1700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 09:10:18 +09:00
ecdd8eb9f6 chore(deps): update pnpm to v8.15.1 (#1699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-30 09:10:06 +09:00
47e2052ce0 chore(i18n): Translated using Weblate (Russian)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-01-29 19:07:33 +01:00
a34eb31d9c chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-01-29 18:47:29 +01:00
c03cab179e chore(i18n): Translated using Weblate (Russian)
Currently translated at 88.7% (299 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-01-29 18:47:29 +01:00
0d61cf906d Fix #1617
Remove duplicated call of `titleBar.appendChild(logo);`.
2024-01-29 14:50:41 +02:00
b3c1aa6b4b chore(deps): update dependency esbuild to v0.20.0 (#1691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-28 07:07:22 +09:00
4904620ce6 chore(deps): update pnpm to v8.15.0 (#1692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-28 07:07:09 +09:00
feaccb593d fix(deps): update dependency i18next to v23.7.20 (#1684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-27 18:29:12 +09:00
9ad2baea59 chore(deps): update dependency electron to v29.0.0-beta.3 (#1683)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-27 18:29:01 +09:00
df77086039 chore(deps): update dependency electron to v29.0.0-beta.2 (#1681)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-26 09:45:16 +09:00
ceb844473a chore(deps): update dependency rollup to v4.9.6 (#1663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-26 09:44:12 +09:00
a0932b0dc4 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-01-25 23:01:50 +01:00
0be37716ef chore(deps): update dependency electron to v29.0.0-beta.1 (#1670) 2024-01-26 00:17:06 +09:00
c07b05a7be fix(deps): update dependency i18next to v23.7.19 (#1680) 2024-01-26 00:16:55 +09:00
94b1da9db0 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.19.1 (#1669) 2024-01-26 00:16:28 +09:00
5fa7a1273f chore(deps): update pnpm to v8.14.3 (#1668) 2024-01-26 00:16:18 +09:00
cf9088785b chore(deps): update dependency vite-plugin-inspect to v0.8.3 (#1672) 2024-01-26 00:15:44 +09:00
adf3e3150e chore(deps): update dependency esbuild to v0.19.12 (#1673) 2024-01-26 00:13:11 +09:00
dbeb63018e fix(deps): update dependency @electron/remote to v2.1.2 (#1676) 2024-01-26 00:12:55 +09:00
51a39d240c chore: Update issue templates (#1661)
* Update bug_report.yml

* Update feature_request.yml

* Update bug_report.yml
2024-01-26 00:08:39 +09:00
4061f8e0e6 chore(i18n): Translated using Weblate (Japanese)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-01-24 14:01:53 +01:00
d32e60249a chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 52.5% (177 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-01-23 08:01:49 +01:00
b84a1e43af chore(i18n): Translated using Weblate (Thai)
Currently translated at 18.3% (62 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2024-01-23 08:01:48 +01:00
f5c22b63aa chore(i18n): Translated using Weblate (French)
Currently translated at 83.6% (282 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-01-23 08:01:47 +01:00
41700799c7 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-22 07:01:47 +01:00
b15b421975 chore(i18n): Translated using Weblate (Japanese)
Currently translated at 92.5% (312 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-01-22 07:01:47 +01:00
cca4de8684 chore(deps): update playwright monorepo to v1.41.1 (#1660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-21 12:46:32 +09:00
946c2790c4 fix(deps): update dependency i18next to v23.7.18 (#1662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-21 12:46:15 +09:00
3a033f1bab chore(deps): update actions/dependency-review-action action to v4 (#1654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-21 12:44:10 +09:00
67a04a2840 chore(deps): update dependency electron to v29.0.0-alpha.11 (#1656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-21 12:43:57 +09:00
dd48e46854 chore(deps): update dependency vite to v5.0.12 [security] (#1659)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-21 12:43:17 +09:00
99edb15c77 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 32.6% (110 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-01-21 04:29:51 +01:00
8503afeac7 chore(i18n): Translated using Weblate (Japanese)
Currently translated at 85.7% (289 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-01-21 04:29:50 +01:00
0528637135 chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 99.4% (335 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-19 09:00:21 +01:00
bf20a2b3be chore(i18n): Translated using Weblate (German)
Currently translated at 99.4% (335 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-01-19 09:00:19 +01:00
0db55ce4f3 fix(deps): update dependency async-mutex to v0.4.1 (#1653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-18 17:40:11 +09:00
21347e9d0a chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 43.3% (146 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-17 16:06:28 +01:00
4333a25c31 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-01-17 16:06:26 +01:00
5b20e491bd chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-01-17 16:06:25 +01:00
bc05f5849d chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-17 16:06:25 +01:00
b1046bc28d chore(deps): update playwright monorepo to v1.41.0 (#1651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-17 11:31:10 +09:00
d5ab36f42e fix(crossfade): fix #1633 2024-01-16 22:38:05 +09:00
922d78dcee fix: notification close 2024-01-16 21:14:37 +09:00
de6506e6b4 fix: notification closing 2024-01-16 21:13:07 +09:00
9d136c8dd5 fix: apply fix from eslint 2024-01-16 21:02:55 +09:00
26de7f940e fix: fix #1621 2024-01-16 20:34:00 +09:00
7c404ba2ea chore(song-info): fix typo 2024-01-16 19:14:16 +09:00
96d2a72bfa chore(song-info): change from array to Set
change from `array` to `Set` to prevent the duplicate callback from being stored
2024-01-16 19:13:35 +09:00
10f41bddad fix(i18n): use dash (-) instead of under-bar (_) 2024-01-16 17:36:48 +09:00
39d2f3ec80 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-01-16 09:33:15 +01:00
512b446a3d chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (337 of 337 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-01-16 09:33:15 +01:00
c9b96f0488 fix(tuna-obs): partially fix #1596 2024-01-16 17:27:27 +09:00
c84ea257d5 fix: os-specific plugin 2024-01-16 17:14:02 +09:00
6512f5ad2a fix(discord): fix hide duration button
fix #1644

Thanks to @DronovasP
2024-01-16 16:41:23 +09:00
e5d0eced5d fix(store): remove duplicated if-statement 2024-01-16 16:40:06 +09:00
f424ee5170 feat: Better Scrobbler Plugin (#1640)
Co-authored-by: JellyBrick <shlee1503@naver.com>
2024-01-16 16:36:27 +09:00
ea0f6c401d chore(deps): update dependency electron to v29.0.0-alpha.10 (#1645)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-16 14:34:05 +09:00
5c5f51b3de chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.19.0 (#1643)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-16 12:52:28 +09:00
7caf02ebba chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-16 04:06:12 +01:00
f6a444b970 chore(i18n): Translated using Weblate (Russian)
Currently translated at 73.1% (242 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-01-15 02:26:24 +01:00
d19a36b44f chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-01-15 02:26:23 +01:00
aacb126fb5 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-01-15 02:26:23 +01:00
5adf45cde2 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-01-15 02:26:23 +01:00
0980aad060 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-15 02:26:23 +01:00
069e5ac8b8 chore(README): Fix plugins names and add plugins in/to Readme (in menu too) (#1624) 2024-01-14 14:50:40 +09:00
b5f6762997 chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-01-14 06:50:01 +01:00
c2abfe4b41 chore(i18n): Translated using Weblate (Polish)
Currently translated at 91.2% (302 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-01-13 13:43:07 +01:00
3964d03a3b fix: apply fix for album-actions 2024-01-13 17:28:12 +09:00
a82c4ce499 fix(album-actions): Fixed album actions (#1639) 2024-01-13 17:08:51 +09:00
2f54fa19e6 fix(yt-music bugs): fix margin in video mode 2024-01-13 12:35:54 +09:00
aacb4b3147 fix(deps): update dependency @xhayper/discord-rpc to v1.1.2 2024-01-13 10:10:32 +09:00
60980251f2 chore: update pnpm-lock 2024-01-13 10:07:55 +09:00
f8e55f95df fix(yt-music bugs): fixed a weird margin-bottom issue when using YouTube Premium 2024-01-13 10:02:18 +09:00
bebd232af0 chore(deps): update playwright monorepo to v1.41.0-beta-1705101589000 (#1638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-13 09:08:02 +09:00
1a89fbe612 fix(#1543): fix song control doesn't work (#1637)
Co-authored-by: Su-Yong <simssy2205@gmail.com>
2024-01-13 09:06:41 +09:00
e73584c2aa feat(issue-template): add checklist 2024-01-13 07:34:00 +09:00
96a713074f chore(deps): update playwright monorepo to v1.41.0-beta-1705092460000 (#1635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-13 07:20:59 +09:00
aedfa4ca06 chore(deps): update dependency rollup to v4.9.5 (#1629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-13 07:17:58 +09:00
ac187f722b chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 29.6% (98 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-12 23:16:48 +01:00
cd87642384 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 4.5% (15 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-01-12 23:16:48 +01:00
4a736d3211 chore(i18n): Translated using Weblate (Thai)
Currently translated at 1.2% (4 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2024-01-12 23:16:48 +01:00
e586940c57 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2024-01-12 23:16:47 +01:00
ab36a21583 chore(i18n): Translated using Weblate (French)
Currently translated at 86.4% (286 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-01-12 23:16:47 +01:00
c0c1c3b626 chore(i18n): Translated using Weblate (German)
Currently translated at 91.5% (303 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-01-12 23:16:47 +01:00
918bd7fdb1 chore(deps): update dependency electron to v29.0.0-alpha.9 (#1627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-12 11:57:43 +09:00
971d1a5776 chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 16.9% (56 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-11 18:06:13 +01:00
1235d46e73 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-11 18:06:13 +01:00
451b98833b chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 99.3% (329 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2024-01-11 18:06:12 +01:00
48f9be9712 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-01-11 18:06:12 +01:00
fd8d59bada chore: update pnpm-lock 2024-01-11 08:47:46 +09:00
99ce0b7f9c chore(deps): update dependency electron to v29.0.0-alpha.8 (#1608)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 08:08:37 +09:00
88ace9ab35 fix(deps): update dependency @cliqz/adblocker-electron to v1.26.15 (#1615)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 08:06:41 +09:00
63b0ea60e4 chore(deps): update dependency rollup to v4.9.4 (#1591)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 08:02:31 +09:00
b4ecf0f935 fix(deps): update dependency @cliqz/adblocker-electron-preload to v1.26.15 (#1616)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 08:02:10 +09:00
c846f18086 chore(deps): update pnpm to v8.14.1 (#1619)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 08:02:03 +09:00
8a851b06f9 chore(deps): update dependency eslint-plugin-prettier to v5.1.3 (#1618)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 14:36:19 +09:00
5484dc8bd1 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.18.1 (#1612)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 19:36:07 +09:00
6c47ac36e3 fix(deps): update dependency youtubei.js to v8.2.0 (#1614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 19:31:02 +09:00
3554496803 chore(deps): update dependency electron-vite to v2.0.0 (#1609)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 19:30:50 +09:00
b8a197615e chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.18.0 (#1603)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-08 23:22:16 +09:00
2ed949920f chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-01-08 14:06:18 +00:00
d76f4dade3 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-01-08 14:06:17 +00:00
aacd01ce7c chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2024-01-08 14:06:16 +00:00
d501b016fc chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-01-08 14:06:14 +00:00
b1503cfb87 chore(deps): update dependency electron-vite to v2.0.0-beta.4 (#1602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-07 04:19:01 +09:00
8a004ae9dd chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-06 18:06:15 +01:00
de709cc7c9 fix: download/pip button for podcast video 2024-01-06 11:05:15 +09:00
6b7c43925a feat: rename IPC 2024-01-06 10:17:40 +09:00
5d5cc58f59 chore(tuna-obs): set keepAlive to true for reuse TCP socket 2024-01-06 09:37:47 +09:00
3e6bab7f15 fix(in-app-menu): fix invalid margin-top
fix #1597
2024-01-06 09:15:57 +09:00
7e17a8b73b fix(README): fix plugins path
fix #1598
2024-01-06 09:03:42 +09:00
129b798d8f chore(README): add demo image 2024-01-06 06:00:07 +09:00
a3a411e197 fix(config): fix duplicated array value 2024-01-06 01:07:57 +09:00
6e6acd6f19 Update changelog for v3.2.2 2024-01-05 14:44:33 +00:00
34cb79eeaf Bump version to 3.2.2 2024-01-05 23:33:42 +09:00
1c30a07031 chore(deps): update dependency playwright to v1.41.0-alpha-jan-5-2024 2024-01-05 23:30:16 +09:00
5dd5f41ef5 chore(deps): update dependency electron to v29.0.0-alpha.7
Change to electron v29 to use node.js v20.
2024-01-05 23:28:24 +09:00
45a3c11d51 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (331 of 331 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-01-05 14:24:44 +00:00
8bd3b4d3f0 fix(visualizer): fixed an issue with audio getting unusually loud 2024-01-05 23:23:39 +09:00
4e3cb5806d fix(music-together): modernize code 2024-01-05 23:11:26 +09:00
6563eb4ddd chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (330 of 330 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-05 14:02:12 +00:00
895386f6f8 fix(music-together): typing 2024-01-05 23:01:55 +09:00
3810955e56 fix(skip-silences): fix audio distorted
fix #1141
2024-01-05 21:58:36 +09:00
59c521e53f fix: download button not working 2024-01-05 21:04:52 +09:00
25d266f8f9 feat(tray): Add song info and paused icon (#1592) 2024-01-05 20:56:47 +09:00
0c3c380591 chore(deps): update dependency rollup to v4.9.3 2024-01-05 20:56:17 +09:00
a20cfa30a1 chore(deps): update dependency vite to v5.0.11 2024-01-05 20:43:13 +09:00
fefe899393 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-05 11:12:50 +01:00
55759e8d7a chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-01-05 11:12:50 +01:00
ddb561937f fix(deps): update dependency i18next to v23.7.16 2024-01-04 22:41:16 +09:00
198cb71a4c chore(deps): update dependency electron to v28.1.1 2024-01-04 22:38:45 +09:00
c34b880752 chore(deps): update dependency electron-vite to v2.0.0-beta.3 2024-01-04 22:38:30 +09:00
76944e3e41 fix(deps): update dependency i18next to v23.7.14 2024-01-03 17:35:30 +09:00
68cd76f2af chore(deps): update pnpm to v8.14.0 2024-01-03 17:35:23 +09:00
81145b52b7 fix(#1580): fix NEW badge doesn't show 2024-01-03 15:02:29 +09:00
2a19dab061 chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 3.3% (11 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-02 10:52:22 +01:00
6958d59d4f chore(i18n): Translated using Weblate (Lithuanian)
Currently translated at 89.6% (294 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/lt/
2024-01-02 09:49:04 +01:00
8a51dfad87 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 89.6% (294 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-02 09:49:04 +01:00
5bb4d9efbe chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-01-02 09:49:04 +01:00
927aa5f24b chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 89.6% (294 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2024-01-02 09:49:03 +01:00
d695bc93a1 chore(i18n): Translated using Weblate (Polish)
Currently translated at 89.3% (293 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-01-02 09:49:03 +01:00
b05fb4ccbe chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 67.9% (223 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2024-01-02 09:49:03 +01:00
299eb7e7d6 chore(i18n): Translated using Weblate (Italian)
Currently translated at 89.3% (293 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2024-01-02 09:49:03 +01:00
ae26333224 chore(i18n): Translated using Weblate (French)
Currently translated at 85.9% (282 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-01-02 09:49:03 +01:00
35176469b0 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-02 09:49:03 +01:00
4e74f9cbc5 chore(i18n): Translated using Weblate (Czech)
Currently translated at 94.8% (311 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-01-02 09:49:02 +01:00
4091b36f36 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-01-02 09:49:02 +01:00
b3f805fce6 chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 2.4% (8 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-01-02 09:43:14 +01:00
b129a3e8d8 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 89.9% (295 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-01-02 09:43:13 +01:00
64ea1fdb58 chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-01-02 09:43:13 +01:00
8fcf59ed0a chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-01-02 09:43:12 +01:00
9811ca63de chore(i18n): Translated using Weblate (Czech)
Currently translated at 94.8% (311 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-01-02 09:43:12 +01:00
9028f88299 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-01-02 09:43:12 +01:00
fd47766d93 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.17.0 2024-01-02 17:34:04 +09:00
26b12c7208 chore(i18n): Added translation using Weblate (Vietnamese) 2024-01-02 07:19:07 +01:00
8da9b3454d chore(deps): update dependency esbuild to v0.19.11 2024-01-01 20:32:13 +09:00
205cbefc83 Update changelog for v3.2.1 2024-01-01 00:32:24 +00:00
0e94c72eef Bump version to 3.2.1 2024-01-01 09:22:46 +09:00
c055641351 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-01-01 01:19:52 +01:00
c0a3aa99de chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-01-01 01:19:52 +01:00
8a8976acef chore(i18n): Translated using Weblate (Czech)
Currently translated at 94.8% (311 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-01-01 01:06:02 +01:00
e409165e1b chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2024-01-01 01:06:02 +01:00
b278140796 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/
2024-01-01 01:01:00 +01:00
397056a54d chore(i18n): Translated using Weblate (Turkish)
Currently translated at 26.5% (87 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-01-01 01:01:00 +01:00
edecd65419 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (328 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2024-01-01 01:01:00 +01:00
4d2d0b7bd6 chore(i18n): Translated using Weblate (Czech)
Currently translated at 85.6% (281 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-01-01 01:01:00 +01:00
0ca4e34efd chore(i18n): Translated using Weblate (Czech)
Currently translated at 85.6% (281 of 328 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2024-01-01 01:00:59 +01:00
43f3226c3a fix: fix #1574 2024-01-01 08:36:48 +09:00
0a6dbecc05 fix: fix #1575 2024-01-01 08:36:22 +09:00
f5aa179cd6 chore(i18n): Translated using Weblate
Co-authored-by: Allan Nordhøy <epost@anotheragency.no>
Co-authored-by: inson1 <vaclav.svarc01@seznam.cz>
Co-authored-by: Anonymous <noreply@weblate.org>
2024-01-01 04:53:59 +09:00
3140e91dda Update changelog for v3.2.0 2023-12-31 16:31:59 +00:00
022f8ff65c Merge branch 'master' of https://github.com/th-ch/youtube-music 2024-01-01 01:23:01 +09:00
5e63cc2e89 Bump version to 3.2.0 2024-01-01 01:22:48 +09:00
880ed99846 Revert "fix(deps): update dependency @xhayper/discord-rpc to v1.1.2"
This reverts commit 050d55c736.
2024-01-01 00:34:49 +09:00
222e78c85b fix(in-app-menu): fix in-app-menu tooltip position 2023-12-31 23:48:01 +09:00
050d55c736 fix(deps): update dependency @xhayper/discord-rpc to v1.1.2 2023-12-31 23:40:26 +09:00
13ef8560ff fix: pnpm build error 2023-12-31 23:40:09 +09:00
78d990c079 feat(album-color-theme): improve Album Color Theme style (#1571) 2023-12-31 23:04:44 +09:00
4d3e2c09da feat(menu): add more detail in Menu (#1570) 2023-12-31 20:56:24 +09:00
aa899d247a chore(plugins): change default config album-actions, music-together 2023-12-31 13:56:42 +09:00
ee0c512529 feat(music-together): Add new plugin Music Together (#1562)
* feat(music-together): test `peerjs`

* feat(music-together): replace `prompt` to `custom-electron-prompt`

* fix(music-together): fix

* test fix

* wow

* test

* feat(music-together): improve `onStart`

* fix: adblocker

* fix(adblock): fix crash with `peerjs`

* feat(music-together): add host UI

* feat(music-together): implement addSong, removeSong, syncQueue

* feat(music-together): inject panel

* feat(music-together): redesign music together panel

* feat(music-together): sync queue, profile

* feat(music-together): sync progress, song, state

* fix(music-together): fix some bug

* fix(music-together): fix sync queue

* feat(music-together): support i18n

* feat(music-together): improve sync queue

* feat(music-together): add profile in music item

* refactor(music-together): refactor structure

* feat(music-together): add permission

* fix(music-together): fix queue sync bug

* fix(music-together): fix some bugs

* fix(music-together): fix permission not working on guest mode

* fix(music-together): fix queue sync relate bugs

* fix(music-together): fix automix items not append using music together

* fix(music-together): fix

* feat(music-together): improve video injection

* fix(music-together): fix injection code

* fix(music-together): fix broadcast guest

* feat(music-together): add more permission

* fix(music-together): fix injector

* fix(music-together): fix guest add song logic

* feat(music-together): add popup close listener

* fix(music-together): fix connection issue

* fix(music-together): fix connection issue 2

* feat(music-together): reserve playlist

* fix(music-together): exclude automix songs

* fix(music-together): fix playlist index sync bug

* fix(music-together): fix connection failed error and sync index

* fix(music-together): fix host set index bug

* fix: apply fix from eslint

* feat(util): add `ImageElementFromSrc`

* chore(util): update jsdoc

* feat(music-together): add owner name

* chore(music-together): add translation

* feat(music-together): add progress sync

* chore(music-together): remove `console.log`

---------

Co-authored-by: JellyBrick <shlee1503@naver.com>
2023-12-31 13:52:15 +09:00
5f9b522307 chore(deps): update dependency rollup to v4.9.2 (#1567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-31 04:05:49 +09:00
c207e29980 fix(deps): update dependency i18next to v23.7.13 (#1569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-31 04:05:44 +09:00
df4d2d6b72 chore(ambient-mode): remove console.log 2023-12-31 02:28:31 +09:00
c3dd20cabd chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (296 of 296 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2023-12-30 17:09:06 +00:00
7a6db95d1a chore(i18n): Translated using Weblate (Czech)
Currently translated at 80.4% (238 of 296 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-30 17:09:05 +00:00
bc6825d63b chore(i18n): Translated using Weblate (Czech)
Currently translated at 76.8% (226 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-29 16:14:02 +01:00
5e79e9e0f2 feat: Add new plugin Album actions (#1515)
Co-authored-by: JellyBrick <shlee1503@naver.com>
2023-12-30 00:13:56 +09:00
5e303c2ba8 fix(deps): update dependency i18next to v23.7.12 (#1564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-29 22:26:41 +09:00
0bd9c16356 fix: Only apply scale factor on Windows (#1565) 2023-12-29 22:26:24 +09:00
f0f5d9da2f feat(ambient-mode): support ambient mode on Song section
resolve #1555
2023-12-29 21:46:27 +09:00
TC
f46c431f4c Move cask definition to separate repo 2023-12-29 11:26:55 +01:00
62410e9ee2 feat(in-app-menu): add show on hover 2023-12-29 17:52:31 +09:00
46f76f1408 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 3.7% (11 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2023-12-27 18:20:59 +01:00
5e071e16d8 chore(i18n): Translated using Weblate (Turkish)
Currently translated at 29.2% (86 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2023-12-27 18:20:58 +01:00
c0238588bd chore(i18n): Translated using Weblate (Russian)
Currently translated at 78.5% (231 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-27 18:20:58 +01:00
Nik
30002d660a chore(i18n): Translated using Weblate (Russian)
Currently translated at 78.5% (231 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-27 18:20:58 +01:00
48eeb6bca3 fix: picture-in-picture icon 2023-12-28 02:17:42 +09:00
e67699fed5 fix: fixed an issue with the download button disappearing
- resolve #1551
2023-12-28 02:08:03 +09:00
8aeae45965 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 77.2% (227 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2023-12-27 13:09:36 +01:00
ce7491941b chore(i18n): Translated using Weblate (Russian)
Currently translated at 74.8% (220 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-27 13:09:36 +01:00
1dce03c4f2 chore(i18n): Translated using Weblate (Polish)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2023-12-27 13:09:36 +01:00
62eae6d5d0 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.16.0 (#1556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 18:37:06 +09:00
15b2b26b84 chore(deps): update pnpm to v8.13.1 (#1557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 18:36:57 +09:00
9664c17c47 chore(deps): update dependency ws to v8.16.0 (#1559)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 18:36:51 +09:00
8067dad2fa fix(deps): update dependency youtubei.js to v8.1.0 (#1560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 18:36:42 +09:00
4dcaa510d9 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 3.7% (11 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2023-12-25 12:42:54 +01:00
b6e918089d chore(i18n): Translated using Weblate (Turkish)
Currently translated at 29.2% (86 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2023-12-25 12:42:54 +01:00
1c9e6b1bb8 chore(i18n): Translated using Weblate (Polish)
Currently translated at 97.9% (288 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2023-12-25 12:42:54 +01:00
ebd304c252 fix(deps): update dependency node-html-parser to v6.1.12 (#1554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-25 20:37:05 +09:00
36083c4173 Revert "fix(deps): update dependency @xhayper/discord-rpc to v1.1.2" (#1552) 2023-12-25 03:48:15 +09:00
a084b060d8 chore(deps): update dependency electron to v28.1.0 2023-12-25 03:32:28 +09:00
432c79b606 fix(deps): update dependency @xhayper/discord-rpc to v1.1.2 2023-12-25 03:32:07 +09:00
0f1f0ee933 chore(deps): update dependency eslint-plugin-prettier to v5.1.2 2023-12-25 03:31:59 +09:00
9b1a4b8d88 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2023-12-23 21:07:03 +01:00
1a7a665915 chore(i18n): Translated using Weblate (Czech)
Currently translated at 76.5% (225 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-22 03:06:46 +01:00
623ecf7fb8 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/
2023-12-20 17:44:47 +01:00
0dc9c6a1a9 chore(i18n): Translated using Weblate (Czech)
Currently translated at 72.7% (214 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-20 17:44:47 +01:00
72c5eaa5ff chore(i18n): Translated using Weblate (Czech)
Currently translated at 82.3% (242 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-20 13:54:56 +01:00
0f47b94b7d 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/
2023-12-20 13:53:36 +01:00
9abe15f1ad chore(i18n): Translated using Weblate (Czech)
Currently translated at 82.3% (242 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-20 13:53:35 +01:00
96afda92c8 chore(i18n): Translated using Weblate (Czech)
Currently translated at 80.9% (238 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-20 13:33:50 +01:00
5c6fd4a739 Update README-ko.md 2023-12-20 14:11:53 +02:00
23b87a876d chore(deps): update dependency eslint-plugin-prettier to v5.1.0 2023-12-20 13:59:40 +09:00
737fd05369 chore(deps): update dependency electron-vite to v2.0.0-beta.2 2023-12-20 13:59:28 +09:00
c5bcd89f16 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.15.0 2023-12-19 16:32:46 +09:00
377e1be0b2 fix(deps): update dependency @foobar404/wave to v2.0.5 2023-12-19 16:32:31 +09:00
a92049c0c9 chore(i18n): Translated using Weblate (Lithuanian)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/lt/
2023-12-19 07:21:28 +01:00
27a2955bba fix: fix homebrew cask
- resolve #1514
2023-12-18 22:02:38 +09:00
cc940e2020 Update changelog for v3.1.1 2023-12-18 12:57:28 +00:00
203c80767d Bump version to 3.1.1 2023-12-18 21:49:31 +09:00
f564039438 chore: fix the example plugins in the README 2023-12-18 14:47:18 +02:00
d6566fb870 chore(i18n): Translated using Weblate (Lithuanian)
Currently translated at 84.3% (248 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/lt/
2023-12-18 13:46:47 +01:00
55ab17e789 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2023-12-18 13:43:08 +01:00
e0eeb720cd feat: upgrade to Vite v5 2023-12-18 21:10:47 +09:00
53ac7ff257 fix: electron-vite dev --watch 2023-12-18 20:00:00 +09:00
a4e2f10afa chore(deps): update dependency playwright to v1.41.0-alpha-dec-18-2023 2023-12-18 19:58:33 +09:00
c9c9d766e6 chore(deps): update dependency rollup to v4.9.1 2023-12-18 19:56:14 +09:00
b82d161180 chore: Update bug_report.yml 2023-12-18 19:47:51 +09:00
7cadacd8cf fix: vite dev mode
fix an issue caused by da3bc5aeb7
2023-12-18 19:07:43 +09:00
fc1a7cda62 chore(i18n): Translated using Weblate (Lithuanian)
Currently translated at 84.3% (248 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/lt/
2023-12-18 10:56:31 +01:00
da3bc5aeb7 fix: renderer plugin load timing
MAGIC OF JAVASCRIPT
2023-12-18 18:42:01 +09:00
ee98344064 chore(i18n): Added translation using Weblate (Lithuanian) 2023-12-17 21:43:08 +01:00
da10eabf99 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 69.3% (204 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2023-12-17 14:55:42 +01:00
ce3c63c386 chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 73.8% (217 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2023-12-17 14:55:42 +01:00
f8c3cff5a9 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2023-12-17 14:55:41 +01:00
08f369f8bc chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 43.5% (128 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2023-12-17 08:28:44 +01:00
1517230ede chore(i18n): Translated using Weblate (German)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2023-12-17 08:28:44 +01:00
45aeadef86 fix(song-info-front): fix type 2023-12-17 16:05:26 +09:00
5ec7c346ca fix(song-info-front): fix parser to parse album name 2023-12-17 15:51:35 +09:00
4b68de1606 fix: update types 2023-12-16 22:39:57 +09:00
7710bcdacc chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2023-12-16 11:58:32 +01:00
4c19bcc983 chore(i18n): Translated using Weblate (Turkish)
Currently translated at 26.1% (77 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2023-12-16 03:33:06 +01:00
2f50b1423a chore(i18n): Translated using Weblate (French)
Currently translated at 95.9% (282 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2023-12-16 03:33:06 +01:00
15768c9691 chore(deps): update dependency eslint to v8.56.0 2023-12-16 11:28:58 +09:00
442eb75b8d chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 43.1% (127 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2023-12-16 03:09:12 +01:00
8facd27125 chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2023-12-16 03:09:11 +01:00
a302cb6ebf chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2023-12-16 03:09:11 +01:00
32422c7ba9 fix(deps): update dependency i18next to v23.7.11 2023-12-15 13:42:50 +09:00
ca131cb156 chore(deps): update dependency eslint-plugin-import to v2.29.1 2023-12-15 13:42:44 +09:00
5f8262ede1 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 65.3% (192 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2023-12-14 02:11:40 +01:00
88db9d3693 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2023-12-13 21:33:32 +01:00
0fa6f344f9 chore(i18n): Translated using Weblate (Polish)
Currently translated at 97.6% (287 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2023-12-13 21:33:31 +01:00
d1642b3dfb chore(i18n): Translated using Weblate (Polish)
Currently translated at 97.6% (287 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2023-12-13 21:33:31 +01:00
7599fce5f5 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 97.6% (287 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2023-12-13 21:33:31 +01:00
9bd0dc9a7b chore(i18n): Translated using Weblate (Greek)
Currently translated at 23.8% (70 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/el/
2023-12-13 21:33:31 +01:00
dad7cafebc chore(i18n): Translated using Weblate (Russian)
Currently translated at 72.7% (214 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-13 16:20:54 +01:00
4febb28201 chore(deps): update dependency rollup to v4.9.0 2023-12-13 21:13:41 +09:00
ced943bad3 chore(deps): update pnpm to v8.12.1 2023-12-13 21:12:07 +09:00
202b8717a2 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2023-12-13 13:10:46 +01:00
eba7026b89 chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2023-12-13 13:10:46 +01:00
6b2adca1f4 fix(downloader): fix download button i18n 2023-12-13 18:02:18 +09:00
0c9d3cc057 chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 42.8% (126 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2023-12-13 05:07:02 +01:00
45ec11aaed chore(deps): update pnpm-lock.yaml 2023-12-13 13:06:10 +09:00
4d47fa3fac fix(deps): update dependency @electron/remote to v2.1.1 2023-12-13 12:24:55 +09:00
6322d5bb09 chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 3.0% (9 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2023-12-12 21:56:36 +01:00
2e8a579049 chore(i18n): Translated using Weblate (Thai)
Currently translated at 1.0% (3 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/th/
2023-12-12 21:56:36 +01:00
9db7e99d7f chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2023-12-12 21:56:36 +01:00
ef73989995 chore(i18n): Translated using Weblate (Czech)
Currently translated at 79.9% (235 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-12 21:56:36 +01:00
61024084e9 chore(deps): update dependency ws to v8.15.1 2023-12-13 05:46:56 +09:00
1c71b2020f fix(deps): update dependency i18next to v23.7.9 2023-12-13 05:45:52 +09:00
3b2b545388 chore(i18n): Translated using Weblate (Russian)
Currently translated at 67.6% (199 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-12 21:44:51 +01:00
fafc7f94fd chore(i18n): Translated using Weblate (Italian)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2023-12-12 21:44:50 +01:00
5fa88b5ce9 fix: fix renderer plugin load timing
- fix #1522
2023-12-12 12:53:41 +09:00
a8fe4167db fix(pip): fix invalid position config 2023-12-12 11:11:41 +09:00
0e6b0ddc26 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2023-12-12 02:24:41 +01:00
af88db3865 chore(i18n): Translated using Weblate (Japanese)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2023-12-12 02:24:41 +01:00
0a1bef556c chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2023-12-12 02:24:41 +01:00
7030181dc1 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2023-12-12 02:24:41 +01:00
98cb2f61ab chore(deps): update dependency playwright to v1.41.0-alpha-dec-12-2023 2023-12-12 10:23:59 +09:00
a601d0b3d2 chore(deps): update dependency rollup to v4.8.0 2023-12-12 10:22:23 +09:00
8d18923065 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 75.1% (221 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2023-12-12 01:08:34 +01:00
4b6a7e0bd7 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2023-12-12 01:08:34 +01:00
44f87853d6 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 74.8% (220 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2023-12-12 01:02:37 +01:00
4ff47bee03 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 74.1% (218 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2023-12-12 00:54:03 +01:00
7a2c28df21 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2023-12-12 00:54:02 +01:00
f7241d1e4a chore(i18n): Added translation using Weblate (Indonesian) 2023-12-12 00:33:55 +01:00
2b5daf3a75 chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.14.0 2023-12-12 06:43:20 +09:00
d7184cf75d chore(i18n): Translated using Weblate (Russian)
Currently translated at 54.0% (159 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2023-12-11 19:59:59 +01:00
1313d18d44 chore(i18n): Translated using Weblate (Czech)
Currently translated at 80.9% (238 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2023-12-11 19:59:58 +01:00
605e9481d9 chore(i18n): Translated using Weblate (English)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/en/
2023-12-11 19:59:58 +01:00
cf4c89f825 chore(i18n): Added translation using Weblate (Thai) 2023-12-11 10:17:18 +01:00
f4f1d4d373 chore(i18n): Translated using Weblate (Norwegian Bokmål)
Currently translated at 46.2% (136 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nb_NO/
2023-12-11 09:00:43 +01:00
6557b40924 Translated using Weblate (Spanish)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2023-12-11 00:20:44 +01:00
e01a29c5d1 Translated using Weblate (Spanish)
Currently translated at 100.0% (294 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2023-12-11 00:20:44 +01:00
d9a7e16d63 Translated using Weblate (Italian)
Currently translated at 99.3% (292 of 294 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/it/
2023-12-11 00:20:44 +01:00
d170199d85 Update changelog for v3.1.0 2023-12-10 23:10:52 +00:00
162 changed files with 17160 additions and 3243 deletions

View File

@ -24,6 +24,12 @@ body:
placeholder: 2.0.0
validations:
required: true
- type: checkboxes
attributes:
label: Checklists
options:
- label: I use the portable version of the YouTube Music Application.
- label: I can reproduce this issue in the [official version of (WEB) YTM](https://music.youtube.com).
- type: dropdown
attributes:
label: What operating system are you using?
@ -44,7 +50,7 @@ body:
required: true
- type: dropdown
attributes:
label: What arch are you using?
label: What CPU architecture are you using?
options:
- x64
- ia32

View File

@ -15,7 +15,7 @@ body:
- type: textarea
attributes:
label: Problem Description
description: Please add a clear and concise description of the problem you are seeking to solve with this feature request.
description: A clear and concise description of the problem you are seeking to solve with this feature request.
validations:
required: true
- type: textarea
@ -33,6 +33,6 @@ body:
- type: textarea
attributes:
label: Additional Information
description: Add any other context about the problem here.
description: Any other context about the problem.
validations:
required: false

View File

@ -17,4 +17,4 @@ jobs:
- name: "Checkout Repository"
uses: actions/checkout@v4
- name: "Dependency Review"
uses: actions/dependency-review-action@v3
uses: actions/dependency-review-action@v4

253
README.md
View File

@ -1,7 +1,7 @@
# YouTube Music
<div align="center">
# YouTube Music
[![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/)
[![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
@ -14,13 +14,14 @@
![Screenshot](web/screenshot.jpg "Screenshot")
<div align="center">
<a href="https://github.com/th-ch/youtube-music/releases/latest">
<img src="web/youtube-music.svg" width="400" height="100" alt="YouTube Music SVG">
</a>
</div>
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md)
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸](./docs/readme/README-is.md)
**Electron wrapper around YouTube Music featuring:**
@ -28,6 +29,136 @@ Read this in other languages: [🇰🇷](./docs/readme/README-ko.md)
- Framework for custom plugins: change YouTube Music to your needs (style, content, features), enable/disable plugins in
one click
## Demo Image
| Player Screen (album color theme & ambient light) |
|:---------------------------------------------------------------------------------------------------------:|
|![Screenshot1](https://github.com/th-ch/youtube-music/assets/16558115/53efdf73-b8fa-4d7b-a235-b96b91ea77fc)|
## Content
- [Features](#features)
- [Available plugins](#available-plugins)
- [Translation](#translation)
- [Download](#download)
- [Arch Linux](#arch-linux)
- [MacOS](#macos)
- [Windows](#windows)
- [How to install without a network connection? (in Windows)](#how-to-install-without-a-network-connection-in-windows)
- [Themes](#themes)
- [Dev](#dev)
- [Build your own plugins](#build-your-own-plugins)
- [Creating a plugin](#creating-a-plugin)
- [Common use cases](#common-use-cases)
- [Build](#build)
- [Production Preview](#production-preview)
- [Tests](#tests)
- [License](#license)
- [FAQ](#faq)
## Features:
- **Auto confirm when paused** (Always Enabled): disable
the ["Continue Watching?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png)
popup that pause music after a certain time
- And more ...
## Available plugins:
- **Ad Blocker**: Block all ads and tracking out of the box
- **Album Actions**: Adds Undislike, Dislike, Like, and Unlike buttons to apply this to all songs in a playlist or album
- **Album Color Theme**: Applies a dynamic theme and visual effects based on the album color palette
- **Ambient Mode**: Applies a lighting effect by casting gentle colors from the video, into your screens background
- **Audio Compressor**: Apply compression to audio (lowers the volume of the loudest parts of the signal and raises the
volume of the softest parts)
- **Blur Navigation Bar**: makes navigation bar transparent and blurry
- **Bypass Age Restrictions**: bypass YouTube's age verification
- **Captions Selector**: Enable captions
- **Compact Sidebar**: Always set the sidebar in compact mode
- **Crossfade**: Crossfade between songs
- **Disable Autoplay**: Makes every song start in "paused" mode
- **[Discord](https://discord.com/) Rich Presence**: Show your friends what you listen to
with [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)
- **Downloader**: downloads
MP3 [directly from the interface](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
- **Exponential Volume**: Makes the volume
slider [exponential](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) so it's easier to
select lower volumes
- **In-App Menu**: [gives bars a fancy, dark look](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png)
> (see [this post](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) if you have problem
accessing the menu after enabling this plugin and hide-menu option)
- **Scrobbler**: Adds scrobbling support for [Last.fm](https://www.last.fm/) and [ListenBrainz](https://listenbrainz.org/)
- **Lumia Stream**: Adds [Lumia Stream](https://lumiastream.com/) support
- **Lyrics Genius**: Adds lyrics support for most songs
- **Music Together**: Share a playlist with others. When the host plays a song, everyone else will hear the same song
- **Navigation**: Next/Back navigation arrows directly integrated in the interface, like in your favorite browser
- **No Google Login**: Remove Google login buttons and links from the interface
- **Notifications**: Display a notification when a song starts
playing ([interactive notifications](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png)
are available on windows)
- **Picture-in-picture**: allows to switch the app to picture-in-picture mode
- **Playback Speed**: Listen fast, listen
slow! [Adds a slider that controls song speed](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png)
- **Precise Volume**: Control the volume precisely using mousewheel/hotkeys, with a custom hud and customizable volume
steps
- **Shortcuts (& MPRIS)**: Allows setting global hotkeys for playback (play/pause/next/previous) +
disable [media osd](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png)
by overriding media keys + enable Ctrl/CMD + F to search + enable linux mpris support for
mediakeys + [custom hotkeys](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50)
for [advanced users](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)
- **Skip Disliked Song**: Skips disliked songs
- **Skip Silences**: Automatically skip silenced sections
- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Automatically Skips non-music parts like intro/outro or
parts of music videos where the song isn't playing
- **Taskbar Media Control**: Control playback from
your [Windows taskbar](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
- **TouchBar**: Custom TouchBar layout for macOS
- **Tuna OBS**: Integration with [OBS](https://obsproject.com/)'s
plugin [Tuna](https://obsproject.com/forum/resources/tuna.843/)
- **Video Quality Changer**: Allows changing the video quality with
a [button](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) on
the video overlay
- **Video Toggle**: Adds
a [button](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) to
switch between Video/Song mode. can also optionally remove the whole video tab
- **Visualizer**: Different music visualizers
## Translation
You can help with translation on [Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/).
@ -44,14 +175,15 @@ latest version.
### Arch Linux
Install the `youtube-music-bin` package from the AUR. For AUR installation instructions, take a look at
Install the [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) package from the AUR. For AUR installation instructions, take a look at
this [wiki page](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
### MacOS
You can install the app using Homebrew:
You can install the app using Homebrew (see the [cask definition](https://github.com/th-ch/homebrew-youtube-music)):
```bash
brew install --cask https://raw.githubusercontent.com/th-ch/youtube-music/master/youtube-music.rb
brew install th-ch/youtube-music/youtube-music
```
If you install the app manually and get an error "is damaged and cant be opened." when launching the app, run the following in the Terminal:
@ -91,103 +223,6 @@ winget install th-ch.YouTubeMusic
- Place them in the **same directory**.
- Run the installer.
## Features:
- **Auto confirm when paused** (Always Enabled): disable
the ["Continue Watching?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png)
popup that pause music after a certain time
- And more ...
## Available plugins:
- **Ad Blocker**: Block all ads and tracking out of the box
- **Album Color Theme**: Applies a dynamic theme and visual effects based on the album color palette
- **Ambient Mode**: Applies a lighting effect by casting gentle colors from the video, into your screens background.
- **Audio Compressor**: Apply compression to audio (lowers the volume of the loudest parts of the signal and raises the
volume of the softest parts)
- **Blur Nav Bar**: makes navigation bar transparent and blurry
- **Bypass age restrictions**: bypass YouTube's age verification
- **Captions selector**: Enable captions
- **Compact sidebar**: Always set the sidebar in compact mode
- **Crossfade**: Crossfade between songs
- **Disable Autoplay**: Makes every song start in "paused" mode
- [**Discord**](https://discord.com/): Show your friends what you listen to
with [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)
- **Downloader**: downloads
MP3 [directly from the interface](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
- **Exponential Volume**: Makes the volume
slider [exponential](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) so it's easier to
select lower volumes.
- **In-App Menu**: [gives bars a fancy, dark look](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png)
> (see [this post](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) if you have problem
accessing the menu after enabling this plugin and hide-menu option)
- [**Last.fm**](https://www.last.fm/): Scrobbles support
- **Lumia Stream**: Adds [Lumia Stream](https://lumiastream.com/) support
- **Lyrics Genius**: Adds lyrics support for most songs
- **Navigation**: Next/Back navigation arrows directly integrated in the interface, like in your favorite browser
- **No Google Login**: Remove Google login buttons and links from the interface
- **Notifications**: Display a notification when a song starts
playing ([interactive notifications](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png)
are available on windows)
- **Picture in picture**: allows to switch the app to picture-in-picture mode
- **Playback Speed**: Listen fast, listen
slow! [Adds a slider that controls song speed](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png)
- **Precise Volume**: Control the volume precisely using mousewheel/hotkeys, with a custom hud and customizable volume
steps
- **Quality Changer**: Allows changing the video quality with
a [button](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) on
the video overlay
- **Shortcuts**: Allows setting global hotkeys for playback (play/pause/next/previous) +
disable [media osd](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png)
by overriding media keys + enable Ctrl/CMD + F to search + enable linux mpris support for
mediakeys + [custom hotkeys](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50)
for [advanced users](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)
- **Skip-Silences** - Automatically skip silenced sections
- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Automatically Skips non-music parts like intro/outro or
parts of music videos where the song isn't playing
- **Taskbar Media Control**: Control playback from
your [Windows taskbar](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
- **Touchbar**: Custom TouchBar layout for macOS
- **Tuna-OBS**: Integration with [OBS](https://obsproject.com/)'s
plugin [Tuna](https://obsproject.com/forum/resources/tuna.843/)
- **Video Toggle**: Adds
a [button](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) to
switch between Video/Song mode. can also optionally remove the whole video tab
- **Visualizer**: Different music visualizers
## Themes
You can load CSS files to change the look of the application (Options > Visual Tweaks > Themes).
@ -212,7 +247,7 @@ Using plugins, you can:
### Creating a plugin
Create a folder in `plugins/YOUR-PLUGIN-NAME`:
Create a folder in `src/plugins/YOUR-PLUGIN-NAME`:
- `index.ts`: the main file of the plugin
```typescript
@ -290,9 +325,9 @@ import style from './style.css?inline'; // import style as inline
import { createPlugin } from '@/utils';
const builder = createPlugin({
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic show restart dialog
restartNeeded: true, // if value is true, ytmusic will show a restart dialog
config: {
enabled: false,
}, // your custom config
@ -306,9 +341,9 @@ const builder = createPlugin({
```typescript
import { createPlugin } from '@/utils';
const builder = createPlugin({
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic show restart dialog
restartNeeded: true, // if value is true, ytmusic will show the restart dialog
config: {
enabled: false,
}, // your custom config
@ -354,7 +389,7 @@ Uses [Playwright](https://playwright.dev/) to test the app.
MIT © [th-ch](https://github.com/th-ch/youtube-music)
## Most asked questions
## FAQ
### Why apps menu isn't showing up?

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -2,8 +2,200 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v3.3.2](https://github.com/th-ch/youtube-music/compare/v3.3.1...v3.3.2)
- fix: fix bugs in MPRIS, and improve MPRIS [`#1760`](https://github.com/th-ch/youtube-music/pull/1760)
- fix(deps): update dependency electron-updater to v6.1.8 [`#1770`](https://github.com/th-ch/youtube-music/pull/1770)
- chore(deps): update dependency electron-builder to v24.12.0 [`#1771`](https://github.com/th-ch/youtube-music/pull/1771)
- feat(scrobblers): use `BrowserWindow` instead of `shell.openExternal` [`#1758`](https://github.com/th-ch/youtube-music/pull/1758)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v7.0.2 [`#1763`](https://github.com/th-ch/youtube-music/pull/1763)
- chore(deps): update dependency esbuild to v0.20.1 [`#1759`](https://github.com/th-ch/youtube-music/pull/1759)
- fix(deps): update dependency i18next to v23.9.0 [`#1754`](https://github.com/th-ch/youtube-music/pull/1754)
- fix: fixed an issue that caused infinite loops when using Music Together [`#1752`](https://github.com/th-ch/youtube-music/issues/1752)
- chore(deps): rollback dependency electron-builder to v24.9.1 [`8bd05f5`](https://github.com/th-ch/youtube-music/commit/8bd05f525df98671f0a516b159cccab302b7ae99)
- chore(deps): update dependency electron-builder to v24.13.1 [`47b23b4`](https://github.com/th-ch/youtube-music/commit/47b23b414c8feb25c4d9a23d6adb7cbf1ac818fb)
- chore(i18n): Translated using Weblate (German) [`47505e9`](https://github.com/th-ch/youtube-music/commit/47505e97482f9e953ee451b968d0950585616ffa)
#### [v3.3.1](https://github.com/th-ch/youtube-music/compare/v3.3.0...v3.3.1)
> 18 February 2024
- Update changelog for v3.3.0 [`6d9bb8e`](https://github.com/th-ch/youtube-music/commit/6d9bb8eb1cc2d892a5552ffb1f7c20859aa80f67)
- hotfix: in-app-menu position issue [`87acf4c`](https://github.com/th-ch/youtube-music/commit/87acf4cf042ba32a000a4aeaec5c17c93501d333)
- release 3.3.1 (HOTFIX) [`a6ed8bf`](https://github.com/th-ch/youtube-music/commit/a6ed8bf3aa20ca8e950e85d88f981ccf9edc7498)
#### [v3.3.0](https://github.com/th-ch/youtube-music/compare/v3.2.2...v3.3.0)
> 18 February 2024
- fix(deps): update dependency i18next to v23.8.3 [`#1751`](https://github.com/th-ch/youtube-music/pull/1751)
- import fixed ./constants [`#1748`](https://github.com/th-ch/youtube-music/pull/1748)
- chore(deps): update dependency rollup to v4.12.0 [`#1743`](https://github.com/th-ch/youtube-music/pull/1743)
- chore(deps): bump undici from 5.28.2 to 5.28.3 [`#1747`](https://github.com/th-ch/youtube-music/pull/1747)
- chore(deps): update dependency vite to v5.1.3 [`#1742`](https://github.com/th-ch/youtube-music/pull/1742)
- chore(deps): update dependency vite-plugin-solid to v2.10.1 [`#1734`](https://github.com/th-ch/youtube-music/pull/1734)
- chore(deps): update dependency discord-api-types to v0.37.70 [`#1740`](https://github.com/th-ch/youtube-music/pull/1740)
- chore(deps): update dependency electron to v28.2.3 [`#1736`](https://github.com/th-ch/youtube-music/pull/1736)
- chore(deps): update pnpm to v8.15.3 [`#1739`](https://github.com/th-ch/youtube-music/pull/1739)
- chore(deps): update dependency rollup to v4.11.0 [`#1738`](https://github.com/th-ch/youtube-music/pull/1738)
- fix(deps): update dependency solid-js to v1.8.15 [`#1735`](https://github.com/th-ch/youtube-music/pull/1735)
- chore(deps): update dependency vite to v5.1.2 [`#1733`](https://github.com/th-ch/youtube-music/pull/1733)
- chore(deps): update dependency vite-plugin-solid to v2.10.0 [`#1732`](https://github.com/th-ch/youtube-music/pull/1732)
- chore(deps): update pnpm to v8.15.2 [`#1729`](https://github.com/th-ch/youtube-music/pull/1729)
- Update Copyright - 2024 [`#1730`](https://github.com/th-ch/youtube-music/pull/1730)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v7 [`#1728`](https://github.com/th-ch/youtube-music/pull/1728)
- fix(deps): update dependency @floating-ui/dom to v1.6.3 [`#1727`](https://github.com/th-ch/youtube-music/pull/1727)
- chore(deps): update dependency electron to v28.2.2 [`#1717`](https://github.com/th-ch/youtube-music/pull/1717)
- chore(deps): update dependency vite to v5.1.1 [`#1718`](https://github.com/th-ch/youtube-music/pull/1718)
- chore(deps): update dependency @types/semver to v7.5.7 [`#1724`](https://github.com/th-ch/youtube-music/pull/1724)
- fix(deps): update dependency @floating-ui/dom to v1.6.2 [`#1725`](https://github.com/th-ch/youtube-music/pull/1725)
- chore(deps): update dependency rollup to v4.10.0 [`#1719`](https://github.com/th-ch/youtube-music/pull/1719)
- fix(deps): update dependency solid-js to v1.8.14 [`#1713`](https://github.com/th-ch/youtube-music/pull/1713)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.21.0 [`#1711`](https://github.com/th-ch/youtube-music/pull/1711)
- fix(deps): update dependency semver to v7.6.0 [`#1712`](https://github.com/th-ch/youtube-music/pull/1712)
- refactor(in-app-menu): refactor `in-app-menu` plugin [`#1710`](https://github.com/th-ch/youtube-music/pull/1710)
- chore(deps): update playwright monorepo to v1.41.2 [`#1706`](https://github.com/th-ch/youtube-music/pull/1706)
- chore(deps): update dependency electron to v29.0.0-beta.5 [`#1707`](https://github.com/th-ch/youtube-music/pull/1707)
- feat(album-color-theme): support album color theme in all pages [`#1685`](https://github.com/th-ch/youtube-music/pull/1685)
- fix(deps): update dependency youtubei.js to v9.0.2 [`#1704`](https://github.com/th-ch/youtube-music/pull/1704)
- fix(deps): update dependency i18next to v23.8.2 [`#1702`](https://github.com/th-ch/youtube-music/pull/1702)
- feat: Support disabling scrobbling for non-music content [`#1665`](https://github.com/th-ch/youtube-music/pull/1665)
- fix(deps): update dependency youtubei.js to v9 [`#1682`](https://github.com/th-ch/youtube-music/pull/1682)
- chore(deps): update dependency electron to v29.0.0-beta.4 [`#1698`](https://github.com/th-ch/youtube-music/pull/1698)
- fix(deps): update dependency i18next to v23.8.1 [`#1694`](https://github.com/th-ch/youtube-music/pull/1694)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.20.0 [`#1700`](https://github.com/th-ch/youtube-music/pull/1700)
- chore(deps): update pnpm to v8.15.1 [`#1699`](https://github.com/th-ch/youtube-music/pull/1699)
- chore(deps): update dependency esbuild to v0.20.0 [`#1691`](https://github.com/th-ch/youtube-music/pull/1691)
- chore(deps): update pnpm to v8.15.0 [`#1692`](https://github.com/th-ch/youtube-music/pull/1692)
- fix(deps): update dependency i18next to v23.7.20 [`#1684`](https://github.com/th-ch/youtube-music/pull/1684)
- chore(deps): update dependency electron to v29.0.0-beta.3 [`#1683`](https://github.com/th-ch/youtube-music/pull/1683)
- chore(deps): update dependency electron to v29.0.0-beta.2 [`#1681`](https://github.com/th-ch/youtube-music/pull/1681)
- chore(deps): update dependency rollup to v4.9.6 [`#1663`](https://github.com/th-ch/youtube-music/pull/1663)
- chore(deps): update dependency electron to v29.0.0-beta.1 [`#1670`](https://github.com/th-ch/youtube-music/pull/1670)
- fix(deps): update dependency i18next to v23.7.19 [`#1680`](https://github.com/th-ch/youtube-music/pull/1680)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.19.1 [`#1669`](https://github.com/th-ch/youtube-music/pull/1669)
- chore(deps): update pnpm to v8.14.3 [`#1668`](https://github.com/th-ch/youtube-music/pull/1668)
- chore(deps): update dependency vite-plugin-inspect to v0.8.3 [`#1672`](https://github.com/th-ch/youtube-music/pull/1672)
- chore(deps): update dependency esbuild to v0.19.12 [`#1673`](https://github.com/th-ch/youtube-music/pull/1673)
- fix(deps): update dependency @electron/remote to v2.1.2 [`#1676`](https://github.com/th-ch/youtube-music/pull/1676)
- chore: Update issue templates [`#1661`](https://github.com/th-ch/youtube-music/pull/1661)
- chore(deps): update playwright monorepo to v1.41.1 [`#1660`](https://github.com/th-ch/youtube-music/pull/1660)
- fix(deps): update dependency i18next to v23.7.18 [`#1662`](https://github.com/th-ch/youtube-music/pull/1662)
- chore(deps): update actions/dependency-review-action action to v4 [`#1654`](https://github.com/th-ch/youtube-music/pull/1654)
- chore(deps): update dependency electron to v29.0.0-alpha.11 [`#1656`](https://github.com/th-ch/youtube-music/pull/1656)
- chore(deps): update dependency vite to v5.0.12 [security] [`#1659`](https://github.com/th-ch/youtube-music/pull/1659)
- fix(deps): update dependency async-mutex to v0.4.1 [`#1653`](https://github.com/th-ch/youtube-music/pull/1653)
- chore(deps): update playwright monorepo to v1.41.0 [`#1651`](https://github.com/th-ch/youtube-music/pull/1651)
- feat: Better Scrobbler Plugin [`#1640`](https://github.com/th-ch/youtube-music/pull/1640)
- chore(deps): update dependency electron to v29.0.0-alpha.10 [`#1645`](https://github.com/th-ch/youtube-music/pull/1645)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.19.0 [`#1643`](https://github.com/th-ch/youtube-music/pull/1643)
- chore(README): Fix plugins names and add plugins in/to Readme (in menu too) [`#1624`](https://github.com/th-ch/youtube-music/pull/1624)
- fix(album-actions): Fixed album actions [`#1639`](https://github.com/th-ch/youtube-music/pull/1639)
- chore(deps): update playwright monorepo to v1.41.0-beta-1705101589000 [`#1638`](https://github.com/th-ch/youtube-music/pull/1638)
- fix(#1543): fix song control doesn't work [`#1637`](https://github.com/th-ch/youtube-music/pull/1637)
- chore(deps): update playwright monorepo to v1.41.0-beta-1705092460000 [`#1635`](https://github.com/th-ch/youtube-music/pull/1635)
- chore(deps): update dependency rollup to v4.9.5 [`#1629`](https://github.com/th-ch/youtube-music/pull/1629)
- chore(deps): update dependency electron to v29.0.0-alpha.9 [`#1627`](https://github.com/th-ch/youtube-music/pull/1627)
- chore(deps): update dependency electron to v29.0.0-alpha.8 [`#1608`](https://github.com/th-ch/youtube-music/pull/1608)
- fix(deps): update dependency @cliqz/adblocker-electron to v1.26.15 [`#1615`](https://github.com/th-ch/youtube-music/pull/1615)
- chore(deps): update dependency rollup to v4.9.4 [`#1591`](https://github.com/th-ch/youtube-music/pull/1591)
- fix(deps): update dependency @cliqz/adblocker-electron-preload to v1.26.15 [`#1616`](https://github.com/th-ch/youtube-music/pull/1616)
- chore(deps): update pnpm to v8.14.1 [`#1619`](https://github.com/th-ch/youtube-music/pull/1619)
- chore(deps): update dependency eslint-plugin-prettier to v5.1.3 [`#1618`](https://github.com/th-ch/youtube-music/pull/1618)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.18.1 [`#1612`](https://github.com/th-ch/youtube-music/pull/1612)
- fix(deps): update dependency youtubei.js to v8.2.0 [`#1614`](https://github.com/th-ch/youtube-music/pull/1614)
- chore(deps): update dependency electron-vite to v2.0.0 [`#1609`](https://github.com/th-ch/youtube-music/pull/1609)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.18.0 [`#1603`](https://github.com/th-ch/youtube-music/pull/1603)
- chore(deps): update dependency electron-vite to v2.0.0-beta.4 [`#1602`](https://github.com/th-ch/youtube-music/pull/1602)
- fix: fix upgrade button [`#1199`](https://github.com/th-ch/youtube-music/issues/1199)
- fix(mpris): fix mpris invalid position [`#1726`](https://github.com/th-ch/youtube-music/issues/1726)
- fix: discord RPC (fix #1664) [`#1664`](https://github.com/th-ch/youtube-music/issues/1664)
- fix: remove sign-in button (fix #1199) [`#1199`](https://github.com/th-ch/youtube-music/issues/1199)
- Fix #1617 [`#1617`](https://github.com/th-ch/youtube-music/issues/1617)
- fix(crossfade): fix #1633 [`#1633`](https://github.com/th-ch/youtube-music/issues/1633)
- fix: fix #1621 [`#1621`](https://github.com/th-ch/youtube-music/issues/1621)
- fix(tuna-obs): partially fix #1596 [`#1596`](https://github.com/th-ch/youtube-music/issues/1596)
- fix(discord): fix hide duration button [`#1644`](https://github.com/th-ch/youtube-music/issues/1644)
- fix(in-app-menu): fix invalid `margin-top` [`#1597`](https://github.com/th-ch/youtube-music/issues/1597)
- fix(README): fix `plugins` path [`#1598`](https://github.com/th-ch/youtube-music/issues/1598)
- chore(i18n): Translated using Weblate (Vietnamese) [`0528637`](https://github.com/th-ch/youtube-music/commit/05286371353e8b4c36a5b9fe9011ae5dfdc7ee82)
- chore: update pnpm-lock [`fd8d59b`](https://github.com/th-ch/youtube-music/commit/fd8d59bada56dab4e156d22394fe0c5efec5abc4)
- fix(in-app-menu): fix app crash in production [`febc63e`](https://github.com/th-ch/youtube-music/commit/febc63edef375bd82db48b7fb460ec5a601ab872)
#### [v3.2.2](https://github.com/th-ch/youtube-music/compare/v3.2.1...v3.2.2)
> 5 January 2024
- feat(tray): Add song info and paused icon [`#1592`](https://github.com/th-ch/youtube-music/pull/1592)
- fix(skip-silences): fix audio distorted [`#1141`](https://github.com/th-ch/youtube-music/issues/1141)
- chore(deps): update dependency rollup to v4.9.3 [`0c3c380`](https://github.com/th-ch/youtube-music/commit/0c3c3805918adf2a185a7f1dc67ea3af8135863d)
- chore(i18n): Translated using Weblate (Turkish) [`64ea1fd`](https://github.com/th-ch/youtube-music/commit/64ea1fdb58fdf2766ae3284ac1a51bfac8894b36)
- fix(music-together): typing [`895386f`](https://github.com/th-ch/youtube-music/commit/895386f6f8c649f77ea15c88f6fb7ecc5b775554)
#### [v3.2.1](https://github.com/th-ch/youtube-music/compare/v3.2.0...v3.2.1)
> 1 January 2024
- fix: fix #1574 [`#1574`](https://github.com/th-ch/youtube-music/issues/1574)
- fix: fix #1575 [`#1575`](https://github.com/th-ch/youtube-music/issues/1575)
- chore(i18n): Translated using Weblate [`f5aa179`](https://github.com/th-ch/youtube-music/commit/f5aa179cd639eb4b8f70f1264b5b459ebcc16695)
- chore(i18n): Translated using Weblate (English) [`e409165`](https://github.com/th-ch/youtube-music/commit/e409165e1bed85f3d1aea3a565e7b9e462b1e05b)
- chore(i18n): Translated using Weblate (Czech) [`0ca4e34`](https://github.com/th-ch/youtube-music/commit/0ca4e34efd86e877314e5a245f266065b4cf0013)
#### [v3.2.0](https://github.com/th-ch/youtube-music/compare/v3.1.1...v3.2.0)
> 1 January 2024
- feat(album-color-theme): improve `Album Color Theme` style [`#1571`](https://github.com/th-ch/youtube-music/pull/1571)
- feat(menu): add more detail in Menu [`#1570`](https://github.com/th-ch/youtube-music/pull/1570)
- feat(music-together): Add new plugin `Music Together` [`#1562`](https://github.com/th-ch/youtube-music/pull/1562)
- chore(deps): update dependency rollup to v4.9.2 [`#1567`](https://github.com/th-ch/youtube-music/pull/1567)
- fix(deps): update dependency i18next to v23.7.13 [`#1569`](https://github.com/th-ch/youtube-music/pull/1569)
- feat: Add new plugin `Album actions` [`#1515`](https://github.com/th-ch/youtube-music/pull/1515)
- fix(deps): update dependency i18next to v23.7.12 [`#1564`](https://github.com/th-ch/youtube-music/pull/1564)
- fix: Only apply scale factor on Windows [`#1565`](https://github.com/th-ch/youtube-music/pull/1565)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.16.0 [`#1556`](https://github.com/th-ch/youtube-music/pull/1556)
- chore(deps): update pnpm to v8.13.1 [`#1557`](https://github.com/th-ch/youtube-music/pull/1557)
- chore(deps): update dependency ws to v8.16.0 [`#1559`](https://github.com/th-ch/youtube-music/pull/1559)
- fix(deps): update dependency youtubei.js to v8.1.0 [`#1560`](https://github.com/th-ch/youtube-music/pull/1560)
- fix(deps): update dependency node-html-parser to v6.1.12 [`#1554`](https://github.com/th-ch/youtube-music/pull/1554)
- Revert "fix(deps): update dependency @xhayper/discord-rpc to v1.1.2" [`#1552`](https://github.com/th-ch/youtube-music/pull/1552)
- feat(ambient-mode): support ambient mode on `Song section` [`#1555`](https://github.com/th-ch/youtube-music/issues/1555)
- fix: fixed an issue with the download button disappearing [`#1551`](https://github.com/th-ch/youtube-music/issues/1551)
- fix: fix `homebrew cask` [`#1514`](https://github.com/th-ch/youtube-music/issues/1514)
- fix: pnpm build error [`13ef856`](https://github.com/th-ch/youtube-music/commit/13ef8560ff43353030537403be7da82542ba535e)
- chore(i18n): Translated using Weblate (Czech) [`0dc9c6a`](https://github.com/th-ch/youtube-music/commit/0dc9c6a1a90bce6505614617b827e816cbaaf875)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.15.0 [`c5bcd89`](https://github.com/th-ch/youtube-music/commit/c5bcd89f164b51d7380486a8ae35edd0caeea842)
#### [v3.1.1](https://github.com/th-ch/youtube-music/compare/v3.1.0...v3.1.1)
> 18 December 2023
- fix: fix renderer plugin load timing [`#1522`](https://github.com/th-ch/youtube-music/issues/1522)
- chore(i18n): Translated using Weblate (Lithuanian) [`fc1a7cd`](https://github.com/th-ch/youtube-music/commit/fc1a7cda62b6e33e5f5d57a5a6e0adef6a32bf9a)
- chore(i18n): Translated using Weblate (Chinese (Simplified)) [`eba7026`](https://github.com/th-ch/youtube-music/commit/eba7026b89bbfdd3ac07cf728a66ba9bdd274ec0)
- chore(deps): update dependency rollup to v4.8.0 [`a601d0b`](https://github.com/th-ch/youtube-music/commit/a601d0b3d2dee0fabad79a18e1a7dd0ca84ccf01)
#### [v3.1.0](https://github.com/th-ch/youtube-music/compare/v3.0.2...v3.1.0)
> 11 December 2023
- chore(deps): update dependency electron to v28 [`#1498`](https://github.com/th-ch/youtube-music/pull/1498)
- Enable/Disable Navigation without restart [`#1507`](https://github.com/th-ch/youtube-music/pull/1507)
- Turkish(tr)_lang_file [`#1513`](https://github.com/th-ch/youtube-music/pull/1513)
- Skip Disliked Songs [`#1505`](https://github.com/th-ch/youtube-music/pull/1505)
- chore(deps): update dependency @typescript-eslint/eslint-plugin to v6.13.2 [`#1452`](https://github.com/th-ch/youtube-music/pull/1452)
- fix: Homebrew latest release url parsing [`#1496`](https://github.com/th-ch/youtube-music/pull/1496)
- fix: in-player adblocker inject timing issue [`#1478`](https://github.com/th-ch/youtube-music/issues/1478)
- fix(package.json): fix RPM version `libuuid` issue [`#1508`](https://github.com/th-ch/youtube-music/issues/1508)
- Translated using Weblate (Polish) [`7b78ba6`](https://github.com/th-ch/youtube-music/commit/7b78ba67613f14be65a45751efeb06431b405a91)
- Translated using Weblate (French) [`ebc0879`](https://github.com/th-ch/youtube-music/commit/ebc087963b23265ff00528c8305d51597abf587a)
- Translated using Weblate (Chinese (Traditional)) [`020bdc0`](https://github.com/th-ch/youtube-music/commit/020bdc0811ea45ad6c2853c62a05ae6695c5c4f9)
#### [v3.0.2](https://github.com/th-ch/youtube-music/compare/v3.0.1...v3.0.2)
> 3 December 2023
- fix(adblocker): fix In-Player adblocker [`#1478`](https://github.com/th-ch/youtube-music/issues/1478)
- fix(menu): crash on linux [`#1477`](https://github.com/th-ch/youtube-music/issues/1477)
- fix: update pnpm-lock.yaml [`9e2c6b1`](https://github.com/th-ch/youtube-music/commit/9e2c6b1afa33b5708853c8328946e68ec45b09c3)

View File

@ -478,7 +478,7 @@
</a>
</li>
</ul>
<div class="footer-copyright">© 2021 th-ch</div>
<div class="footer-copyright">© 2024 th-ch</div>
</div>
</div>
</div>

388
docs/readme/README-is.md Normal file
View File

@ -0,0 +1,388 @@
<div align="center">
# YouTube Tónlist
[![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/)
[![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
[![Build status](https://img.shields.io/github/actions/workflow/status/th-ch/youtube-music/build.yml?branch=master&style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/)
[![GitHub All Releases](https://img.shields.io/github/downloads/th-ch/youtube-music/total?style=for-the-badge&logo=youtube-music)](https://GitHub.com/th-ch/youtube-music/releases/)
[![AUR](https://img.shields.io/aur/version/youtube-music-bin?color=blueviolet&style=for-the-badge&logo=youtube-music)](https://aur.archlinux.org/packages/youtube-music-bin)
[![Known Vulnerabilities](https://snyk.io/test/github/th-ch/youtube-music/badge.svg)](https://snyk.io/test/github/th-ch/youtube-music)
</div>
![Screenshot](../../web/screenshot.jpg "Screenshot")
<div align="center">
<a href="https://github.com/th-ch/youtube-music/releases/latest">
<img src="../../web/youtube-music.svg" width="400" height="100" alt="YouTube Music SVG">
</a>
</div>
**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
- Rammi fyrir sérsniðnar viðbætur: breyttu YouTube Tónlist að þínum þörfum (stíl, efni, eiginleikar), virkjaðu/slökktu á viðbætur í
einn smellur
## Sýnishornsmynd
| Spilaraskjár (albúmslitaþema & umhverfisljós) |
|:---------------------------------------------------------------------------------------------------------:|
|![Screenshot1](https://github.com/th-ch/youtube-music/assets/16558115/53efdf73-b8fa-4d7b-a235-b96b91ea77fc)|
## Efni
- [Eiginleikar](#eiginleikar)
- [Tiltæk viðbætur](#tiltæk-viðbætur)
- [Þýðing](#þýðing)
- [Sækja](#sækja)
- [Arch Linux](#arch-linux)
- [MacOS](#macos)
- [Windows](#windows)
- [Hvernig á að setja upp án nettengingar? (í Windows)](#hvernig-á-að-setja-upp-án-nettengingar-í-windows)
- [Þemu](#þemu)
- [Þróun](#þróun)
- [Búðu til þín eigin viðbætur](#búðu-til-þín-eigin-viðbætur)
- [Er að búa til viðbót](#er-að-búa-til-viðbót)
- [Algeng notkunartilvik](#algeng-notkunartilvik)
- [Byggja](#byggja)
- [Framleiðsluforskoðun](#framleiðsluforskoðun)
- [Prófanir](#prófanir)
- [Leyfi](#leyfi)
- [Algengustu spurningar](#algengustu-spurningar)
## Eiginleikar:
- **Sjálfvirk staðfesting þegar gert er hlé** (Alltaf virkt): slökkva á
["Halda áfram að horfa?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png)
popup sem gerir hlé á tónlist eftir ákveðinn tíma
- Og meira...
## Tiltæk viðbætur:
- **Auglýsingablokkari**: Lokaðu fyrir allar auglýsingar og rakningar úr kassanum
- **Albúmsaðgerðir**: Bætir Ódíslika, Mislíkt, Líkt, og Ólíkt til að nota þetta á öll lög á spilunarlista eða albúm
- **Albúmslitaþema**: Beitir kraftmikið þema og sjónrænum áhrifum sem byggjast á litavali albúmsins
- **Umhverfishamur**: Beitir lýsingaráhrifum með því að varpa mildum litum úr myndbandinu í bakgrunn skjásins
- **Hljóðþjöppur**: Notaðu þjöppun á hljóð (lækkar hljóðstyrk háværustu hluta merkis og hækkar hljóðstyrk í mýkstu hlutunum)
- **Þoka Leiðsagnarstika**: Gerir leiðsögustikuna gagnsæja og óskýrt
- **Farið Framhjá Aldurstakmörkunum**: Framhjá aldursstaðfestingu YouTube
- **Yfirskriftarval**: Virkja skjátexta
- **Fyrirferðarlítillhliðarstika**: Stilltu hliðarstikuna alltaf í þétta stillingu
- **Krossfæra**: Krossfæra á milli lög
- **Slökkva á Sjálfvirkri Spilun**: Gerir lag að byrja í "hlé" ham
- **[Discord](https://discord.com/) Rík Nærveru**: Sýndu vinum þínum hvað þú hlustar á
með [Rík Nærveru](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)
- **Niðurhalari**: Niðurhalum
MP3 [beint úr viðmótinu](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
- **Veldibundiðrúmmál**: Gerir hljóðstyrkssleðann [veldisvísis](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/)
svo það er auðveldara að velja lægra hljóðstyrk.
- **Valmynd í Forriti**: [Gefur börum flott, dökkt útlit](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png)
> (sjá [þessa færslu](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) ef þú átt í vandræðum
með að fá aðgang að valmyndinni eftir að hafa virkjað þessa viðbót og fela valmyndarvalkostinn)
- **Scrobbler**: Bætir við scrobbling stuðningi fyrir [Last.fm](https://www.last.fm/) og [ListenBrainz](https://listenbrainz.org/)
- **Lumia Stream**: Bætir við [Lumia Stream](https://lumiastream.com/) stuðningi
- **Söngtexti Snilld**: Bætir stuðningi við texta fyrir flest lög
- **Tónlist Saman**: Deila spilunarlista með öðrum. Þegar gestgjafinn spilar lag munu allir aðrir heyra sama lagið
- **Leiðsögn**: Næsta/Til baka leiðsagnarörvar beint samþættar í viðmótinu, eins og í uppáhalds vafranum þínum
- **Engin Google Innskráning**: Fjarlægðu Google innskráningarhnappa og tengla úr viðmótinu
- **Tilkynningar**: Birta tilkynningu þegar lag byrjar að spila
([gagnvirkartilkynningar](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) eru fáanlegar á Windows)
- **Mynd-í-Mynd**: Gerir kleift að skipta forritinu yfir í mynd-í-mynd stillingu
- **Spilunarhraði**: Hlustaðu hratt, hlustaðu hægt!
[Bætir við sleða sem stjórnar lagahraðanum](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png)
- **Nákvæmshljóðstyrkur**: Stjórnaðu hljóðstyrknum nákvæmlega með músarhjóli/hraðtökkum, með sérsniðnum HUD og sérsniðnum hljóðstyrksþrepum
- **Flýtileiðir (og MPRIS)**: Leyfir að stilla alþjóðlegarflýtilyklar fyrir spilun (spila/gera hlé/næsta/fyrri) +
óvirkja [media osd](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png)
með því að hnekkja miðlunarlyklum + virkja Ctrl/CMD + F til að leita + virkja linux mpris stuðning fyrir
miðlunarlyklar + [sérsniðnir flýtilyklar](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50)
fyrir [háþróaða notendur](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)
- **Slepptu Lögum sem Mislíkuðust**: Sleppir mislíkaði lög
- **Slepptu Þögnum**: Slepptu sjálfkrafa þagnarköflum í lögum
- [**Styrktarblokk**](https://github.com/ajayyy/SponsorBlock): Sleppur sjálfkrafa hlutum sem ekki eru tónlist, eins og inngangur/lok
eða hlutar af tónlistarmyndböndum þar sem lag er ekki að spila
- **Miðlunarstýringarverkefnastikunnar**: Stjórnaðu spilun frá [Windows verkefnastikunni þinni](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
- **Snertistiku**: Sérsniðið Snertistikuútlit fyrir macOS
- **Tuna OBS**: Samþætting við [OBS](https://obsproject.com/)
viðbótina [Tuna](https://obsproject.com/forum/resources/tuna.843/)
- **Myndbandgæðisbreyting**: Leyfir að breyta myndbandgæðum með
[hnappi](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) á
myndbandsyfirlaginu
- **Myndbandsrofi**: Bætir við [hnappi](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) til
að skipta á milli myndbands/lagshams. Getur einnig valfrjálst fjarlægt allan myndbandsflipann
- **Sjónrænir**: Mismunandi tónlist sjónrænir
## Þýðing
Þú getur aðstoðað við þýðingar á [Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/).
<a href="https://hosted.weblate.org/engage/youtube-music/">
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/multi-auto.svg" alt="translation status" />
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="translation status 2" />
</a>
## Sækja
Þú getur skoðað [nýjustu útgáfuna](https://github.com/th-ch/youtube-music/releases/latest) til að finna fljótt
nýjustu útgáfuna.
### Arch Linux
Settu upp [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) pakkann frá AUR. Fyrir AUR uppsetningarleiðbeiningar skaltu skoða
þessa [wiki síðu](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
### MacOS
Þú getur sett upp appið með því að nota Homebrew (sjá [cask skilgreiningu](https://github.com/th-ch/homebrew-youtube-music))
```bash
brew install th-ch/youtube-music/youtube-music
```
Ef þú setur upp forritið handvirkt og færð villu "er skemmd og ekki er hægt að opna það," þegar þú ræsir forritið skaltu keyra eftirfarandi í flugstöðinni:
```bash
xattr -cr /Applications/YouTube\ Music.app
```
### Windows
Þú getur notað [Scoop pakkastjórnun](https://scoop.sh) til að setja upp `youtube-music` pakkann frá
[`extras` fötuna](https://github.com/ScoopInstaller/Extras).
```bash
scoop bucket add extras
scoop install extras/youtube-music
```
Að öðrum kosti geturðu notað [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), Windows 11s
opinber CLI pakkastjóri til að setja upp `th-ch.YouTubeMusic` pakkann.
*Athugið: Microsoft Defender SmartScreen gæti lokað uppsetningunni þar sem hún er frá „óþekktum útgefanda“. Þetta er einnig
satt fyrir handvirka uppsetningu þegar reynt er að keyra executable(.exe) eftir handvirkt niðurhal hér á github (sama
skrá).*
```bash
winget install th-ch.YouTubeMusic
```
#### Hvernig á að setja upp án nettengingar? (í Windows)
- Sæktu `*.nsis.7z` skrána fyrir _arkitektúr tækisins þíns_ á [útgáfusíðu](https://github.com/th-ch/youtube-music/releases/latest).
- `x64` fyrir 64-bita Windows
- `ia32` fyrir 32-bita Windows
- `arm64` fyrir ARM64 Windows
- Sæktu uppsetningarforrit á útgáfusíðu. (`*-Setup.exe`)
- Settu þær í **sömu möppuna**.
- Keyrðu uppsetningarforritið.
## Þemu
Þú getur hlaðið CSS skrám til að breyta útliti forritsins (Valkostir > Sjónræn klip > Þemu).
Sum fyrirframskilgreind þemu eru fáanleg á https://github.com/kerichdev/themes-for-ytmdesktop-player.
## Þróun
```bash
git clone https://github.com/th-ch/youtube-music
cd youtube-music
pnpm install --frozen-lockfile
pnpm dev
```
## Búðu til þín eigin viðbætur
Með því að nota viðbætur geturðu:
- vinna með appið - `BrowserWindow` frá electron er sent til viðbótarstjórans
- breyttu framhliðinni með því að vinna með HTML/CSS
### Er að búa til viðbót
Búðu til möppu í `src/plugins/YOUR-PLUGIN-NAME`:
- `index.ts`: aðal skránni af viðbótin
```typescript
import style from './style.css?inline'; // flytja inn stíl sem inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // ef gildi er satt, ytmusic show endurræsa gluggann
config: {
enabled: false,
}, // sérsniðnastillingar þinn
stylesheets: [style], // sérsniðnastílinn þinn
menu: async ({ getConfig, setConfig }) => {
// Allar *stillingaraðferðir eru umvafnar Lofor<T>
const config = await getConfig();
return [
{
label: 'menu',
submenu: [1, 2, 3].map((value) => ({
label: `value ${value}`,
type: 'radio',
checked: config.value === value,
click() {
setConfig({ value });
},
})),
},
];
},
backend: {
start({ window, ipc }) {
window.maximize();
// þú getur tengst við renderer viðbótina
ipc.handle('some-event', () => {
return 'hello';
});
},
// það kviknaði þegar stillingum var breytt
onConfigChange(newConfig) { /* ... */ },
// it fired when plugin disabled
stop(context) { /* ... */ },
},
renderer: {
async start(context) {
console.log(await context.ipc.invoke('some-event'));
},
// Aðeins krókur sem er í boði fyrir renderer
onPlayerApiReady(api: YoutubePlayer, context: RendererContext) {
// stilltu stillingar viðbótarinnar auðveldlega
context.setConfig({ myConfig: api.getVolume() });
},
onConfigChange(newConfig) { /* ... */ },
stop(_context) { /* ... */ },
},
preload: {
async start({ getConfig }) {
const config = await getConfig();
},
onConfigChange(newConfig) {},
stop(_context) {},
},
});
```
### Algeng notkunartilvik
- er að sprauta sérsniðnum CSS: búðu til `style.css` skrá í sömu möppu þá:
```typescript
// index.ts
import style from './style.css?inline'; // flytja inn stíl sem inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // ef gildi er satt, ytmusic show endurræsa gluggann
config: {
enabled: false,
}, // sérsniðnastillingar þinn
stylesheets: [style], // sérsniðnastílinn þinn
renderer() {} // skilgreina renderer krók
});
```
- Ef þú vilt breyta HTML:
```typescript
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // ef gildi er satt, ytmusic show endurræsa gluggann
config: {
enabled: false,
}, // sérsniðnastillingar þinn
renderer() {
// Fjarlægðu innskráningarhnappinn
document.querySelector(".sign-in-link.ytmusic-nav-bar").remove();
} // skilgreina renderer krók
});
```
- samskipti á milli að framan og aftan: hægt að gera með því að nota ipcMain eininguna frá electron. Sjá `index.ts` skrá og
dæmi í 'styrktarblokk' viðbótinni.
## Byggja
1. Klóna geymsluna
2. Fylgdu [þessa handbók](https://pnpm.io/installation) til að setja upp 'pnpm'
3. Keyrðu `pnpm install --frozen-lockfile` til að setja upp ósjálfstæði
4. Keyrðu `pnpm build:OS`
- `pnpm dist:win` - Windows
- `pnpm dist:linux` - Linux
- `pnpm dist:mac` - MacOS
Byggir appið fyrir macOS, Linux og Windows,
með því að nota [electron-builder](https://github.com/electron-userland/electron-builder).
## Framleiðsluforskoðun
```bash
pnpm start
```
## Prófanir
```bash
pnpm test
```
Notar [Playwright](https://playwright.dev/) til að prófa forritið.
## Leyfi
MIT © [th-ch](https://github.com/th-ch/youtube-music)
## Algengustu Spurningar
### Hvers vegna forritavalmynd birtist ekki?
Ef valmöguleikinn „Fela valmynd“ er á - þú getur sýnt valmyndina með <kbd>alt</kbd> lyklinum (eða <kbd>\`</kbd> [bakka]
ef þú notar viðbótina fyrir valmynd í forriti)

View File

@ -1,7 +1,7 @@
# 유튜브 뮤직 (YouTube Music)
<div align="center">
# 유튜브 뮤직 (YouTube Music)
[![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/)
[![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
@ -25,62 +25,26 @@
- 원래의 인터페이스를 유지하는 것을 목표로 하는 네이티브 디자인 및 느낌
- 맞춤 플러그인을 위한 프레임워크: 스타일, 콘텐츠, 기능 등 필요에 따라 유튜브 뮤직을 변경하고, 클릭 한 번으로 플러그인을 활성화/비활성화할 수 있습니다.
## 번역
## Content
[Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/)에서 번역을 도울 수 있습니다.
<a href="https://hosted.weblate.org/engage/youtube-music/">
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/multi-auto.svg" alt="번역 상태" />
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="번역 상태 2" />
</a>
## 다운로드
[최신 릴리즈](https://github.com/th-ch/youtube-music/releases/latest)를 확인하여 최신 버전을 빠르게 찾을 수 있습니다.
### Arch Linux
AUR에서 `youtube-music-bin` 패키지를 설치합니다. AUR 설치 지침은 [이 위키 페이지](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)를 참조하세요.
### MacOS
Homebrew를 사용하여 앱을 설치할 수 있습니다:
```bash
brew install --cask https://raw.githubusercontent.com/th-ch/youtube-music/master/youtube-music.rb
```
(앱을 수동으로 설치하고) 앱을 실행할 때 `손상되었기 때문에 열 수 없습니다.`라는 오류가 발생하면 터미널에서 다음을 실행하세요:
```bash
xattr -cr /Applications/YouTube\ Music.app
```
### Windows
[Scoop 패키지 매니저](https://scoop.sh)를 사용하여 [`extras` 버킷](https://github.com/ScoopInstaller/Extras)에서 `youtube-music` 패키지를 설치할 수 있습니다.
```bash
scoop bucket add extras
scoop install extras/youtube-music
```
또는 Windows 11의 공식 CLI 패키지 관리자인 [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)을 사용하여 `th-ch.YouTubeMusic` 패키지를 설치할 수 있습니다.
*참고: "알 수 없는 게시자"의 파일이기 때문에 Microsoft Defender의 SmartScreen에서 설치를 차단할 수 있습니다. 이는 GitHub에서 동일 파일을 수동으로 다운로드한 후 실행 파일(.exe)을 실행하려고 할 때도 마찬가지로 발생합니다.*
```bash
winget install th-ch.YouTubeMusic
```
#### (Windows에서) 네트워크에 연결하지 않고 설치하는 방법은 무엇인가요?
- [릴리즈 페이지](https://github.com/th-ch/youtube-music/releases/latest)에서 _본인 기기 아키텍처_에 맞는 `*.nsis.7z` 파일을 다운로드하세요.
- `x64`는 64비트 Windows 용입니다.
- `ia32`는 32비트 Windows 용입니다.
- `arm64`는 ARM64 Windows 용입니다.
- 릴리즈 페이지에서 설치기를 다운로드하세요. (`*-Setup.exe`)
- 두 파일을 **동일한 위치**에 놓아주세요.
- 설치기를 실행하세요.
- [기능](#기능)
- [사용 가능한 플러그인](#사용-가능한-플러그인)
- [번역](#번역)
- [다운로드](#다운로드)
- [Arch Linux](#arch-linux)
- [MacOS](#macos)
- [Windows](#windows)
- [(Windows에서) 네트워크에 연결하지 않고 설치하는 방법은 무엇인가요?](#windows에서-네트워크에-연결하지-않고-설치하는-방법은-무엇인가요)
- [테마](#테마)
- [개발](#개발)
- [나만의 플러그인 만들기](#나만의-플러그인-만들기)
- [플러그인 만들기](#플러그인-만들기)
- [일반적인 사용 예](#일반적인-사용-예)
- [빌드](#빌드)
- [프로덕션 빌드 미리보기](#프로덕션-빌드-미리보기)
- [테스트](#테스트)
- [라이선스](#라이선스)
- [자주 묻는 질문](#자주-묻는-질문)
## 기능:
@ -156,6 +120,63 @@ winget install th-ch.YouTubeMusic
- **비주얼라이저**: 플레이어에 시각화 도구 추가
## 번역
[Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/)에서 번역을 도울 수 있습니다.
<a href="https://hosted.weblate.org/engage/youtube-music/">
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/multi-auto.svg" alt="번역 상태" />
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="번역 상태 2" />
</a>
## 다운로드
[최신 릴리즈](https://github.com/th-ch/youtube-music/releases/latest)를 확인하여 최신 버전을 빠르게 찾을 수 있습니다.
### Arch Linux
AUR에서 [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) 패키지를 설치합니다. AUR 설치 지침은 [이 위키 페이지](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)를 참조하세요.
### MacOS
Homebrew를 사용하여 앱을 설치할 수 있습니다:
```bash
brew install --cask https://raw.githubusercontent.com/th-ch/youtube-music/master/youtube-music.rb
```
(앱을 수동으로 설치하고) 앱을 실행할 때 `손상되었기 때문에 열 수 없습니다.`라는 오류가 발생하면 터미널에서 다음을 실행하세요:
```bash
xattr -cr /Applications/YouTube\ Music.app
```
### Windows
[Scoop 패키지 매니저](https://scoop.sh)를 사용하여 [`extras` 버킷](https://github.com/ScoopInstaller/Extras)에서 `youtube-music` 패키지를 설치할 수 있습니다.
```bash
scoop bucket add extras
scoop install extras/youtube-music
```
또는 Windows 11의 공식 CLI 패키지 관리자인 [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)을 사용하여 `th-ch.YouTubeMusic` 패키지를 설치할 수 있습니다.
*참고: "알 수 없는 게시자"의 파일이기 때문에 Microsoft Defender의 SmartScreen에서 설치를 차단할 수 있습니다. 이는 GitHub에서 동일 파일을 수동으로 다운로드한 후 실행 파일(.exe)을 실행하려고 할 때도 마찬가지로 발생합니다.*
```bash
winget install th-ch.YouTubeMusic
```
#### (Windows에서) 네트워크에 연결하지 않고 설치하는 방법은 무엇인가요?
- [릴리즈 페이지](https://github.com/th-ch/youtube-music/releases/latest)에서 _본인 기기 아키텍처_에 맞는 `*.nsis.7z` 파일을 다운로드하세요.
- `x64`는 64비트 Windows 용입니다.
- `ia32`는 32비트 Windows 용입니다.
- `arm64`는 ARM64 Windows 용입니다.
- 릴리즈 페이지에서 설치기를 다운로드하세요. (`*-Setup.exe`)
- 두 파일을 **동일한 위치**에 놓아주세요.
- 설치기를 실행하세요.
## 테마
CSS 파일을 로드하여 애플리케이션의 모양을 변경할 수 있습니다(설정 > 시각적 변경 > 테마).
@ -258,7 +279,7 @@ import style from './style.css?inline'; // 스타일을 인라인으로 가져
import { createPlugin } from '@/utils';
const builder = createPlugin({
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // 값이 true면, YTM은 재시작 다이얼로그를 표시합니다
config: {
@ -274,7 +295,7 @@ const builder = createPlugin({
```typescript
import { createPlugin } from '@/utils';
const builder = createPlugin({
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // 값이 true면, YTM은 재시작 다이얼로그를 표시합니다
config: {

View File

@ -1,15 +1,19 @@
import { resolve } from 'node:path';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { defineConfig, defineViteConfig } from 'electron-vite';
import builtinModules from 'builtin-modules';
import viteResolve from 'vite-plugin-resolve';
import Inspect from 'vite-plugin-inspect';
import { pluginVirtualModuleGenerator } from './vite-plugins/plugin-importer';
import pluginLoader from './vite-plugins/plugin-loader';
import { pluginVirtualModuleGenerator } from './vite-plugins/plugin-importer.mjs';
import pluginLoader from './vite-plugins/plugin-loader.mjs';
import type { UserConfig } from 'vite';
import { i18nImporter } from './vite-plugins/i18n-importer';
import { i18nImporter } from './vite-plugins/i18n-importer.mjs';
import solidPlugin from 'vite-plugin-solid';
const __dirname = dirname(fileURLToPath(import.meta.url));
const resolveAlias = {
'@': resolve(__dirname, './src'),
@ -114,6 +118,7 @@ export default defineConfig({
'virtual:i18n': i18nImporter(),
'virtual:plugins': pluginVirtualModuleGenerator('renderer'),
}),
solidPlugin(),
],
root: './src/',
build: {

View File

@ -1,7 +1,7 @@
{
"name": "youtube-music",
"productName": "YouTube Music",
"version": "3.1.0",
"version": "3.3.3",
"description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js",
"license": "MIT",
@ -77,8 +77,8 @@
"rpm"
]
},
"rpm":{
"depends":[
"rpm": {
"depends": [
"/usr/lib64/libuuid.so.1"
]
},
@ -102,20 +102,20 @@
"vite:inspect": "pnpm clean && electron-vite build --mode development && pnpm exec serve .vite-inspect",
"start": "electron-vite preview",
"start:debug": "cross-env ELECTRON_ENABLE_LOGGING=1 pnpm start",
"dev": "electron-vite dev",
"dev": "electron-vite dev --watch",
"dev:debug": "cross-env ELECTRON_ENABLE_LOGGING=1 pnpm dev",
"clean": "del-cli dist && del-cli pack && del-cli .vite-inspect",
"dist": "pnpm clean && pnpm build && electron-builder --win --mac --linux -p never",
"dist:linux": "pnpm clean && pnpm build && electron-builder --linux -p never",
"dist:mac": "pnpm clean && pnpm build && electron-builder --mac dmg:x64 -p never",
"dist:mac:arm64": "pnpm clean && pnpm build && electron-builder --mac dmg:arm64 -p never",
"dist:win": "pnpm clean && pnpm build && electron-builder --win -p never",
"dist:win:x64": "pnpm clean && pnpm build && electron-builder --win nsis-web:x64 -p never",
"dist": "pnpm clean && pnpm build && pnpm electron-builder --win --mac --linux -p never",
"dist:linux": "pnpm clean && pnpm build && pnpm electron-builder --linux -p never",
"dist:mac": "pnpm clean && pnpm build && pnpm electron-builder --mac dmg:x64 -p never",
"dist:mac:arm64": "pnpm clean && pnpm build && pnpm electron-builder --mac dmg:arm64 -p never",
"dist:win": "pnpm clean && pnpm build && pnpm electron-builder --win -p never",
"dist:win:x64": "pnpm clean && pnpm build && pnpm electron-builder --win nsis-web:x64 -p never",
"lint": "eslint .",
"changelog": "npx --yes auto-changelog",
"release:linux": "pnpm clean && pnpm build && electron-builder --linux -p always -c.snap.publish=github",
"release:mac": "pnpm clean && pnpm build && electron-builder --mac -p always",
"release:win": "pnpm clean && pnpm build && electron-builder --win -p always",
"release:linux": "pnpm clean && pnpm build && pnpm electron-builder --linux -p always -c.snap.publish=github",
"release:mac": "pnpm clean && pnpm build && pnpm electron-builder --mac -p always",
"release:win": "pnpm clean && pnpm build && pnpm electron-builder --win -p always",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"engines": {
@ -124,28 +124,33 @@
"pnpm": {
"overrides": {
"usocket": "1.0.1",
"rollup": "4.7.0",
"node-gyp": "10.0.1",
"xml2js": "0.6.2",
"node-fetch": "3.3.2",
"@electron/universal": "2.0.0",
"@babel/runtime": "7.23.2"
"@electron/universal": "2.0.1",
"@babel/runtime": "7.23.8"
},
"patchedDependencies": {
"vudio@2.1.1": "patches/vudio@2.1.1.patch",
"@xhayper/discord-rpc@1.1.2": "patches/@xhayper__discord-rpc@1.1.2.patch"
}
},
"dependencies": {
"@cliqz/adblocker-electron": "1.26.12",
"@cliqz/adblocker-electron-preload": "1.26.12",
"@cliqz/adblocker-electron": "1.26.16",
"@cliqz/adblocker-electron-preload": "1.26.16",
"@electron-toolkit/tsconfig": "1.0.1",
"@electron/remote": "2.1.0",
"@electron/remote": "2.1.2",
"@ffmpeg.wasm/core-mt": "0.12.0",
"@ffmpeg.wasm/main": "0.12.0",
"@foobar404/wave": "2.0.4",
"@floating-ui/dom": "1.6.3",
"@foobar404/wave": "2.0.5",
"@jellybrick/electron-better-web-request": "1.0.4",
"@jellybrick/mpris-service": "2.1.4",
"@xhayper/discord-rpc": "1.1.1",
"async-mutex": "0.4.0",
"@xhayper/discord-rpc": "1.1.2",
"async-mutex": "0.5.0",
"butterchurn": "3.0.0-beta.4",
"butterchurn-presets": "3.0.0-beta.4",
"color": "4.2.3",
"conf": "10.2.0",
"custom-electron-prompt": "1.5.7",
"dbus-next": "0.10.2",
@ -153,56 +158,67 @@
"electron-debug": "3.2.0",
"electron-is": "3.0.0",
"electron-localshortcut": "3.2.1",
"electron-store": "8.1.0",
"electron-store": "8.2.0",
"electron-unhandled": "4.0.1",
"electron-updater": "6.1.7",
"electron-updater": "6.1.8",
"fast-average-color": "9.4.0",
"fast-equals": "5.0.1",
"filenamify": "6.0.0",
"howler": "2.2.4",
"html-to-text": "9.0.5",
"i18next": "23.7.8",
"i18next": "23.10.1",
"keyboardevent-from-electron-accelerator": "2.0.0",
"keyboardevents-areequal": "0.2.2",
"node-html-parser": "6.1.11",
"node-html-parser": "6.1.12",
"node-id3": "0.2.6",
"peerjs": "1.5.2",
"semver": "7.6.0",
"serve": "14.2.1",
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
"ts-morph": "21.0.1",
"solid-floating-ui": "0.3.1",
"solid-js": "1.8.16",
"solid-styled-components": "0.28.5",
"solid-transition-group": "0.2.3",
"ts-morph": "22.0.0",
"vudio": "2.1.1",
"x11": "2.3.0",
"youtubei.js": "8.0.0"
"youtubei.js": "9.1.0"
},
"devDependencies": {
"@playwright/test": "1.41.0-alpha-dec-10-2023",
"@playwright/test": "1.42.1",
"@total-typescript/ts-reset": "0.5.1",
"@types/color": "3.0.6",
"@types/electron-localshortcut": "3.1.3",
"@types/howler": "2.2.11",
"@types/html-to-text": "9.0.4",
"@typescript-eslint/eslint-plugin": "6.13.2",
"@types/semver": "7.5.8",
"@typescript-eslint/eslint-plugin": "7.3.1",
"bufferutil": "4.0.8",
"builtin-modules": "3.3.0",
"cross-env": "7.0.3",
"del-cli": "5.1.0",
"electron": "28.0.0",
"discord-api-types": "0.37.76",
"electron": "29.1.5",
"electron-builder": "24.9.1",
"electron-devtools-installer": "3.2.0",
"electron-vite": "1.0.29",
"eslint": "8.55.0",
"electron-vite": "2.1.0",
"esbuild": "0.20.2",
"eslint": "8.57.0",
"eslint-import-resolver-exports": "1.0.0-beta.5",
"eslint-import-resolver-typescript": "3.6.1",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-prettier": "5.0.1",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-prettier": "5.1.3",
"glob": "10.3.10",
"node-gyp": "10.0.1",
"playwright": "1.41.0-alpha-dec-10-2023",
"rollup": "4.7.0",
"typescript": "5.3.3",
"playwright": "1.42.1",
"rollup": "4.13.0",
"typescript": "5.4.3",
"utf-8-validate": "6.0.3",
"vite": "4.5.1",
"vite-plugin-inspect": "0.8.1",
"vite": "5.2.4",
"vite-plugin-inspect": "0.8.3",
"vite-plugin-resolve": "2.5.1",
"ws": "8.15.0"
"vite-plugin-solid": "2.10.2",
"ws": "8.16.0"
},
"auto-changelog": {
"hideCredit": true,
@ -210,5 +226,5 @@
"unreleased": true,
"output": "changelog.md"
},
"packageManager": "pnpm@8.12.0"
"packageManager": "pnpm@8.15.5"
}

View File

@ -0,0 +1,17 @@
diff --git a/package.json b/package.json
index 40db5dfbd8a4455ce2987d8115eca9882e1f9f14..414fc6986b9c0cc288908eb0107b90c4bfd916b2 100644
--- a/package.json
+++ b/package.json
@@ -25,11 +25,7 @@
},
"dependencies": {
"axios": "^1.6.2",
- "ws": "^8.15.1"
- },
- "optionalDependencies": {
- "bufferutil": "^4.0.8",
- "utf-8-validate": "^6.0.3"
+ "ws": "^8.16.0"
},
"devDependencies": {
"@types/node": "^14.*",

20
patches/vudio@2.1.1.patch Normal file
View File

@ -0,0 +1,20 @@
diff --git a/umd/vudio.js b/umd/vudio.js
index d0d1127e57125ad4e77442af2db4a26998c7b385..c0b66bd4327c65c31dc6e588bfa4ae6ec70bd3b8 100644
--- a/umd/vudio.js
+++ b/umd/vudio.js
@@ -147,7 +147,6 @@
source.connect(this.analyser);
this.analyser.fftSize = this.option.accuracy * 2;
- this.analyser.connect(audioContext.destination);
this.freqByteData = new Uint8Array(this.analyser.frequencyBinCount);
@@ -207,7 +206,6 @@
source.connect(this.analyser);
this.analyser.fftSize = this.option.accuracy * 2;
- this.analyser.connect(audioContext.destination);
},
__rebuildData : function (freqByteData, horizontalAlign) {

1943
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,7 @@ export interface DefaultConfig {
proxy: string;
startingPage: string;
overrideUserAgent: boolean;
usePodcastParticipantAsArtist: boolean;
themes: string[];
};
plugins: Record<string, unknown>;
@ -66,6 +67,7 @@ const defaultConfig: DefaultConfig = {
proxy: '',
startingPage: '',
overrideUserAgent: false,
usePodcastParticipantAsArtist: false,
themes: [],
},
'plugins': {},

View File

@ -1,5 +1,5 @@
import Store from 'electron-store';
import { deepmerge } from 'deepmerge-ts';
import { deepmergeCustom } from 'deepmerge-ts';
import defaultConfig from './defaults';
@ -8,6 +8,10 @@ import plugins from './plugins';
import { restart } from '@/providers/app-controls';
const deepmerge = deepmergeCustom({
mergeArrays: false,
});
const set = (key: string, value: unknown) => {
store.set(key, value);
};

View File

@ -6,6 +6,56 @@ import defaults from './defaults';
import { DefaultPresetList, type Preset } from '@/plugins/downloader/types';
const migrations = {
'>=3.3.0'(store: Conf<Record<string, unknown>>) {
const lastfmConfig = store.get('plugins.lastfm') as {
enabled?: boolean;
token?: string;
session_key?: string;
api_root?: string;
api_key?: string;
secret?: string;
};
if (lastfmConfig) {
let scrobblerConfig = store.get(
'plugins.scrobbler',
) as {
enabled?: boolean;
scrobblers?: {
lastfm?: {
enabled?: boolean;
token?: string;
sessionKey?: string;
apiRoot?: string;
apiKey?: string;
secret?: string;
};
};
} | undefined;
if (!scrobblerConfig) {
scrobblerConfig = {
enabled: lastfmConfig.enabled,
};
}
if (!scrobblerConfig.scrobblers) {
scrobblerConfig.scrobblers = {
lastfm: {},
};
}
scrobblerConfig.scrobblers.lastfm = {
enabled: lastfmConfig.enabled,
token: lastfmConfig.token,
sessionKey: lastfmConfig.session_key,
apiRoot: lastfmConfig.api_root,
apiKey: lastfmConfig.api_key,
secret: lastfmConfig.secret,
};
store.set('plugins.scrobbler', scrobblerConfig);
store.delete('plugins.lastfm');
}
},
'>=3.0.0'(store: Conf<Record<string, unknown>>) {
const discordConfig = store.get('plugins.discord') as Record<
string,

178
src/i18n/resources/bg.json Normal file
View File

@ -0,0 +1,178 @@
{
"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": "bg",
"local-name": "Български",
"name": "Bulgarian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Завърши зареждането. DevTools отворени"
},
"i18n": {
"loaded": "i18n заредено"
},
"second-instance": {
"receive-command": "Получена команда чрез протокол: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS файл \"{{cssFile}}\" не съществува, ингнорира се"
},
"unresponsive": {
"details": "Грешка без отговор!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Изчистване на кешът на аппа"
},
"window": {
"tried-to-render-offscreen": "Прозореца се опита да се изрисува извън екрана, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Менюто е скрито. Използвайте \"Alt\", за да го покажете, или \"Escape\", ако използвате менюто в приложението",
"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": "Копиране на текущия 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": "Замяна на User-Agent",
"restart-on-config-changes": "Рестартиране при промени в конфигурацията",
"set-proxy": {
"label": "Задаване на прокси",
"prompt": {
"label": "Въведете адрес на прокси: (оставете празно, за да деактивирате)",
"placeholder": "Пример: SOCKS5://127.0.0.1:9999",
"title": "Задаване на прокси"
}
},
"toggle-dev-tools": "Активиране на DevTools"
}
},
"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": {
"label": "Тема",
"submenu": {
"import-css-file": "Импортиране на потребителски CSS файл",
"no-theme": "Без тема"
}
}
}
}
}
},
"plugins": {
"enabled": "Активирани",
"label": "Плъгини",
"new": "НОВО"
}
}
}
}

View File

@ -2,13 +2,14 @@
"common": {
"console": {
"plugins": {
"execute-failed": "Selhalo execute pluginu {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} executed at {{ms}}ms",
"initialize-failed": "Selhala initialize \"{{pluginName}}\" pluginu",
"execute-failed": "Selhalo spuštění pluginu {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} spuštěn za {{ms}}ms",
"initialize-failed": "Selhalo zapnutí \"{{pluginName}}\" pluginu",
"load-all": "Načítání všech pluginů",
"load-failed": "Selhalo načtení \"{{pluginName}}\" pluginu",
"loaded": "Plugin \"{{pluginName}}\" načten",
"unload-failed": "Selhalo unload \"{{pluginName}}\" pluginu"
"unload-failed": "Selhalo unload \"{{pluginName}}\" pluginu",
"unloaded": "Plugin {{pluginName}} byl odnačten"
}
}
},
@ -20,7 +21,7 @@
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Dokončeno načítání. DevTools otevřeny"
"dev-tools": "Načítání dokončeno. Vývojářské nástroje se otevřely"
},
"i18n": {
"loaded": "i18n načteno"
@ -32,20 +33,20 @@
"css-file-not-found": "CSS soubor \"{{cssFile}}\" neexistuje, ignorováno"
},
"unresponsive": {
"details": "Unresponsive chyba!\n{{error}}"
"details": "Chyba - Aplikace nereaguje!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Čištění mezipaměti aplikace"
},
"window": {
"tried-to-render-offscreen": "Okno se pokusilo render na pozadí, Velikost okna ={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
"tried-to-render-offscreen": "Okno se pokusilo vykreslit na pozadí, velikost okna = {{windowSize}}, display velikost = {{displaySize}}, pozice = {{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menu je skryté, use 'Alt' to show it (nebo 'Escape', pokud používáte in-app-menu)",
"message": "Skrýt Menu je povoleno",
"title": "Skrýt Menu Povolené"
"detail": "Menu je skryté, stiskněte 'Alt' k jeho zobrazení (nebo 'Escape', pokud používáte in-app-menu)",
"message": "Skrýt menu je povoleno",
"title": "Skrýt menu Povolené"
},
"need-to-restart": {
"buttons": {
@ -72,9 +73,9 @@
"download": "Stáhnout",
"ok": "OK"
},
"detail": "Nová verze je k dispozici a lze stáhnout na {{downloadLink}}",
"detail": "Nová verze je k dispozici a lze ji stáhnout na {{downloadLink}}",
"message": "Nová verze je dostupná",
"title": "Aktualizace k dispozici"
"title": "Aktualizace je k dispozici"
}
},
"menu": {
@ -82,7 +83,7 @@
"navigation": {
"label": "Navigace",
"submenu": {
"copy-current-url": "Kopírovat aktuální URL adresu",
"copy-current-url": "Zkopírovat aktuální URL adresu",
"go-back": "Jít zpátky",
"go-forward": "Jít dopředu",
"quit": "Ukončit",
@ -95,28 +96,28 @@
"advanced-options": {
"label": "Pokročilé možnosti",
"submenu": {
"auto-reset-app-cache": "Při spuštění aplikace, se resetuje její mezipaměť",
"auto-reset-app-cache": "Při spuštění aplikace se resetuje její mezipaměť",
"disable-hardware-acceleration": "Vypnout hardware zrychlení",
"edit-config-json": "Upravit config.json",
"override-user-agent": "Přepsat User-Agent",
"restart-on-config-changes": "Restartovat na změny v konfiguraci",
"override-user-agent": "Přepsat uživatelského agenta",
"restart-on-config-changes": "Restartovat aplikaci na změny v konfiguraci",
"set-proxy": {
"label": "Nastavit proxy",
"prompt": {
"label": "Zadejte adresu proxy: (nechejte prázdné to disable)",
"placeholder": "Příklad: socks5://127.0.0.1:9999",
"label": "Zadejte adresu proxy: (k vypnutí nechte pole prázdné)",
"placeholder": "Příklad: SOCKS5://127.0.0.1:9999",
"title": "Nastavit proxy"
}
},
"toggle-dev-tools": "Toggle Vývojářské nástroje"
"toggle-dev-tools": "Přepínat vývojářské nástroje"
}
},
"always-on-top": "Vždy na vrchu",
"auto-update": "Automatické aktualizace",
"hide-menu": {
"dialog": {
"message": "Menu bude skryto na dalším launch, use [Alt] to show it (nebo backtick [`] pokud používáte in-app-menu)",
"title": "Skrýt Menu Povoleno"
"message": "Menu bude skryto na dalším spuštěním, použijte [Alt] k jeho zobrazení (nebo backtick [`] pokud používáte in-app-menu)",
"title": "Skrýt menu Povoleno"
},
"label": "Skrýt menu"
},
@ -130,14 +131,17 @@
"to-help-translate": "Chcete pomoc s překladem? Klikněte zde"
}
},
"resume-on-start": "Resume poslední písničku při spuštění aplikace",
"resume-on-start": "Při spuštění aplikace, pokračovat na poslední písničce",
"single-instance-lock": "Zámek pro jednu instanci",
"start-at-login": "Zapnutí aplikace po přihlášení",
"starting-page": {
"label": "Úvodní stránka",
"unset": "Nenastaveno"
},
"tray": {
"label": "Tray",
"submenu": {
"disabled": "Vypnuto",
"enabled-and-hide-app": "Povolit a skrýt aplikaci",
"enabled-and-show-app": "Enabled a show aplikaci",
"play-pause-on-click": "Přehrát/Pozastavit na kliknutí"
@ -148,15 +152,15 @@
"submenu": {
"like-buttons": {
"default": "Výchozí",
"force-show": "Vynutit show",
"hide": "Schovat",
"force-show": "Vynutit zobrazení",
"hide": "Skrýt",
"label": "Like tlačítka"
},
"remove-upgrade-button": "Odebrat upgrade tlačítko",
"theme": {
"label": "Motiv",
"submenu": {
"import-css-file": "Import vlastní CSS soubor",
"import-css-file": "Vložit vlastní CSS soubor",
"no-theme": "Žádný motiv"
}
}
@ -166,13 +170,16 @@
},
"plugins": {
"enabled": "Povoleno",
"label": "Pluginy"
"label": "Pluginy",
"new": "NOVÉ"
},
"view": {
"label": "Zobrazení",
"submenu": {
"force-reload": "Vynutit znovu načtení",
"reset-zoom": "Actual velikost",
"reload": "Obnovit",
"reset-zoom": "Skutečná velikost",
"toggle-fullscreen": "Přepnout režim celé obrazovky",
"zoom-in": "Přiblížit",
"zoom-out": "Oddálit"
}
@ -184,7 +191,7 @@
"previous": "Minulý",
"quit": "Ukončit",
"restart": "Restartovat aplikaci",
"show": "Ukázat okno"
"show": "Zobrazit okno"
}
},
"plugins": {
@ -195,14 +202,19 @@
},
"name": "Blokovač reklam"
},
"album-actions": {
"description": "Přidává Undislike, Dislike, Like, a Unlike tlačítka k apply this ke všem písničkám v seznamu písniček nebo albumu.",
"name": "Album akce"
},
"album-color-theme": {
"description": "Použije dynamický motiv a vizuální efekty na základě palety barev alba",
"description": "Používá dynamický motiv a vizuální efekty na základě palety barev alba",
"name": "Motiv podle barvy Alba"
},
"ambient-mode": {
"description": "Applies a lighting efekty pomocí casting gentle barvy z videa, do vašeho screens pozadí.",
"description": "Applies bleskové efekty pomocí casting jemných barev z videa, do vašeho pozadí obrazovky.",
"menu": {
"blur-amount": {
"label": "Množství rozmazání",
"submenu": {
"pixels": "{{blurAmount}} pixelů"
}
@ -234,18 +246,22 @@
"smoothness-transition": {
"label": "Plynulý přechod",
"submenu": {
"during": "Během {{interpolationTime}}s"
"during": "Během {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Používání režimu celé obrazovky"
}
},
"name": "Ambientní režim"
},
"audio-compressor": {
"description": "Apply compression k audiu (snižuje hlasitost nejhlasitěších částí signálu and zvyšuje hlasitost nejjemnějších částí)",
"name": "Audio kompresor"
},
"blur-nav-bar": {
"description": "Udělá navigační panel průhledným a rozmazaným",
"name": "Rozmazaný navigační Bar"
"description": "Udělá navigační panel průhledný a rozmazaný",
"name": "Rozmazaný navigační panel"
},
"bypass-age-restrictions": {
"description": "Obejít ověření věku na YouTube",
@ -270,15 +286,15 @@
}
},
"compact-sidebar": {
"description": "Vždy set the sidebar v kompaktním režimu",
"name": "Kompaktní Sidebar"
"description": "Vždy nastavit postranní panel do kompaktního režimu",
"name": "Kompaktní postranní panel"
},
"crossfade": {
"description": "Crossfade mezi písničkami",
"description": "Prolínání mezi písničkami",
"menu": {
"advanced": "Pokročilý"
},
"name": "Prolínání [beta]",
"name": "Prolínání [Beta]",
"prompt": {
"options": {
"multi-input": {
@ -293,26 +309,35 @@
}
},
"disable-autoplay": {
"description": "Spustí písničku v režimu \"pozastaveno\"",
"menu": {
"apply-once": "Applies jenom na spuštění aplikace"
},
"name": "Zrušit automatické přehrávání"
"name": "Vypnout automatické přehrávání"
},
"discord": {
"backend": {
"already-connected": "Pokusilo se spojit s aktivním spojením",
"connected": "Připojeno k Discordu",
"disconnected": "Odpojeno od Discordu"
},
"description": "Ukažte svým přátelům, co posloucháte s Rich Presence",
"description": "Ukažte svým přátelům, co posloucháte s Bohatou přítomností",
"menu": {
"auto-reconnect": "Automaticky znovu připojit",
"clear-activity": "Vymazat aktivitu",
"clear-activity-after-timeout": "Vymazat aktivitu po timeout",
"connected": "Připojeno",
"disconnected": "Odpojeno",
"hide-duration-left": "Skrýt zbývající duration",
"hide-github-button": "Skrýt tlačítko s odkazem na GitHub",
"play-on-youtube-music": "Hrát na YouTube Music"
"play-on-youtube-music": "Hrát na YouTube Music",
"set-inactivity-timeout": "Nastavit timeout pro neaktivitu"
},
"name": "Discord Bohatá přítomnost",
"prompt": {
"set-inactivity-timeout": {
"label": "Zadejte inactivity timeout v sekundách:"
"label": "Zadejte timeout neaktivity v sekundách:",
"title": "Nastavit timeout pro neaktivitu"
}
}
},
@ -331,70 +356,122 @@
"ok": "OK"
},
"detail": "({{playlistSize}} písničky)",
"message": "Stahování seznamu skladeb {{playlistTitle}}",
"message": "Stahování seznamu písniček {{playlistTitle}}",
"title": "Stahování začalo"
}
},
"feedback": {
"conversion-progress": "Konverze: {{percent}}%",
"done": "Hotovo: {{filePath}}",
"download-info": "Stahování {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Stahování: {{percent}}%",
"downloading": "Stahování…",
"downloading-counter": "Stahování {{current}}/{{total}}…",
"downloading-playlist": "Stahování seznamu skladeb \"{{playlistTitle}}\" - {{playlistSize}} písničky ({{playlistId}})",
"downloading-playlist": "Stahování seznamu písniček \"{{playlistTitle}}\" - {{playlistSize}} písničky ({{playlistId}})",
"error-while-downloading": "Chyba při stahování \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "Složka {{playlistFolder}} již existuje",
"getting-playlist-info": "Getting informace o seznamu skladeb…",
"getting-playlist-info": "Získávání informací o seznamu písniček…",
"loading": "Načítání…",
"playlist-has-only-one-song": "Seznam skladeb má pouze jednu položku, downloading it directly",
"playlist-id-not-found": "Žádné ID seznamu skladeb nenalezeno",
"playlist-is-empty": "Seznam skladeb je prázdný",
"playlist-has-only-one-song": "Seznam písniček má pouze jednu položku, stahuje se přímo",
"playlist-id-not-found": "Žádné ID seznamu písnček nenalezeno",
"playlist-is-empty": "Seznam písniček je prázdný",
"playlist-is-mix-or-private": "Chyba při získávání informací o seznamu písniček: ujistite se, že se nejedná o soukromý nebo \"Namíchaný pro vás\" seznam písniček\n\n{{error}}",
"preparing-file": "Připravování souboru…",
"saving": "Ukládání…",
"trying-to-get-playlist-id": "Trying to get ID seznamu skladeb: {{playlistId}}",
"video-id-not-found": "Video nebylo nalezeno"
"trying-to-get-playlist-id": "Trying se získat ID seznamu písniček: {{playlistId}}",
"video-id-not-found": "Video nebylo nalezeno",
"writing-id3": "Psaní ID3 značek…"
}
},
"description": "Stahuje MP3 / source audio přímo z rozhraní",
"menu": {
"choose-download-folder": "Vybrat download složku",
"download-playlist": "Stáhnout seznam skladeb",
"choose-download-folder": "Vybrat složku pro stahování",
"download-playlist": "Stáhnout seznam písniček",
"presets": "Předvolby",
"skip-existing": "Přeskočit existující soubory"
},
"name": "Stahovač",
"renderer": {
"can-not-update-progress": "Progress nemůže být aktualizován"
},
"templates": {
"button": "Stáhnout"
}
},
"exponential-volume": {
"description": "Dělá posuvník hlasitosti exponenciální, takže je snazší vybrat nižší hlasitost.",
"name": "Exponenciální hlasitost"
},
"in-app-menu": {
"description": "Dává menu-bars a fancy, tmavý nebo album-color vzhled"
},
"last-fm": {
"description": "Přidat scrobbling podporu pro Last.fm",
"name": "Last.fm"
"description": "Dává menu panelům fancy, tmavý nebo album-color vzhled",
"menu": {
"hide-dom-window-controls": "Skrýt DOM window controls"
}
},
"lumiastream": {
"description": "Přidává Lumia Stream podporu"
"description": "Přidává Lumia Stream podporu",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Přidat lyrics podporu pro většinu písniček",
"description": "Přidává lyrics podporu pro většinu písniček",
"renderer": {
"fetched-lyrics": "Fetched lyrics pro Genius"
}
},
"music-together": {
"description": "Sdílejte seznam písniček s ostatními. Když the host hraje písničku, uslyší jí i všichni ostatní.",
"dialog": {
"enter-host": "Zadejte Host ID"
},
"internal": {
"save": "Uložit",
"unknown-user": "Neznámý uživatel"
},
"menu": {
"click-to-copy-id": "Zkopírovat Host ID",
"close": "Zavřít Hudba Spolu",
"connected-users": "Připojení uživatelé",
"disconnect": "Odpojit od Hudby Spolu",
"empty-user": "Žadní připojení uživatelé",
"host": "Hudba Spolu Host",
"join": "Připojit se k Hudbě Spolu",
"permission": {
"all": "Povolit hostům ovládat seznam písniček a přehrávač",
"host-only": "Jenom host může ovládat seznam písniček a přehrávač",
"playlist": "Povolit hostům ovládat seznam písniček"
},
"set-permission": "Změnit ovládací oprávnění",
"status": {
"disconnected": "Odpojen",
"guest": "Připojený/á jako Guest",
"host": "Připojený/á jako Host"
}
},
"name": "Hudba Spolu [Beta]",
"toast": {
"add-song-failed": "Selhalo přidání písničky",
"closed": "Hudba Spolu zavřena",
"disconnected": "Hudba Spolu odpojena",
"host-failed": "Selhalo hostování Hudby Spolu",
"id-copied": "Host ID zkopírováno do schránky",
"join-failed": "Selhalo připojení k Hudba Spolu",
"joined": "Připojil/a jste se k Hudbě Spolu",
"permission-changed": "Oprávnění Hudby Spolu se změnilo na \"{{permission}}\"",
"remove-song-failed": "Selhalo odstranění písničky",
"user-connected": "{{name}} se připojil/a k Hudbě Spolu",
"user-disconnected": "{{name}} odpustil/a Hudba Spolu"
}
},
"navigation": {
"description": "Další/Zpátky navigační šipky přímo integrovány do rozhraní, jako ve vašem oblíbeném prohlížeči",
"name": "Navigace"
},
"no-google-login": {
"description": "Odstranit Google login tlačítka a odkazy z rozhraní",
"description": "Odstranit tlačítka Google přihlášení a odkazy z rozhraní",
"name": "Žádné Google přihlášení"
},
"notifications": {
"description": "Display oznámení when a písnička starts hraje (interactive notifications are available on Windows)",
"description": "Zobrazit oznámení, když písnička začne hrát (interaktiv notifikace jsou dostupné na Windows)",
"menu": {
"interactive": "Interaktivní oznámení",
"interactive-settings": {
@ -402,7 +479,7 @@
"submenu": {
"hide-button-text": "Skrýt text tlačítka",
"refresh-on-play-pause": "Refresh na Přehrát/Pozastavit",
"tray-controls": "Otevřít/Zavřít on tray click"
"tray-controls": "Otevřít/Zavřít aplikaci na kliknutí na tray ikonu"
}
},
"priority": "Priorita Oznámení",
@ -411,6 +488,7 @@
"name": "Oznámení"
},
"picture-in-picture": {
"description": "Povoluje switch aplikaci do režimu obrázek v obrázku",
"menu": {
"always-on-top": "Vždy na vrchu",
"hotkey": {
@ -419,8 +497,8 @@
"keybind-options": {
"hotkey": "Klávesová zkratka"
},
"label": "Vybrat klávesovou zkratku pro toggle obrázek v obrázku",
"title": "Obrázek v obrázku klávesová zkratka"
"label": "Vybrat klávesovou zkratku pro přepínání obrázek v obrázku",
"title": "klávesová zkratka pro obrázek v obrázku"
}
},
"save-window-position": "Uložit pozici okna",
@ -433,14 +511,16 @@
}
},
"playback-speed": {
"description": "Posloiuchej rychle, poslouchej pomalu! Adds a slider, který kontroluje rychlost písníčky",
"description": "Poslouchej rychle, poslouchej pomalu! Přidává slider, který kontroluje rychlost písníčky",
"name": "Rychlost přehrávání",
"templates": {
"button": "Rychlost"
}
},
"precise-volume": {
"description": "Přesná kontrola hlasitosti pomocí kolečka myši/klávesnicových zkratek, s vlastní HUD a customizable hlasitostních steps",
"menu": {
"custom-volume-steps": "Nastavit vlastní hlasitostní steps",
"global-shortcuts": "Globální klávesové zkratky"
},
"name": "Přesná hlasitost",
@ -449,7 +529,13 @@
"keybind-options": {
"decrease": "Snížit hlasitost",
"increase": "Zvýšit hlasitost"
}
},
"label": "Vybrat globální klávesnicové zkratky:",
"title": "Globální klávesnicové zkratky hlasitosti"
},
"volume-steps": {
"label": "Vybrat Zvýšení/Snížení hlasitost Steps",
"title": "Hlasitostní steps"
}
}
},
@ -462,11 +548,15 @@
"title": "Vybrat kvalitu videa"
}
}
}
},
"description": "Umožňuje měnit kvalitu videa pomocí tlačítka na video overlay",
"name": "Měnič kvality videa"
},
"shortcuts": {
"description": "Dovoluje nastavit globální klávesové zkratky pro playback (přehrát/pozastavit/další/předchozí) a vypínání media OSD pomocí přepisování media klíčů, zapínání Ctrl/CMD + F k vyhledávání, zapínání Linux MPRIS podporu pro media klíče, a vlastní klávesové zkratky pro pokročilé uživatele.",
"menu": {
"override-media-keys": "Přepsat Media Keys"
"override-media-keys": "Přepsat media klíče",
"set-keybinds": "Nastavit globální Controls písniček"
},
"name": "Zkratky (& MPRIS)",
"prompt": {
@ -475,19 +565,26 @@
"next": "Další",
"play-pause": "Přehrát / Pozastavit",
"previous": "Předchozí"
}
},
"label": "Vybrat globální klávesnicové zkratky pro ovládání písniček:",
"title": "Globální klávesnicové zkratky"
}
}
},
"skip-disliked-songs": {
"description": "Přeskakovat disliked písničky",
"name": "Přeskočit Disliked písničky"
},
"skip-silences": {
"description": "Automaticky přeskakovat tichá místa v písničkách",
"name": "Přeskočit Tichá místa"
"name": "Přeskakovat Tichá místa"
},
"sponsorblock": {
"description": "Automaticky přeskakuje non-music části jako intro/outro nebo části of music videos, kde nehraje písnčka"
"description": "Automaticky přeskakuje nehudební části jako intro/outro nebo části hudebních videí, kde nehraje písnčka",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Ovládejte přehrávání z vašeho hlavního panelu Windows",
"description": "Ovládejte přehrávání z vašeho Windows hlavního panelu",
"name": "Hlavní panel Media Control"
},
"touchbar": {
@ -495,10 +592,11 @@
"name": "Touch Bar"
},
"tuna-obs": {
"description": "Integrace s OBS's plugin Tuna"
"description": "Integrace s OBS's plugin Tuna",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Přidává tlačítko switch mezi videem/písničkou mode. Může také optionally remove celou video kartu",
"description": "Přidává tlačítko k switch mezi video/písničko režimem. Může také odstranit celou video kartu",
"menu": {
"align": {
"label": "Zarovnání",
@ -510,9 +608,15 @@
},
"force-hide": "Vynutit odstranění karty videa",
"mode": {
"label": "Režim"
"label": "Režim",
"submenu": {
"custom": "Vlastní přepínač",
"disabled": "Vypnuto",
"native": "Původní přepínač"
}
}
},
"name": "Přepínač videa",
"templates": {
"button": "Písnička"
}

View File

@ -44,9 +44,9 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menü ist versteckt, nutze 'Alt', um es zu zeigen (oder 'Escape' beim Verwenden des In-App-Menüs)",
"detail": "Das Menü ist versteckt, nutze 'Alt', um es zu aufzurufen (oder 'Escape' beim Verwenden des In-App-Menüs)",
"message": "Menü verstecken ist aktiviert",
"title": "Menü Verstecken Aktiviert"
"title": "Menü verstecken aktiviert"
},
"need-to-restart": {
"buttons": {
@ -55,7 +55,7 @@
},
"detail": "\"{{pluginName}}\"-Erweiterung erfordert einen Neustart, um in Kraft zu treten",
"message": "\"{{pluginName}}\" muss neugestartet werden",
"title": "Neustart Erforderlich"
"title": "Neustart erforderlich"
},
"unresponsive": {
"buttons": {
@ -75,7 +75,7 @@
},
"detail": "Eine neue Version ist verfügbar und kann unter {{downloadLink}} heruntergeladen werden",
"message": "Eine neue Version ist verfügbar",
"title": "Aktualisierung Verfügbar"
"title": "Aktualisierung verfügbar"
}
},
"menu": {
@ -87,7 +87,7 @@
"go-back": "Zurück gehen",
"go-forward": "Vorwärts gehen",
"quit": "Beenden",
"restart": "Anwendung Neustarten"
"restart": "Anwendung neustarten"
}
},
"options": {
@ -105,7 +105,7 @@
"label": "Proxy setzen",
"prompt": {
"label": "Proxy-Adresse eingeben: (leer lassen zum Ausschalten)",
"placeholder": "Beispiel: socks5://127.0.0.1:9999",
"placeholder": "Beispiel: SOCKS5://127.0.0.1:9999",
"title": "Proxy setzen"
}
},
@ -124,7 +124,7 @@
"language": {
"dialog": {
"message": "Sprache wird nach Neustart geändert",
"title": "Sprache Geändert"
"title": "Sprache geändert"
},
"label": "Sprache",
"submenu": {
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "Aktiviert",
"label": "Erweiterungen"
"label": "Erweiterungen",
"new": "NEU"
},
"view": {
"label": "Ansicht",
@ -190,7 +191,11 @@
"previous": "Vorheriges",
"quit": "Beenden",
"restart": "Anwendung neu starten",
"show": "Fenster anzeigen"
"show": "Fenster anzeigen",
"tooltip": {
"default": "YouTube Musik",
"with-song-info": "YouTube Musik: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -201,12 +206,24 @@
},
"name": "Werbeblocker"
},
"album-actions": {
"description": "Fügt Undislike, Dislike, Like und Unlike-Knöpfe hinzu, welche sich auf alle Lieder in einer Playlist oder Album auswirken",
"name": "Album-Aktionen"
},
"album-color-theme": {
"description": "Wendet ein dynamisches Farbthema und visuelle Effekte auf Basis der Farbpalette des Albumcovers an",
"menu": {
"color-mix-ratio": {
"label": "Farbmischungsverhältnis",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Thema aus Albumfarbe"
},
"ambient-mode": {
"description": "Fügt einen Lichteffekt durch sanftes Abstreifen der Farben des Videos in deinen Bildschirmhintergrund hinzu.",
"description": "Fügt einen Lichteffekt durch sanftes Abstreifen der Farben des Videos in deinen Bildschirmhintergrund hinzu",
"menu": {
"blur-amount": {
"label": "Unschärfemenge",
@ -221,7 +238,7 @@
}
},
"opacity": {
"label": "Durchsichtigkeit",
"label": "Transparenz",
"submenu": {
"percent": "{{opacity}}%"
}
@ -266,7 +283,7 @@
"description": "Untertitelwähler für YouTube Music-Audio-Lieder",
"menu": {
"autoload": "Wähle automatisch den zuletzt verwendeten Untertitel",
"disable-captions": "Standartmäßig keine Untertitel"
"disable-captions": "Standardmäßig keine Untertitel"
},
"name": "Untertitelwähler",
"prompt": {
@ -408,10 +425,6 @@
},
"name": "In-App Menü"
},
"last-fm": {
"description": "Scrobbling-Unterstützung für Last.fm hinzufügen",
"name": "Last.fm"
},
"lumiastream": {
"description": "Fügt Unterstützung für Lumia Stream hinzu",
"name": "Lumia Stream [Beta]"
@ -426,6 +439,52 @@
"fetched-lyrics": "Liedtexte für Genius abgerufen"
}
},
"music-together": {
"description": "Teile eine Wiedergabeliste mit anderen. Wenn der Host ein Lied abspielt, hören alle anderen das gleiche Lied",
"dialog": {
"enter-host": "Host ID eingeben"
},
"internal": {
"save": "Speichern",
"track-source": "Quelle verfolgen",
"unknown-user": "Unbekannter Nutzer"
},
"menu": {
"click-to-copy-id": "Host ID kopieren",
"close": "Music Together schließen",
"connected-users": "Verbundene Benutzer",
"disconnect": "Verbindung zu Music Together trennen",
"empty-user": "Keine verbundenen Benutzer",
"host": "Host für Music Together",
"join": "Music Together beitreten",
"permission": {
"all": "Gästen erlauben, Wiederhabeliste und Player zu bedienen",
"host-only": "Nur der Host kann die Playlist und den Player kontrollieren",
"playlist": "Gäste das Kontrollieren der Playlist erlauben"
},
"set-permission": "Kontrollberechtigung ändern",
"status": {
"disconnected": "Verbindung getrennt",
"guest": "Als Gast verbunden",
"host": "Als Host verbunden"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Song hinzufügen gescheitert",
"closed": "Music Together geschlossen",
"disconnected": "Verbindung zu Music Together getrennt",
"host-failed": "Hosten von Music Together gescheitert",
"id-copied": "Host ID in die Zwischenablage kopiert",
"id-copy-failed": "Kopieren der Host ID in die Zwischenablage gescheitert",
"join-failed": "Beitreten zu Music Together gescheitert",
"joined": "Music Together beigetreten",
"permission-changed": "Music Together-Berechtigung zu \"{{permission}}\" geändert",
"remove-song-failed": "Entfernen des Liedes gescheitert",
"user-connected": "{{name}} ist Music Together beigetreten",
"user-disconnected": "{{name}} hat Music Together verlassen"
}
},
"navigation": {
"description": "Vorwärts/Zurück Navigationspfeile direkt in die Oberfläche integriert - wie in deinem geliebten Browser",
"name": "Navigation"
@ -470,9 +529,9 @@
"save-window-size": "Fenstergröße speichern",
"use-native-pip": "Browsereigenes PiP verwenden"
},
"name": "Bild im Bild",
"name": "Bild-im-Bild",
"templates": {
"button": "Bild im Bild"
"button": "Bild-im-Bild"
}
},
"playback-speed": {
@ -518,8 +577,41 @@
"description": "Erlaubt die Videoqualität über einen Knopf auf dem Video",
"name": "Videoqualitätsänderer"
},
"scrobbler": {
"description": "Scrobbling-Unterstützung aktivieren (z.B. für last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Die Authentifizierung von Last.fm ist fehlgeschlagen.\nBlende das Pop-up bis zum nächsten Neustart aus.",
"title": "Authentifizierung fehlgeschlagen"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API Einstellungen"
},
"listenbrainz": {
"token": "ListenBrainz-Benutzer-Token eintragen"
},
"scrobble-other-media": "Andere Medien scrobbeln"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Last.fm API-Schlüssel",
"api-secret": "Last.fm API-Kennwort"
},
"listenbrainz": {
"token": {
"label": "ListenBrainz-Benutzer-Token eintragen:",
"title": "ListenBrainz-Token"
}
}
}
},
"shortcuts": {
"description": "Ermöglicht das Festlegen globaler Hotkeys für die Wiedergabe (Abspielen/Pause/Nächstes/Vorheriges) + Deaktivieren des Medien-OSD durch Überschreiben der Medientasten + Aktivieren von Strg/CMD + F zum Suchen + Aktivieren der Linux mpris-Unterstützung für Medientasten + Angepasste Tastenkürzel für fortgeschrittene Benutzer",
"description": "Ermöglicht das Festlegen globaler Hotkeys für die Wiedergabe (Abspielen/Pause/Nächster/Vorheriger) + Deaktivieren des Medien-OSD durch Überschreiben der Medientasten + Aktivieren von Strg/CMD + F zum Suchen + Aktivieren der Linux mpris-Unterstützung für Medientasten + Angepasste Tastenkürzel für fortgeschrittene Benutzer",
"menu": {
"override-media-keys": "Medientasten überschreiben",
"set-keybinds": "Globale Liedsteuerung setzen"
@ -537,6 +629,10 @@
}
}
},
"skip-disliked-songs": {
"description": "Überspringt Lieder, die ihnen nicht gefallen",
"name": "Überspring Lieder, die ihnen nicht gefallen"
},
"skip-silences": {
"description": "Automatisch stille Abschnitte in Liedern überspringen",
"name": "Stille überspringen"

View File

@ -1,4 +1,11 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Αποτυχία εκτέλεσης προσθέτου {{pluginName}}::{{contextName}}"
}
}
},
"language": {
"code": "el",
"local-name": "Ελληνικά",
@ -192,9 +199,6 @@
"button": "Download"
}
},
"last-fm": {
"name": "Last.fm"
},
"navigation": {
"name": "Navigation"
},

View File

@ -44,7 +44,7 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menu is hidden, use 'Alt' to show it (or 'Escape' if using in-app-menu)",
"detail": "Menu is hidden, use 'Alt' to show it (or 'Escape' if using In-App Menu)",
"message": "Hide Menu is enabled",
"title": "Hide Menu Enabled"
},
@ -96,7 +96,7 @@
"advanced-options": {
"label": "Advanced options",
"submenu": {
"auto-reset-app-cache": "Reset App cache when app starts",
"auto-reset-app-cache": "Reset app cache when app starts",
"disable-hardware-acceleration": "Disable hardware acceleration",
"edit-config-json": "Edit config.json",
"override-user-agent": "Override User-Agent",
@ -105,7 +105,7 @@
"label": "Set proxy",
"prompt": {
"label": "Enter Proxy Address: (leave empty to disable)",
"placeholder": "Example: socks5://127.0.0.1:9999",
"placeholder": "Example: SOCKS5://127.0.0.1:9999",
"title": "Set proxy"
}
},
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "Enabled",
"label": "Plugins"
"label": "Plugins",
"new": "NEW"
},
"view": {
"label": "View",
@ -190,7 +191,11 @@
"previous": "Previous",
"quit": "Exit",
"restart": "Restart App",
"show": "Show window"
"show": "Show window",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -199,14 +204,26 @@
"menu": {
"blocker": "Blocker"
},
"name": "Adblocker"
"name": "Ad Blocker"
},
"album-actions": {
"description": "Adds Undislike, Dislike, Like, and Unlike buttons to apply this to all songs in a playlist or album",
"name": "Album Actions"
},
"album-color-theme": {
"description": "Applies a dynamic theme and visual effects based on the album color palette",
"name": "Album Color Theme"
"name": "Album Color Theme",
"menu": {
"color-mix-ratio": {
"label": "Color mix ratio",
"submenu": {
"percent": "{{ratio}}%"
}
}
}
},
"ambient-mode": {
"description": "Applies a lighting effect by casting gentle colors from the video, into your screens background.",
"description": "Applies a lighting effect by casting gentle colors from the video, into your screens background",
"menu": {
"blur-amount": {
"label": "Blur amount",
@ -241,7 +258,7 @@
"smoothness-transition": {
"label": "Smoothness transition",
"submenu": {
"during": "During {{interpolationTime}}s"
"during": "During {{interpolationTime}} s"
}
},
"use-fullscreen": {
@ -289,12 +306,12 @@
"menu": {
"advanced": "Advanced"
},
"name": "Crossfade [beta]",
"name": "Crossfade [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Fade in duration (milliseconds)",
"fade-out-duration": "Fade out duration (milliseconds)",
"fade-in-duration": "Fade in duration (ms)",
"fade-out-duration": "Fade out duration (ms)",
"fade-scaling": {
"label": "Fade scaling",
"linear": "Linear",
@ -408,13 +425,9 @@
},
"name": "In-App Menu"
},
"last-fm": {
"description": "Add scrobbling support for Last.fm",
"name": "Last.fm"
},
"lumiastream": {
"description": "Adds Lumia Stream support",
"name": "Lumia Stream [beta]"
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Adds lyrics support for most songs",
@ -426,6 +439,52 @@
"fetched-lyrics": "Fetched lyrics for Genius"
}
},
"music-together": {
"description": "Share a playlist with others. When the host plays a song, everyone else will hear the same song",
"dialog": {
"enter-host": "Enter Host ID"
},
"internal": {
"save": "Save",
"track-source": "Track Source",
"unknown-user": "Unknown User"
},
"menu": {
"click-to-copy-id": "Copy Host ID",
"close": "Close Music Together",
"connected-users": "Connected Users",
"disconnect": "Disconnect Music Together",
"empty-user": "No connected users",
"host": "Music Together Host",
"join": "Join Music Together",
"permission": {
"all": "Allow guests to control playlist and player",
"host-only": "Only the host can control playlist and player",
"playlist": "Allow guests to control playlist"
},
"set-permission": "Change Control Permission",
"status": {
"disconnected": "Disconnected",
"guest": "Connected as Guest",
"host": "Connected as Host"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Failed to add song",
"closed": "Music Together closed",
"disconnected": "Music Together disconnected",
"host-failed": "Failed to host Music Together",
"id-copied": "Host ID copied to clipboard",
"id-copy-failed": "Failed to copy Host ID to clipboard",
"join-failed": "Failed to join Music Together",
"joined": "Joined Music Together",
"permission-changed": "Music Together permission changed to \"{{permission}}\"",
"remove-song-failed": "Failed to remove song",
"user-connected": "{{name}} joined Music Together",
"user-disconnected": "{{name}} left Music Together"
}
},
"navigation": {
"description": "Next/Back navigation arrows directly integrated in the interface, like in your favorite browser",
"name": "Navigation"
@ -462,17 +521,17 @@
"keybind-options": {
"hotkey": "Hotkey"
},
"label": "Choose a hotkey for toggle Picture in Picture",
"title": "Picture in Picture Hotkey"
"label": "Choose a hotkey to toggle picture-in-picture",
"title": "Picture-in-picture Hotkey"
}
},
"save-window-position": "Save window position",
"save-window-size": "Save window size",
"use-native-pip": "Use browser native PiP"
},
"name": "Picture in Picture",
"name": "Picture-in-picture",
"templates": {
"button": "Picture in Picture"
"button": "Picture-in-picture"
}
},
"playback-speed": {
@ -518,8 +577,41 @@
"description": "Allows changing the video quality with a button on the video overlay",
"name": "Video Quality Changer"
},
"scrobbler": {
"description": "Add scrobbling support (etc. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"title": "Authentication Failed",
"message": "Failed to authenticate with Last.fm\nHide the popup until the next restart."
}
}
},
"menu": {
"scrobble-other-media": "Scrobble other media",
"lastfm": {
"api-settings": "Last.fm API Settings"
},
"listenbrainz": {
"token": "Enter ListenBrainz user token"
}
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Last.fm API key",
"api-secret": "Last.fm API secret"
},
"listenbrainz": {
"token": {
"label": "Enter your ListenBrainz user token:",
"title": "ListenBrainz token"
}
}
}
},
"shortcuts": {
"description": "Allows setting global hotkeys for playback (play/pause/next/previous) + disable media osd by overriding media keys + enable Ctrl/CMD + F to search + enable linux mpris support for mediakeys + custom hotkeys for advanced users",
"description": "Allows setting global hotkeys for playback (play/pause/next/previous) and turning off media OSD by overriding media keys, turning on Ctrl/CMD + F to search, turning on Linux MPRIS support for media keys, and custom hotkeys for advanced users",
"menu": {
"override-media-keys": "Override Media Keys",
"set-keybinds": "Set Global Song Controls"

View File

@ -15,13 +15,13 @@
},
"language": {
"code": "es",
"local-name": "Inglés",
"name": "Inglés"
"local-name": "Español",
"name": "Spanish"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Carga Finalizada. DevTools abiertas"
"dev-tools": "Carga finalizada. DevTools abiertos"
},
"i18n": {
"loaded": "i18n cargado"
@ -44,7 +44,7 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "El menú está oculto, use 'Alt' para mostrarlo (o 'Escape' si usa en-app-menu)",
"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",
"title": "Menú oculto activado"
},
@ -96,7 +96,7 @@
"advanced-options": {
"label": "Opciones avanzadas",
"submenu": {
"auto-reset-app-cache": "Restablecer la caché cuando se inicie la aplicación",
"auto-reset-app-cache": "Restablecer la caché de la aplicación al iniciarla",
"disable-hardware-acceleration": "Desactivar la aceleración por hardware",
"edit-config-json": "Editar config.json",
"override-user-agent": "sobrescribir User-Agent",
@ -105,7 +105,7 @@
"label": "Definir proxy",
"prompt": {
"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",
"title": "Establecer proxy"
}
},
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "Habilitado",
"label": "Plugins"
"label": "Plugins",
"new": "NUEVO"
},
"view": {
"label": "Ver",
@ -190,7 +191,11 @@
"previous": "Anterior",
"quit": "Salir",
"restart": "Reiniciar la aplicación",
"show": "Mostrar ventana"
"show": "Mostrar ventana",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -199,14 +204,26 @@
"menu": {
"blocker": "Bloqueador"
},
"name": "Adblocker"
"name": "Bloqueador de anuncios"
},
"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",
"name": "Acciones en el álbum"
},
"album-color-theme": {
"description": "Aplica un tema dinámico y efectos visuales basados en la paleta de colores del álbum",
"menu": {
"color-mix-ratio": {
"label": "Proporción de la mezcla de colores",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Color del álbum"
},
"ambient-mode": {
"description": "Aplica un efecto de iluminación proyectando 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 del vídeo en el fondo de la pantalla",
"menu": {
"blur-amount": {
"label": "Cantidad de desenfoque",
@ -241,7 +258,7 @@
"smoothness-transition": {
"label": "Transición suave",
"submenu": {
"during": "Durante {{interpolationTime}}s"
"during": "Durante {{interpolationTime}} s"
}
},
"use-fullscreen": {
@ -289,12 +306,12 @@
"menu": {
"advanced": "Avanzado"
},
"name": "Crossfade [beta]",
"name": "Crossfade [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Duración del fundido (milliseconds)",
"fade-out-duration": "Duración del fundido de salida (milliseconds)",
"fade-in-duration": "Duración del fundido (ms)",
"fade-out-duration": "Duración del fundido de salida (ms)",
"fade-scaling": {
"label": "Escala de fundido",
"linear": "Lineal",
@ -408,24 +425,66 @@
},
"name": "Menú de aplicación"
},
"last-fm": {
"description": "Añade soporte de scrobbling para Last.fm",
"name": "Last.fm"
},
"lumiastream": {
"description": "Agrega soporte para Lumia Stream",
"name": "Lumia Stream [beta]"
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Añade el soporte para las letras para la mayoría de las canciones",
"menu": {
"romanized-lyrics": "Letras Romanizadas"
},
"name": "Lyrics Genius",
"name": "Letras Genius",
"renderer": {
"fetched-lyrics": "Letras recuperadas de Genius"
}
},
"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",
"dialog": {
"enter-host": "Introduzca el ID del host"
},
"internal": {
"save": "Guardar",
"track-source": "Fuente de la pista",
"unknown-user": "Usuario desconocido"
},
"menu": {
"click-to-copy-id": "Copiar el ID del host",
"close": "Cerrar Music Together",
"connected-users": "Usuarios conectados",
"disconnect": "Desactivar Music Together",
"empty-user": "No hay usuarios conectados",
"host": "Host de Music Together",
"join": "Únase a Music Together",
"permission": {
"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",
"playlist": "Permita que los invitados controlen la lista de reproducción"
},
"set-permission": "Permiso de control de cambios",
"status": {
"disconnected": "Desconectado",
"guest": "Conectado como invitado",
"host": "Conectado como anfitrión"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "No se puede añadir la canción",
"closed": "Music Together cerrado",
"disconnected": "Music Together desconectados",
"host-failed": "Fallo el host de Music Together",
"id-copied": "ID del host copiado en el portapapeles",
"id-copy-failed": "No se ha podido copiar el ID del host en el portapapeles",
"join-failed": "Fallo en la unión a Music Together",
"joined": "Unido a Music Together",
"permission-changed": "Permiso de Music Together cambiado a \"{{permission}}\"",
"remove-song-failed": "Error al eliminar la canción",
"user-connected": "{{name}} se unió a Music Together",
"user-disconnected": "{{name}} dejó Music Together"
}
},
"navigation": {
"description": "Flechas de navegación Siguiente/Atrás directamente integradas en la interfaz, como en tu navegador favorito",
"name": "Navegación"
@ -462,17 +521,17 @@
"keybind-options": {
"hotkey": "Tecla de acceso rápido"
},
"label": "Elige una tecla de acceso rápido para alternar al modo \"Dos imágenes a la vez\" PiP",
"title": "Tecla de acceso rápido al modo \"Dos imágenes a la vez\" PiP"
"label": "Elige una tecla de acceso rápido para activar la función de imagen en imagen",
"title": "Tecla de acceso directo a imagen en imagen"
}
},
"save-window-position": "Guardar la posición 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"
},
"name": "Imagen en Imagen",
"name": "Imagen en imagen",
"templates": {
"button": "Imagen en Imagen"
"button": "Imagen en imagen"
}
},
"playback-speed": {
@ -518,8 +577,41 @@
"description": "Permite cambiar la calidad del vídeo con un botón sobre puesto en el vídeo",
"name": "Ajustador de calidad de vídeo"
},
"scrobbler": {
"description": "Añadir soporte para scrobbling (last.fm, Listenbrainz, etc.)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Error al autenticar con Last.fm\nOcultar la ventana emergente hasta el próximo reinicio.",
"title": "Error de autenticación"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Ajustes de la API de Last.fm"
},
"listenbrainz": {
"token": "Introduzca el token de usuario de ListenBrainz"
},
"scrobble-other-media": "Scrobble en otros medios"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Clave de la API de Last.fm",
"api-secret": "Clave secreta de la API de Last.fm"
},
"listenbrainz": {
"token": {
"label": "Introduzca su token de usuario de ListenBrainz:",
"title": "Token de ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Permite ajustar atajos de teclado generales para reproducción (reproducir/pausar/siguiente/previo) + deshabilita OSD de medios mediante la anulación de las teclas de medios + habilitar Ctrl/CMD + F para buscar + habilitar soporte mpris de linux para teclas de medios + atajos de teclado personalizados para usuarios avanzados",
"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",
"menu": {
"override-media-keys": "Anular teclas de medios",
"set-keybinds": "Configurar controles globales de canciones"

View File

@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "Activé",
"label": "Extensions"
"label": "Extensions",
"new": "NOUVELLE"
},
"view": {
"label": "Vue",
@ -190,7 +191,11 @@
"previous": "Précédent",
"quit": "Quitter",
"restart": "Redémarrer l'application",
"show": "Afficher la fenêtre"
"show": "Afficher la fenêtre",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -201,6 +206,10 @@
},
"name": "Bloqueur de publicités"
},
"album-actions": {
"description": "Ajoute les boutons Dislike, Undislike, Like, et Unlike à appliquer sur toutes les chansons dans un playlist ou un album.",
"name": "Actions d'Album"
},
"album-color-theme": {
"description": "Applique un thème dynamique et des effets visuels basés sur la palette des couleurs de l'album",
"name": "Thème de couleur d'album"
@ -289,7 +298,7 @@
"menu": {
"advanced": "Avancé"
},
"name": "Fondu enchaîné [bêta]",
"name": "Fondu enchaîné [Bêta]",
"prompt": {
"options": {
"multi-input": {
@ -363,7 +372,7 @@
"converting": "Conversion…",
"done": "Terminé : {{filePath}}",
"download-info": "Téléchargement {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Télécharger: {{percent}}%",
"download-progress": "Téléchargé : {{percent}}%",
"downloading": "Télécharge…",
"downloading-counter": "Télécharge {{current}}/{{total}}…",
"downloading-playlist": "Téléchargement de la playlist \"{{playlistTitle}}\"  {{playlistSize}} chansons ({{playlistId}})",
@ -408,13 +417,9 @@
},
"name": "Menu intégré à l'application"
},
"last-fm": {
"description": "Ajouter le support du scrobbling pour Last.fm",
"name": "Last.fm"
},
"lumiastream": {
"description": "Ajoute la prise en charge de Lumia Stream",
"name": "Lumia Stream [bêta]"
"name": "Lumia Stream [Bêta]"
},
"lyrics-genius": {
"description": "Ajoute la prise en charge des paroles pour la plupart des chansons",
@ -426,6 +431,52 @@
"fetched-lyrics": "Paroles récupérées pour Genius"
}
},
"music-together": {
"description": "Partage une playlist avec d'autres personnes. Quand l'hôte joue un son, tout les participants entendront le même son",
"dialog": {
"enter-host": "Entrer l'identifiant de l'hôte"
},
"internal": {
"save": "Enregistrer",
"track-source": "Source de la piste audio",
"unknown-user": "Utilisateur inconnu"
},
"menu": {
"click-to-copy-id": "Copier l'identifiant de l'hôte",
"close": "Fermer Music Together",
"connected-users": "Utilisateurs connectés",
"disconnect": "Déconnecter Music Together",
"empty-user": "Aucun utilisateur connecté",
"host": "Hôte du Music Together",
"join": "Rejoindre le Music Together",
"permission": {
"all": "Autorisez les invités à contrôler la musique et le player",
"host-only": "Seulement l'hôte peut contrôler les playlists et le lecteur",
"playlist": "Autoriser les invités à contrôler les playlists"
},
"set-permission": "Changer les permissions de contrôle",
"status": {
"disconnected": "Déconnecté",
"guest": "Connecté en tant qu'invité",
"host": "Connecté en tant qu'hôte"
}
},
"name": "Music Together [BETA]",
"toast": {
"add-song-failed": "Echec d'ajout de musique",
"closed": "Music Together fermé",
"disconnected": "Music Together déconnecté",
"host-failed": "Echec de l'hébergement du Music Together",
"id-copied": "Identifiant de l'hôte copié dans le presse papier",
"id-copy-failed": "Echec de la copie de l'identifiant de l'hôte dans le presse papier",
"join-failed": "Echec en rejoignant le Music Together",
"joined": "Rejoint le Music Together",
"permission-changed": "Permission du Music Together changé à \"{{permission}}\"",
"remove-song-failed": "Echec du retrait de la piste",
"user-connected": "{{name}} à rejoint le Music Together",
"user-disconnected": "{{name}} à quitté le Music Together"
}
},
"navigation": {
"description": "Flèches de navigation Suivant/Retour directement intégrées dans l'interface, comme dans votre navigateur préféré",
"name": "Navigation"
@ -518,8 +569,41 @@
"description": "Permet de changer la qualité vidéo avec un bouton sur la vidéo",
"name": "Changeur de qualité vidéo"
},
"scrobbler": {
"description": "Ajouter le support de scrobbling (ex. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Erreur lors de l'authetification avec Last.fm\nCachez la popup jusqu'au prochain redémarrage.",
"title": "Authentification échouée"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Paramètres API de Last.fm"
},
"listenbrainz": {
"token": "Entrer le token utilisateur de ListenBrainz"
},
"scrobble-other-media": "Scrobbler d'autres médias"
},
"name": "Scrobble",
"prompt": {
"lastfm": {
"api-key": "Clé API de Last.fm",
"api-secret": "API secret de Last.fm"
},
"listenbrainz": {
"token": {
"label": "Entrez votre token utilisateur ListenBrainz:",
"title": "Token ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Permet de définir des raccourcis clavier globaux pour la lecture (lecture/pause/suivant/précédent) + désactiver l'OSD multimédia en remplaçant les touches multimédias + activer Ctrl/CMD + F pour rechercher + activer la prise en charge Linux MPRIS pour les touches multimédias + raccourcis clavier personnalisés pour les utilisateurs avancés",
"description": "Permet de définir des raccourcis clavier globaux pour la lecture (lecture/pause/suivant/précédent) + désactiver l'OSD multimédia en remplaçant les touches multimédias + activer Ctrl/CMD + F pour rechercher + activer la prise en charge Linux MPRIS pour les touches multimédias + raccourcis clavier personnalisés pour les utilisateurs avancés.",
"menu": {
"override-media-keys": "Remplacer les touches multimédias",
"set-keybinds": "Définir les contrôles globaux des morceaux"
@ -537,6 +621,10 @@
}
}
},
"skip-disliked-songs": {
"description": "Passer les musiques que je n'aime pas",
"name": "Passer Chansons Déplaisantes"
},
"skip-silences": {
"description": "Ignorer automatiquement les sections de silence dans les chansons",
"name": "Passer les silences"

100
src/i18n/resources/hu.json Normal file
View File

@ -0,0 +1,100 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Nem sikerült futtatni a plugint {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} a {{ms}}ms időpontban végrehajtott",
"initialize-failed": "Nem sikerült inicializálni a \"{{pluginName}}\" plugint",
"load-all": "Összes bővítmény betöltése",
"load-failed": "Nem sikerült betölteni a \"{{pluginName}}\" plugint",
"loaded": "Plugin \"{{pluginName}}\" betöltve",
"unload-failed": "Nem sikerült a \"{{pluginName}}\" bővítményt letölteni",
"unloaded": "A \"{{pluginName}}\" bővítményt nem töltötték be"
}
}
},
"language": {
"code": "hu",
"local-name": "Magyar",
"name": "Hungarian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Betöltés befejezve. DevTools megnyitva"
},
"i18n": {
"loaded": "i18n betöltve"
},
"second-instance": {
"receive-command": "Fogadott parancs a protokollon keresztül: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS fájl \"{{cssFile}}\" nem létezik, figyelmen kívül hagyva"
},
"unresponsive": {
"details": "Nem reagál hiba!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Alkalmazás gyorsítótárának törlése"
},
"window": {
"tried-to-render-offscreen": "Az ablak a képernyőn kívül próbált renderelni, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "A menü el van rejtve, a megjelenítéshez használd az 'Alt' billentyűt (vagy az 'Escape' billentyűt, ha az alkalmazáson belüli menüt használod)",
"message": "A menü elrejtése engedélyezve",
"title": "Menü elrejtése engedélyezve"
},
"need-to-restart": {
"buttons": {
"later": "Később",
"restart-now": "Újraindítás most"
},
"detail": "A \"{{pluginName}}\" plugin újraindítást igényel a hatálybalépéshez",
"message": "\"{{pluginName}}\" újra kell indítani",
"title": "Újraindítás szükséges"
},
"unresponsive": {
"buttons": {
"quit": "Kilépés",
"relaunch": "Újraindítás",
"wait": "Várj"
}
},
"update-available": {
"buttons": {
"disable": "Frissítések letiltása",
"download": "Letöltés",
"ok": "OK"
},
"detail": "Az új verzió elérhető, és letölthető a {{downloadLink}}",
"message": "Új verzió áll rendelkezésre",
"title": "Elérhető frissítés"
}
},
"menu": {
"about": "Névjegy",
"navigation": {
"label": "Navigálás",
"submenu": {
"copy-current-url": "Jelenlegi URL másolása",
"go-back": "Vissza",
"go-forward": "Előre",
"quit": "Kilépés",
"restart": "App újraindítása"
}
},
"options": {
"label": "Beállítások",
"submenu": {
"advanced-options": {
"label": "Speciális beállítások"
}
}
}
}
}
}

690
src/i18n/resources/id.json Normal file
View File

@ -0,0 +1,690 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Gagal saat mengeksekusi plugin {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} dieksekusi pada {{ms}}ms",
"initialize-failed": "Gagal dalam menginisialisasi plugin \"{{pluginName}}\"",
"load-all": "Memuat semua plugin",
"load-failed": "Gagal memuat plugin \"{{pluginName}}\"",
"loaded": "Plugin \"{{pluginName}}\" dimuat",
"unload-failed": "Gagal untuk memuat plugin \"{{pluginName}}\"",
"unloaded": "Plugin \"{{pluginName}}\" telah dikeluarkan"
}
}
},
"language": {
"code": "id",
"local-name": "Bahasa Indonesia",
"name": "Indonesian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Selesai memuat. DevTools terbuka"
},
"i18n": {
"loaded": "i18n selesai dimuat"
},
"second-instance": {
"receive-command": "Menerima instruksi lewat protokol: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS file \"{{cssFile}}\" tidak ada, mengabaikan"
},
"unresponsive": {
"details": "Kesalahan Tidak Responsif!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Menghapus cache aplikasi"
},
"window": {
"tried-to-render-offscreen": "Window mencoba membuat render di luar layar, windowUkuran={{windowSize}}, displaySize={{displaySize}}, posisi={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menu tersembunyi, gunakan 'Alt' untuk menampilkannya (atau 'Escape' jika menggunakan Menu Dalam Aplikasi)",
"message": "Menu Sembunyikan diaktifkan",
"title": "Sembunyikan Menu Diaktifkan"
},
"need-to-restart": {
"buttons": {
"later": "Kemudian",
"restart-now": "Restart Sekarang"
},
"detail": "\"{{pluginName}}\" Plugin memerlukan pengaktifan ulang agar dapat diterapkan",
"message": "\"{{pluginName}}\" harus dimulai ulang",
"title": "Diperlukan Restart"
},
"unresponsive": {
"buttons": {
"quit": "Keluar",
"relaunch": "Luncurkan kembali",
"wait": "Tunggu"
},
"detail": "Kami mohon maaf atas ketidaknyamanan ini. silakan pilih apa yang harus dilakukan:",
"message": "Aplikasi Tidak Responsif",
"title": "Jendela Tidak Responsif"
},
"update-available": {
"buttons": {
"disable": "Nonaktifkan Pembaruan",
"download": "Unduh",
"ok": "OK"
},
"detail": "Versi baru tersedia dan dapat diunduh di {{downloadLink}}",
"message": "Versi baru tersedia",
"title": "Pembaruan Tersedia"
}
},
"menu": {
"about": "Tentang",
"navigation": {
"label": "Navigasi",
"submenu": {
"copy-current-url": "Salin URL saat ini",
"go-back": "Kembali",
"go-forward": "Maju",
"quit": "Keluar",
"restart": "Restart Aplikasi"
}
},
"options": {
"label": "Option",
"submenu": {
"advanced-options": {
"label": "Opsi lanjutan",
"submenu": {
"auto-reset-app-cache": "Mengatur ulang cache aplikasi saat aplikasi dimulai",
"disable-hardware-acceleration": "Menonaktifkan akselerasi perangkat keras",
"edit-config-json": "Ubah config.json",
"override-user-agent": "Mengesampingkan User-Agent",
"restart-on-config-changes": "Mulai ulang pada perubahan konfigurasi",
"set-proxy": {
"label": "Atur Proxy",
"prompt": {
"label": "Masukkan Alamat Proxy: (biarkan kosong untuk menonaktifkan)",
"placeholder": "Contoh: SOCKS5://127.0.0.1:9999",
"title": "Atur proxy"
}
},
"toggle-dev-tools": "Beralih ke DevTools"
}
},
"always-on-top": "Selalu di atas",
"auto-update": "Pembaruan Otomatis",
"hide-menu": {
"dialog": {
"message": "Menu akan disembunyikan pada peluncuran berikutnya, gunakan [Alt] untuk menampilkannya (atau centang [`] jika menggunakan menu dalam aplikasi)",
"title": "Sembunyikan Menu Diaktifkan"
},
"label": "Sembunyikan Menu"
},
"language": {
"dialog": {
"message": "Bahasa akan berubah setelah restart",
"title": "Bahasa Berubah"
},
"label": "Bahasa",
"submenu": {
"to-help-translate": "Ingin membantu menerjemahkan? Klik di sini"
}
},
"resume-on-start": "Melanjutkan lagu terakhir saat aplikasi dimulai",
"single-instance-lock": "Kunci Instance Tunggal",
"start-at-login": "Mulai saat masuk",
"starting-page": {
"label": "Halaman awal",
"unset": "Tidak ditetapkan"
},
"tray": {
"label": "Bilah",
"submenu": {
"disabled": "Dinonaktifkan",
"enabled-and-hide-app": "Mengaktifkan dan menyembunyikan aplikasi",
"enabled-and-show-app": "Mengaktifkan dan menampilkan aplikasi",
"play-pause-on-click": "Putar/Jeda dengan klik"
}
},
"visual-tweaks": {
"label": "Penyesuaian Visual",
"submenu": {
"like-buttons": {
"default": "Standar",
"force-show": "Pertunjukan paksa",
"hide": "Sembunyikan",
"label": "Tombol suka"
},
"remove-upgrade-button": "Hapus tombol peningkatan",
"theme": {
"label": "Tema",
"submenu": {
"import-css-file": "Impor file CSS khusus",
"no-theme": "Tidak ada tema"
}
}
}
}
}
},
"plugins": {
"enabled": "Diaktifkan",
"label": "Plugin",
"new": "Baru"
},
"view": {
"label": "Lihat",
"submenu": {
"force-reload": "Paksa Reload",
"reload": "Muat ulang",
"reset-zoom": "Ukuran sebenarnya",
"toggle-fullscreen": "Alihkan Layar Penuh",
"zoom-in": "Perbesar",
"zoom-out": "Perkecil"
}
}
},
"tray": {
"next": "Selanjutnya",
"play-pause": "Putar/Jeda",
"previous": "Sebelumnya",
"quit": "Keluar",
"restart": "Restart aplikasi",
"show": "Tampilkan jendela",
"tooltip": {
"default": "YouTube Musik",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "Blokir semua iklan dan pelacakan di luar kotak",
"menu": {
"blocker": "Pemblokir"
},
"name": "Pemblokir Iklan"
},
"album-actions": {
"description": "Tambah tombol Suka, Batal Suka, Tidak Suka dan Batal Tidak Suka untuk diterapkan ke semua lagu dalam daftar putar atau album",
"name": "Tindakan Album"
},
"album-color-theme": {
"description": "Menerapkan tema dinamis dan efek visual berdasarkan palet warna album",
"menu": {
"color-mix-ratio": {
"label": "Rasio campuran warna",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Tema Warna Album"
},
"ambient-mode": {
"description": "Menerapkan efek pencahayaan dengan memancarkan warna-warna lembut dari video, ke dalam latar belakang layar Anda",
"menu": {
"blur-amount": {
"label": "Jumlah kabur",
"submenu": {
"pixels": "{{blurAmount}} piksel"
}
},
"buffer": {
"label": "Buffer",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Keburaman",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Kualitas",
"submenu": {
"pixels": "{{quality}} piksel"
}
},
"size": {
"label": "Ukuran",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Kehalusan transisi",
"submenu": {
"during": "Selama {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Gunakan layar penuh"
}
},
"name": "Mode ambient"
},
"audio-compressor": {
"description": "Menerapkan kompresi pada audio (mengurangi volume pada bagian paling keras dari sinyal dan meningkatkan volume pada bagian paling lembut)",
"name": "Kompresi suara"
},
"blur-nav-bar": {
"description": "Jadikan bar navigasi blur dan transparan",
"name": "buramkan bar navigasi"
},
"bypass-age-restrictions": {
"description": "Lewati verifikasi umur dari YouTube",
"name": "Lewati batasan umur"
},
"captions-selector": {
"description": "pemilih caption untuk trek audio YouTube Music",
"menu": {
"autoload": "pilih caption terakhir secara otomatis",
"disable-captions": "bawaannya tanpa caption"
},
"name": "pemilih caption",
"prompt": {
"selector": {
"label": "bahasa caption yang dipakai sekarang: {{language}}",
"none": "tidak ada",
"title": "pilih bahasa caption"
}
},
"templates": {
"title": "buka pemilih caption"
}
},
"compact-sidebar": {
"description": "Selalu atur sidebar dalam mode kompak",
"name": "sidebar ringkas"
},
"crossfade": {
"description": "Crossfade antar lagu",
"menu": {
"advanced": "Lanjutan"
},
"name": "Crossfade [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "durasi fade in (ms)",
"fade-out-duration": "durasi fade out (ms)",
"fade-scaling": {
"label": "redup perlahan",
"linear": "Linear",
"logarithmic": "Logaritmik"
},
"seconds-before-end": "Crossfade N detik sebelum berakhir"
},
"title": "Pilihan crossfade"
}
}
},
"disable-autoplay": {
"description": "Buat lagu mulai dalam mode \"jeda\"",
"menu": {
"apply-once": "Hanya terapkan pada saat startup"
},
"name": "Matikan Autoplay"
},
"discord": {
"backend": {
"already-connected": "Percobaan untuk terhubung dengan koneksi yang aktif",
"connected": "Terhubung dengan Discord",
"disconnected": "Terputus dari Discord"
},
"description": "tunjukan apa yang kamu dengarkan dengan Rich Presence",
"menu": {
"auto-reconnect": "Reconnect otomatis",
"clear-activity": "Hapus riwayat aktifitas",
"clear-activity-after-timeout": "hapus riwayat aktifitas setelah timeout",
"connected": "terhubung",
"disconnected": "tidak terhubung",
"hide-duration-left": "sembunyikan sisa durasi",
"hide-github-button": "sembunyikan tombol link GitHub",
"play-on-youtube-music": "Mainkan di YouTube Music",
"set-inactivity-timeout": "Tetapkan batas waktu tidak aktif"
},
"name": "Rich Presence Discord",
"prompt": {
"set-inactivity-timeout": {
"label": "Masukkan batas waktu tidak aktif dalam detik:",
"title": "Tetapkan batas waktu tidak aktif"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Oke"
},
"message": "Argh! Maaf, dowloadnya gagal…",
"title": "Downloadnya error!"
},
"start-download-playlist": {
"buttons": {
"ok": "Oke"
},
"detail": "({{playlistSize}} lagu-lagu)",
"message": "Mengunduh Playlist {{playlistTitle}}",
"title": "Download dimulai"
}
},
"feedback": {
"conversion-progress": "Konversi: {{percent}}%",
"converting": "Mengkonversi…",
"done": "Selesai: {{filePath}}",
"download-info": "Mengunduh {{artist}} - {{title}} {{videoId}}",
"download-progress": "Mengunduh: {{percent}}%",
"downloading": "Mengunduh…",
"downloading-counter": "Mengunduh {{current}}/{{total}}…",
"downloading-playlist": "Mengunduh playlist \"{{playlistTitle}}\" - {{playlistSize}} lagu ({{playlistId}})",
"error-while-downloading": "Gagal mengunduh \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "Folder {{playlistFolder}} sudah ada",
"getting-playlist-info": "Mendapatkan informasi playlist…",
"loading": "Memuat…",
"playlist-has-only-one-song": "Daftar putar hanya memiliki satu item, mengunduhnya secara langsung",
"playlist-id-not-found": "ID playlist tidak ditemukan",
"playlist-is-empty": "Playlist kosong",
"playlist-is-mix-or-private": "Kesalahan mendapatkan info playlist: pastikan bukan playlist pribadi atau \"Campuran untuk Anda\"\n\n{{error}}",
"preparing-file": "Menyiapkan file…",
"saving": "Menyimpan…",
"trying-to-get-playlist-id": "Mencoba mendapatkan ID playlist: {{playlistId}}",
"video-id-not-found": "Video tidak ditemukan",
"writing-id3": "Menulis tanda ID3…"
}
},
"description": "Unduh MP3 / sumber suara secara langsung via antarmuka",
"menu": {
"choose-download-folder": "Pilih folder unduhan",
"download-playlist": "Unduh daftar putar",
"presets": "Prasetel",
"skip-existing": "Lewati berkas yang sudah ada"
},
"name": "Pengunduh",
"renderer": {
"can-not-update-progress": "Tidak dapat memperbarui proses"
},
"templates": {
"button": "Unduh"
}
},
"exponential-volume": {
"description": "Buat penggeser volume menjadi eksponen sehingga memudahkan memilih volume yang lebih rendah.",
"name": "Volume Eksponen"
},
"in-app-menu": {
"description": "Buat bilah-menu terlihat indah, gelap atau serupa dengan album",
"menu": {
"hide-dom-window-controls": "Sembunyikan DOM pengendali jendela"
},
"name": "Menu di Aplikasi"
},
"lumiastream": {
"description": "Tambah dukungan Lumia Stream",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Tambah dukungan lirik untuk kebanyakan lagu",
"menu": {
"romanized-lyrics": "Romanisasi Lirik"
},
"name": "Lirik Genius",
"renderer": {
"fetched-lyrics": "Lirik yang diambil untuk Genius"
}
},
"music-together": {
"description": "Bagikan daftar putar dengan yang lain. Saat host memainkan lagu, semua orang akan mendengarkan lagu yang sama",
"dialog": {
"enter-host": "Masukkan ID Host"
},
"internal": {
"save": "Simpan",
"track-source": "Sumber Trek",
"unknown-user": "Pengguna Tidak Diketahui"
},
"menu": {
"click-to-copy-id": "Salin ID Host",
"close": "Tutup Musik Bersama",
"connected-users": "Pengguna Terhubung",
"disconnect": "Putuskan Musik Bersama",
"empty-user": "Tidak ada pengguna terhubung",
"host": "Host Musik Bersama",
"join": "Gabung Musik Bersama",
"permission": {
"all": "Izinkan tamu untuk mengendalikan daftar putar dan pemutar",
"host-only": "Hanya host yang dapat mengendalikan daftar putar dan pemutar",
"playlist": "Izinkan tamu untuk mengendalikan daftar putar"
},
"set-permission": "Ubah Pengendali Izin",
"status": {
"disconnected": "Terputus",
"guest": "Terhubung sebagai Tamu",
"host": "Terhubung sebagai Host"
}
},
"name": "Musik Bersama [Beta]",
"toast": {
"add-song-failed": "Gagal untuk menambahkan lagu",
"closed": "Musik Bersama ditutup",
"disconnected": "Musik Bersama terputus",
"host-failed": "Gagal untuk memulai Musik Bersama",
"id-copied": "ID Host tersalin ke papan klip",
"id-copy-failed": "Gagal menyalin ID Host ke papan klip",
"join-failed": "Gagal untuk bergabung ke Musik Bersama",
"joined": "Bergabung ke Musik Bersama",
"permission-changed": "Perizinan Musik Bersama diubah ke \"{{permission}}\"",
"remove-song-failed": "Gagal menghapus lagu",
"user-connected": "{{name}} bergabung ke Musik Bersama",
"user-disconnected": "{{name}} meninggalkan Musik Bersama"
}
},
"navigation": {
"description": "panah navigasi Selanjutnya/Sebelumnya terintegrasi pada antarmuka, layaknya peramban kesukaan Anda",
"name": "Navigasi"
},
"no-google-login": {
"description": "Hapus tombol dan tautan masuk Google dari antarmuka",
"name": "Tanpa Google Login"
},
"notifications": {
"description": "Tampilkan pemberitahuan saat lagu dimainkan (pemberitahuan interaktif tersedia di Windows)",
"menu": {
"interactive": "Pemberitahuan Interaktif",
"interactive-settings": {
"label": "Pengaturan Interaktif",
"submenu": {
"hide-button-text": "Sembunyikan teks tombol",
"refresh-on-play-pause": "Segarkan saat Putar/Jeda",
"tray-controls": "Buka/Tutup saat baki ditekan"
}
},
"priority": "Prioritas Pemberitahuan",
"toast-style": "Gaya Toast",
"unpause-notification": "Tampilkan pemberitahuan saat tidak dijeda"
},
"name": "Pemberitahuan"
},
"picture-in-picture": {
"description": "Izinkan untuk memindahkan aplikasi ke mode gambar-dalam-gambar",
"menu": {
"always-on-top": "Selalu di atas",
"hotkey": {
"label": "Pintasan",
"prompt": {
"keybind-options": {
"hotkey": "Pintasan"
},
"label": "Pilih pintasan untuk beralih ke gambar-dalam-gambar",
"title": "Pintasan gambar-dalam-gambar"
}
},
"save-window-position": "Simpan posisi jendela",
"save-window-size": "Simpan ukuran jendela",
"use-native-pip": "Gunakan PiP bawaan peramban"
},
"name": "Gambar-dalam-gambar",
"templates": {
"button": "Gambar-dalam-gambar"
}
},
"playback-speed": {
"description": "Dengarkan cepat, dengarkan perlahan! Tambahkan penggeser untuk mengendalikan kecepatan lagu",
"name": "Kecepatan Pemutar",
"templates": {
"button": "Kecepatan"
}
},
"precise-volume": {
"description": "Kendalikan volume secara presisi menggunakan roda tetikus/pintasan, dengan HUD kustom dan langkah volume yang dapat diatur",
"menu": {
"arrows-shortcuts": "Kendali Tombol Panah Lokal",
"custom-volume-steps": "Atur Langkah Volume Kustom",
"global-shortcuts": "Pintasan Global"
},
"name": "Volume Presisi",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Kurangi Volume",
"increase": "Tingkatkan Volume"
},
"label": "Pilih Pintasan Volume Global:",
"title": "Pintasan Volume Global"
},
"volume-steps": {
"label": "Pilih Langkah Peningkatan/Pengurangan Volume",
"title": "Langkah Volume"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Kualitas Terkini: {{quality}}",
"message": "Pilih Kualitas Video:",
"title": "Pilih Kualitas Video"
}
}
},
"description": "Izinkan untuk mengubah kualitas video dengan tombol pada hamparan video",
"name": "Pengubah Kualitas Video"
},
"scrobbler": {
"description": "Tambahkan dukungan scrobbling (mis. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Gagal mengotentikasi Last.fm\nSembunyikan munculan hingga muat ulang selanjutnya.",
"title": "Otentikasi Gagal"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Pengaturan API Last.fm"
},
"listenbrainz": {
"token": "Masukkan token pengguna ListenBrainz"
},
"scrobble-other-media": "Scrobble media lain"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Kunci API Last.fm",
"api-secret": "Secret API Last.fm"
},
"listenbrainz": {
"token": {
"label": "Masukkan token pengguna ListenBrainz Anda:",
"title": "Token ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Izinkan pengaturan pintasan global untuk pemutar (main/jeda/selanjutnya/sebelumnya) dan mematikan OSD media dengan mengesampingkan tombol media, mengaktifkan Ctrl/CMD + F untuk pencarian, mengaktifkan dukungan MPRIS Linux untuk tombol media, dan tombol pintasan kustom untuk pengguna lanjutan",
"menu": {
"override-media-keys": "Timpa Tombol Media",
"set-keybinds": "Atur Pengendali Lagu Global"
},
"name": "Pintasan (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Selanjutnya",
"play-pause": "Main / Jeda",
"previous": "Sebelumnya"
},
"label": "Pilih Pintasan Global untuk Pengendali Lagu:",
"title": "Pintasan Global"
}
}
},
"skip-disliked-songs": {
"description": "Lewati lagu yang tidak disukai",
"name": "Lewati Lagu yang Tidak Disukai"
},
"skip-silences": {
"description": "Otomatis lewati bagian hening dari lagu",
"name": "Lewati Keheningan"
},
"sponsorblock": {
"description": "Otomatis Melewati bagian yang bukan musik seperti intro/outro atau bagian dari video musik di mana lagu tidak dimainkan",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Kendalikan pemutaran dari bilah alat Windows",
"name": "Pengendali Media di Bilah Alat"
},
"touchbar": {
"description": "Tambahkan widget TouchBar untuk pengguna macOS",
"name": "TouchBar"
},
"tuna-obs": {
"description": "Integrasi dengan plugin Tuna OBS",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Tambahkan tombol untuk beralih antara mode Lagu/Video. secara opsional juga dapat menghapus keseluruhan tab video",
"menu": {
"align": {
"label": "Perataan",
"submenu": {
"left": "Kiri",
"middle": "Tengah",
"right": "Kanan"
}
},
"force-hide": "Paksa hapus tab video",
"mode": {
"label": "Mode",
"submenu": {
"custom": "Peralih kustom",
"disabled": "Mati",
"native": "Peralih bawaan"
}
}
},
"name": "Peralih Video",
"templates": {
"button": "Lagu"
}
},
"visualizer": {
"description": "Tambahkan visualisator ke pemutar",
"menu": {
"visualizer-type": "Tipe Visualisator"
},
"name": "Visualisator"
}
}
}

690
src/i18n/resources/is.json Normal file
View File

@ -0,0 +1,690 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Tókst ekki að framkvæma viðbót {{pluginName}}::{{contextName}}",
"executed-at-ms": "Viðbótin {{pluginName}}::{{contextName}} var framkvæmd í {{ms}}ms",
"initialize-failed": "Tókst ekki að frumstilla viðbót \"{{pluginName}}\"",
"load-all": "Er að hlaða öllum viðbótum",
"load-failed": "Tókst ekki að hlaða viðbótinni \"{{pluginName}}\"",
"loaded": "Viðbót \"{{pluginName}}\" hlaðið",
"unload-failed": "Tókst ekki að afhlaða viðbótinni \"{{pluginName}}\"",
"unloaded": "Viðbótin „{{pluginName}}“ óhlaðin"
}
}
},
"language": {
"code": "is",
"local-name": "Íslenska",
"name": "Icelandic"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Lokið við hleðslu. DevTools opnuð"
},
"i18n": {
"loaded": "i18n hlaðið"
},
"second-instance": {
"receive-command": "Fengið skipun yfir prótókoll: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS skrá \"{{cssFile}}\" er ekki til, er að hunsa"
},
"unresponsive": {
"details": "Viðbragðslaust Villa!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Er að hreinsa forritabúfera"
},
"window": {
"tried-to-render-offscreen": "Gluggi reyndi að birta utan skjás, gluggastærð={{windowSize}}, skjástærð={{displaySize}}, stöðu={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Valmyndin er falin, notaðu 'Breytingarlykil' til að sýna hana (eða 'Útfararlykil' ef þú notar valmynd í forriti)",
"message": "Fela Valmynd er virkjuð",
"title": "Fela Valmynd Virkjuð"
},
"need-to-restart": {
"buttons": {
"later": "Seinna",
"restart-now": "Endurræsa Núna"
},
"detail": "\"{{pluginName}}\" viðbótin þarfnast endurræsingar til að taka gildi",
"message": "\"{{pluginName}}\" þarf að endurræsa",
"title": "Endurræsa Krafist"
},
"unresponsive": {
"buttons": {
"quit": "Hætta",
"relaunch": "Endurræsa",
"wait": "Bíddu"
},
"detail": "Við biðjumst velvirðingar á óþægindunum! vinsamlegast veldu hvað á að gera:",
"message": "Umsóknin svarar ekki",
"title": "Gluggi er svarar ekki"
},
"update-available": {
"buttons": {
"disable": "Gera Uppfærslur Óvirkar",
"download": "Sækja",
"ok": "Í lagi"
},
"detail": "Ný útgáfa er fáanleg og hægt er að hlaða henni niður á {{downloadLink}}",
"message": "Ný útgáfa er fáanleg",
"title": "Uppfærsla Fáanleg"
}
},
"menu": {
"about": "Um",
"navigation": {
"label": "Leiðsögn",
"submenu": {
"copy-current-url": "Afritaðu núverandi vefslóð",
"go-back": "Farðu til baka",
"go-forward": "Farðu áfram",
"quit": "Útganga",
"restart": "Endurræstu Forritið"
}
},
"options": {
"label": "Valkostir",
"submenu": {
"advanced-options": {
"label": "Ítarlegravalkostir",
"submenu": {
"auto-reset-app-cache": "Endurstilltu skyndiminni forritsins þegar forritið ræsir",
"disable-hardware-acceleration": "Slökktu á vélbúnaðarhröðun",
"edit-config-json": "Breyta config.json",
"override-user-agent": "Hneka Notandaumboðsmanni",
"restart-on-config-changes": "Endurræstu við stillingarbreytingar",
"set-proxy": {
"label": "Stilla umboð",
"prompt": {
"label": "Sláðu inn umboðsfang: (skilið eftir autt til að slökkva á)",
"placeholder": "Dæmi: SOCKS5://127.0.0.1:9999",
"title": "Stilla umboð"
}
},
"toggle-dev-tools": "Breyta DevTools"
}
},
"always-on-top": "Alltaf á toppnum",
"auto-update": "Sjálfvirk Uppfærsla",
"hide-menu": {
"dialog": {
"message": "Valmyndin verður falin við næstu ræsingu, notaðu [Alt] til að sýna hana (eða bakaðu við [`] ef þú notar valmynd í forriti)",
"title": "Fela Valmynd Virkjuð"
},
"label": "Fela Valmynd"
},
"language": {
"dialog": {
"message": "Tungumáli verður breytt eftir endurræsingu",
"title": "Tungumáli Breytt"
},
"label": "Tungumál",
"submenu": {
"to-help-translate": "Viltu hjálpa til við að þýða? Smellið hér"
}
},
"resume-on-start": "Haltu áfram síðasta lagi þegar forritið byrjar",
"single-instance-lock": "Eittdæmilás",
"start-at-login": "Byrjaðu á innskráningu",
"starting-page": {
"label": "Upphafssíða",
"unset": "Ósetja"
},
"tray": {
"label": "Bakki",
"submenu": {
"disabled": "Fötluð",
"enabled-and-hide-app": "Bakki virkt, og fela forritsgluggi",
"enabled-and-show-app": "Virkjað og sýna forrit",
"play-pause-on-click": "Spila/hlé við smell"
}
},
"visual-tweaks": {
"label": "Sjónrænaraðlögun",
"submenu": {
"like-buttons": {
"default": "Sjálfgefinn",
"force-show": "Þvingaðu sýna",
"hide": "Fela",
"label": "Líkartakkar"
},
"remove-upgrade-button": "Fjarlægja uppgræðartakkan",
"theme": {
"label": "Þema",
"submenu": {
"import-css-file": "Flytja inn sérsniðna CSS skrá",
"no-theme": "Engin þema"
}
}
}
}
}
},
"plugins": {
"enabled": "Virkt",
"label": "Viðbætur",
"new": "NÝR"
},
"view": {
"label": "Útsýni",
"submenu": {
"force-reload": "Þvingaðu Endurhleðslu",
"reload": "Endurhlaða",
"reset-zoom": "Raunveruleg Stærð",
"toggle-fullscreen": "Breyta Fullskjá",
"zoom-in": "Aðdráttur",
"zoom-out": "Aðdráttur út"
}
}
},
"tray": {
"next": "Næst",
"play-pause": "Spila/Hlé",
"previous": "Fyrri",
"quit": "Útganga",
"restart": "Endurræstu Forritið",
"show": "Sýna glugga",
"tooltip": {
"default": "YouTube Tónlist",
"with-song-info": "YouTube Tónlist: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "Lokaðu fyrir allar auglýsingar og rakningar úr kassanum",
"menu": {
"blocker": "Blokkari"
},
"name": "Auglýsingablokkari"
},
"album-actions": {
"description": "Bætir Ódíslika, Mislíkt, Líkt, og Ólíkt til að nota þetta á öll lög á spilunarlista eða albúm",
"name": "Albúmsaðgerðir"
},
"album-color-theme": {
"description": "Beitir kraftmikið þema og sjónrænum áhrifum sem byggjast á litavali albúmsins",
"menu": {
"color-mix-ratio": {
"label": "Litablöndunarhlutfall",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Albúmslitaþema"
},
"ambient-mode": {
"description": "Beitir lýsingaráhrifum með því að varpa mildum litum úr myndbandinu í bakgrunn skjásins",
"menu": {
"blur-amount": {
"label": "Þokuupphæð",
"submenu": {
"pixels": "{{blurAmount}} pixlum"
}
},
"buffer": {
"label": "Stuðpúði",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Ógegnsæi",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Gæði",
"submenu": {
"pixels": "{{quality}} pixlum"
}
},
"size": {
"label": "Sæði",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Slétt umskipti",
"submenu": {
"during": "Meðan á {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Er að nota fullskjár"
}
},
"name": "Umhverfishamur"
},
"audio-compressor": {
"description": "Notaðu þjöppun á hljóð (lækkar hljóðstyrk háværustu hluta merkis og hækkar hljóðstyrk í mýkstu hlutunum)",
"name": "Hljóðþjöppu"
},
"blur-nav-bar": {
"description": "Gerir leiðsögustikuna gagnsæja og óskýrt",
"name": "Þoka Leiðsagnarstika"
},
"bypass-age-restrictions": {
"description": "Framhjá aldursstaðfestingu YouTube",
"name": "Farið Framhjá Aldurstakmörkunum"
},
"captions-selector": {
"description": "Skjátextavali fyrir YouTube Tónlist hljóðrásir",
"menu": {
"autoload": "Veldu sjálfkrafa síðast notaða myndatexta",
"disable-captions": "Engir skjátextar sjálfgefið"
},
"name": "Yfirskriftarval",
"prompt": {
"selector": {
"label": "Núverandi tungumál skjátexta: {{language}}",
"none": "Enginn",
"title": "Veldu tungumál fyrir skjátexta"
}
},
"templates": {
"title": "Opnaðu skjátextavali"
}
},
"compact-sidebar": {
"description": "Stilltu hliðarstikuna alltaf í þétta stillingu",
"name": "Fyrirferðarlítillhliðarstika"
},
"crossfade": {
"description": "Krossfæra á milli lög",
"menu": {
"advanced": "Háþróaður"
},
"name": "Krossfæra [Prófunarútgáfa]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Dvína í lengd (ms)",
"fade-out-duration": "Dvína út lengd (ms)",
"fade-scaling": {
"label": "Fölunarskala",
"linear": "Línulegt",
"logarithmic": "Logaritmískt"
},
"seconds-before-end": "Krossfæra N sekúndum fyrir enda"
},
"title": "Krossfæravalkosti"
}
}
},
"disable-autoplay": {
"description": "Gerir lag að byrja í \"hlé\" ham",
"menu": {
"apply-once": "Á aðeins við ræsingu"
},
"name": "Slökkva á sjálfvirkri spilun"
},
"discord": {
"backend": {
"already-connected": "Reyndi að tengja við virka tengingu",
"connected": "Tengdur við Discord",
"disconnected": "Aftengdur við Discord"
},
"description": "Sýndu vinum þínum hvað þú hlustar á með Rík Nærvera",
"menu": {
"auto-reconnect": "Sjálfvirk endurtengja",
"clear-activity": "Hreinsa virkni",
"clear-activity-after-timeout": "Hreinsa virkni eftir tímamörk",
"connected": "Tengt",
"disconnected": "Aftengt",
"hide-duration-left": "Fela tímalengd til vinstri",
"hide-github-button": "Fela GitHub tengilhnapp",
"play-on-youtube-music": "Spilaðu á YouTube Tónlist",
"set-inactivity-timeout": "Stilltu tímamörk fyrir óvirkni"
},
"name": "Discord Rík Nærvera",
"prompt": {
"set-inactivity-timeout": {
"label": "Sláðu inn óvirknitíma eftir sekúndur:",
"title": "Stilltu tímamörk fyrir óvirkni"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Í lagi"
},
"message": "Úff! Afsakið, niðurhal mistókst…",
"title": "Villa við niðurhal!"
},
"start-download-playlist": {
"buttons": {
"ok": "Í lagi"
},
"detail": "({{playlistSize}} lög)",
"message": "Að sækja lagalista {{playlistTitle}}",
"title": "Niðurhal byrjað"
}
},
"feedback": {
"conversion-progress": "Umbreyting: {{percent}}%",
"converting": "Er að umbreytir…",
"done": "Búið: {{filePath}}",
"download-info": "Er að niðurhal {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Niðurhal: {{percent}}%",
"downloading": "Er að niðurhal…",
"downloading-counter": "Er að niðurhal {{current}}/{{total}}…",
"downloading-playlist": "Er að niðurhal spilunarlisti \"{{playlistTitle}}\" - {{playlistSize}} lög ({{playlistId}})",
"error-while-downloading": "Villa við niðurhal \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "Mappan {{playlistFolder}} er þegar til",
"getting-playlist-info": "Sækir upplýsingar um spilunarlista…",
"loading": "Er að hlaða.…",
"playlist-has-only-one-song": "Spilunarlista hefur aðeins eitt atriði, það er verið að hlaða því niður beint",
"playlist-id-not-found": "Ekkert auðkenni spilunarlista fannst",
"playlist-is-empty": "Spilunarlistinn er tómur",
"playlist-is-mix-or-private": "Villa við að fá upplýsingar um spilunarlista: Gakktu úr skugga um að þetta sé ekki einkaspilunarlisti eða \"Mixað fyrir þig\"\n\n{{error}}",
"preparing-file": "Er að undirbúa skrá…",
"saving": "Er að vista…",
"trying-to-get-playlist-id": "Er að reyna að fá auðkenni spilunarlista: {{playlistId}}",
"video-id-not-found": "Myndband fannst ekki",
"writing-id3": "Að skrifa ID3 tög…"
}
},
"description": "Niðurhalar MP3 / upprunahljóði beint úr viðmótinu",
"menu": {
"choose-download-folder": "Veldu niðurhalsmöppu",
"download-playlist": "Sækja spilunarlista",
"presets": "Forstillingar",
"skip-existing": "Slepptu núverandi skrám"
},
"name": "Niðurhalari",
"renderer": {
"can-not-update-progress": "Ekki er hægt að uppfæra framvindu"
},
"templates": {
"button": "Sækja"
}
},
"exponential-volume": {
"description": "Gerir hljóðstyrkssleðann veldisvísis svo það er auðveldara að velja lægra hljóðstyrk.",
"name": "Veldibundiðrúmmál"
},
"in-app-menu": {
"description": "Gefur valmyndastikum glæsilegt, dökkt eða albúmslitsjáðu",
"menu": {
"hide-dom-window-controls": "Fela DOM gluggastýringar"
},
"name": "Valmynd í forriti"
},
"lumiastream": {
"description": "Bætir við Lumia Stream stuðningi",
"name": "Lumia Stream [Prófunarútgáfa]"
},
"lyrics-genius": {
"description": "Bætir stuðningi við texta fyrir flest lög",
"menu": {
"romanized-lyrics": "Rómaníseraðir Söngtexti"
},
"name": "Söngtexti Snilld",
"renderer": {
"fetched-lyrics": "Sótt söngtexti fyrir Snilld"
}
},
"music-together": {
"description": "Deila spilunarlista með öðrum. Þegar gestgjafinn spilar lag munu allir aðrir heyra sama lagið",
"dialog": {
"enter-host": "Sláðu inn auðkenni gestgjafa"
},
"internal": {
"save": "Vista",
"track-source": "Lagsuppspretta",
"unknown-user": "Óþekktur notandi"
},
"menu": {
"click-to-copy-id": "Afritaðu hýsingarauðkenni",
"close": "Lokaðu Tónlist Saman",
"connected-users": "Tengdir Notendur",
"disconnect": "Aftengdu Tónlist Saman",
"empty-user": "Engir tengdir notendur",
"host": "Tónlist Saman Gestgjafi",
"join": "Vertu með Tónlist Saman",
"permission": {
"all": "Leyfðu gestum að stjórna spilunarlista og spilara",
"host-only": "Aðeins gestgjafi getur stjórnað spilunarlista og spilara",
"playlist": "Leyfðu gestum að stjórna spilunarlista"
},
"set-permission": "Breyta Stjórnunarheimild",
"status": {
"disconnected": "Aftengt",
"guest": "Tengdur sem Gestur",
"host": "Tengdur sem Gestgjafi"
}
},
"name": "Tónlist Saman [Prófunarútgáfa]",
"toast": {
"add-song-failed": "Mistókst að bæta við lagi",
"closed": "Tónlist Saman lokað",
"disconnected": "Tónlist Saman aftengt",
"host-failed": "Mistókst að hýsa Tónlist Saman",
"id-copied": "Gestgjafaauðkenni afritað á klippiborð",
"id-copy-failed": "Mistókst að afrita Hýsingarauðkenni á klippiborð",
"join-failed": "Ekki tókst að taka þátt í Tónlist Saman",
"joined": "Tengd Tónlist Saman",
"permission-changed": "Tónlist Saman leyfi breytt í \"{{permission}}\"",
"remove-song-failed": "Tókst ekki að fjarlægja lag",
"user-connected": "{{name}} tengd Tónlist Saman",
"user-disconnected": "{{name}} fór frá Tónlist Saman"
}
},
"navigation": {
"description": "Næsta/Til baka leiðsagnarörvar beint samþættar í viðmótinu, eins og í uppáhalds vafranum þínum",
"name": "Leiðsögn"
},
"no-google-login": {
"description": "Fjarlægðu Google innskráningarhnappa og tengla úr viðmótinu",
"name": "Engin Google innskráning"
},
"notifications": {
"description": "Birta tilkynningu þegar lag byrjar að spila (gagnvirkartilkynningar eru fáanlegar á Windows)",
"menu": {
"interactive": "Gagnvirkartilkynningar",
"interactive-settings": {
"label": "Gagnvirkarstillingar",
"submenu": {
"hide-button-text": "Fela hnappatexta",
"refresh-on-play-pause": "Endurnýjaðu í Spilun/Hlé",
"tray-controls": "Opna/loka á bakka smellur"
}
},
"priority": "Tilkynningaforgangur",
"toast-style": "Ristað brauð stíl",
"unpause-notification": "Sýna tilkynningu þegar ekki er gert hlé"
},
"name": "Tilkynningar"
},
"picture-in-picture": {
"description": "Gerir kleift að skipta forritinu yfir í mynd-í-mynd stillingu",
"menu": {
"always-on-top": "Alltaf á toppnum",
"hotkey": {
"label": "Flýtilykil",
"prompt": {
"keybind-options": {
"hotkey": "Flýtilykil"
},
"label": "Veldu flýtilykil til að skipta mynd-í-mynd",
"title": "Mynd-í-mynd Flýtilykil"
}
},
"save-window-position": "Vista gluggastöðu",
"save-window-size": "Vista gluggastærð",
"use-native-pip": "Notaðu innbyggða PiP í vafra"
},
"name": "Mynd-í-mynd",
"templates": {
"button": "Mynd-í-mynd"
}
},
"playback-speed": {
"description": "Hlustaðu hratt, hlustaðu hægt! Bætir við sleða sem stjórnar lagahraðanum",
"name": "Spilunarhraði",
"templates": {
"button": "Hraði"
}
},
"precise-volume": {
"description": "Stjórnaðu hljóðstyrknum nákvæmlega með músarhjóli/hraðtökkum, með sérsniðnum HUD og sérsniðnum hljóðstyrksþrepum",
"menu": {
"arrows-shortcuts": "Staðbundnar Örvatakkar Stjórna",
"custom-volume-steps": "Stilltu Sérsniðin Hljóðstyrksskref",
"global-shortcuts": "Alþjóðlegarflýtilyklar"
},
"name": "Nákvæmshljóðstyrkur",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Minnka Hljóðstyrk",
"increase": "Auka Hljóðstyrk"
},
"label": "Veldu Alþjóðleghljóðstyrklyklabindingar:",
"title": "Alþjóðleghljóðstyrklyklabindingar"
},
"volume-steps": {
"label": "Veldu Hljóðstyrksauka/Minnka Skref",
"title": "Hljóðstyrksskref"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Núverandi Gæði: {{quality}}",
"message": "Veldu Myndbandsgæði:",
"title": "Veldu Myndbandsgæði"
}
}
},
"description": "Leyfir að breyta myndbandgæðum með hnappi á myndbandsyfirlaginu",
"name": "Myndbandgæðisbreyting"
},
"scrobbler": {
"description": "Bæta við scrobbling stuðningi (osv. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Mistókst að auðkenna með Last.fm\nFela sprettigluggann þar til næstu endurræsingu.",
"title": "Auðkenning Mistókst"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API Stillingar"
},
"listenbrainz": {
"token": "Sláðu inn ListenBrainz notandalykilinn"
},
"scrobble-other-media": "Scrobble aðra fjölmiðla"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Last.fm API lykill",
"api-secret": "Last.fm API leyndarmál"
},
"listenbrainz": {
"token": {
"label": "Sláðu inn ListenBrainz notandatáknið þitt:",
"title": "ListenBrainz tákn"
}
}
}
},
"shortcuts": {
"description": "Leyfir að stilla alþjóðlegaflýtilykla fyrir spilun (spila/gera hlé/næsta/fyrri) og slökkva á OSD miðla með því að hnekkja miðlunartökkum, kveikja á Ctrl/CMD + F til að leita, kveikja á Linux MPRIS stuðningi fyrir miðlunarlykla og sérsniðna flýtilykla fyrir lengra komna notendur",
"menu": {
"override-media-keys": "Hneka Fjölmiðlalykla",
"set-keybinds": "Stilltu Alþjóðlegslagastýringar"
},
"name": "Flýtileiðir (og MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Næst",
"play-pause": "Spila / Hlé",
"previous": "Fyrri"
},
"label": "Veldu Alþjóðlegslyklabind fyrir Lagastýringu:",
"title": "Alþjóðlegslyklabindingar"
}
}
},
"skip-disliked-songs": {
"description": "Sleppir mislíkaði lög",
"name": "Slepptu Mislíkaði Lög"
},
"skip-silences": {
"description": "Slepptu sjálfkrafa þagnarköflum í lögum",
"name": "Slepptu Þögnum"
},
"sponsorblock": {
"description": "Sleppur sjálfkrafa hlutum sem ekki eru tónlist, eins og inngangur/lok eða hlutar af tónlistarmyndböndum þar sem lag er ekki að spila",
"name": "Styrktarblokk"
},
"taskbar-mediacontrol": {
"description": "Stjórnaðu spilun frá Windows verkefnastikunni þinni",
"name": "Miðlunarstýringarverkefnastikunnar"
},
"touchbar": {
"description": "Bætir við Snertistiku græju fyrir macOS notendur",
"name": "Snertistiku"
},
"tuna-obs": {
"description": "Samþætting við OBS viðbót Tuna",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Bætir við hnappi til að skipta á milli myndbands/lagshams. Getur einnig valfrjálst fjarlægt allan myndbandsflipann",
"menu": {
"align": {
"label": "Jöfnun",
"submenu": {
"left": "Vinstri",
"middle": "Miðja",
"right": "Rétt"
}
},
"force-hide": "Þvingaðu fjarlægja myndbandsflipann",
"mode": {
"label": "Hamur",
"submenu": {
"custom": "Sérsniðinn rofi",
"disabled": "Fötluð",
"native": "Innfæddsrofi"
}
}
},
"name": "Myndbandsrofi",
"templates": {
"button": "Lag"
}
},
"visualizer": {
"description": "Bætir sýndarstýringar við spilarann",
"menu": {
"visualizer-type": "Sýndarstýringartegund"
},
"name": "Sýndarstýringar"
}
}
}

View File

@ -15,8 +15,8 @@
},
"language": {
"code": "it",
"local-name": "Inglese",
"name": "Inglese"
"local-name": "Italiano",
"name": "Italian"
},
"main": {
"console": {
@ -44,7 +44,7 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "Il menu è nascosto, utilizza 'Alt' per visualizzarlo (o 'Escape' se si utilizza il menu In-App)\"",
"detail": "Il menu è nascosto, utilizza 'Alt' per visualizzarlo (o 'Escape' se si utilizza il Menu In-App)\"",
"message": "'Nascondi menu' è attivo",
"title": "'Nascondi menu' attivo"
},
@ -96,7 +96,7 @@
"advanced-options": {
"label": "Opzioni avanzate",
"submenu": {
"auto-reset-app-cache": "Resetta la cache dell'app quando viene riavviata",
"auto-reset-app-cache": "Reimposta la cache dell'app quando viene riavviata",
"disable-hardware-acceleration": "Disabilita l'accelerazione hardware",
"edit-config-json": "Modificare config.json",
"override-user-agent": "Sovrascrivi User-Agent",
@ -105,7 +105,7 @@
"label": "Imposta il proxy",
"prompt": {
"label": "Inserisci l'indirizzo proxy: (lascia vuoto per disabilitare)",
"placeholder": "Esempio: socks5://127.0.0.1:9999",
"placeholder": "Esempio: SOKS5://127.0.0.1:9999",
"title": "Imposta il proxy"
}
},
@ -116,7 +116,7 @@
"auto-update": "Aggiornamento automatico",
"hide-menu": {
"dialog": {
"message": "Il menu verrà nascosto al prossimo avvio. Utilizzare [Alt] per mostrarlo (o backtick [`] se si utilizza il menu In-App)",
"message": "Il menu verrà nascosto al prossimo avvio. Utilizzare [Alt] per mostrarlo (o backtick [`] se si utilizza il Menu In-App)",
"title": "Nascondi menu abilitato"
},
"label": "Nascondi menu"
@ -132,7 +132,7 @@
}
},
"resume-on-start": "Riprendi a riprodurre l'ultimo brano all'avvio dell'app",
"single-instance-lock": "Blocco a istanza singola",
"single-instance-lock": "Permetti una sola istanza dell'app",
"start-at-login": "Avvia al login",
"starting-page": {
"label": "Pagina iniziale",
@ -169,15 +169,16 @@
}
},
"plugins": {
"enabled": "Abilitato",
"label": "Plugin"
"enabled": "Attivato",
"label": "Plugin",
"new": "NUOVO"
},
"view": {
"label": "Visualizzazione",
"submenu": {
"force-reload": "Forza l'aggiornamento",
"reload": "Aggiorna",
"reset-zoom": "Dimensione attuale",
"reset-zoom": "Ripristina dimensione",
"toggle-fullscreen": "Attiva/disattiva Schermo Intero",
"zoom-in": "Zoom in",
"zoom-out": "Zoom out"
@ -190,7 +191,11 @@
"previous": "Precedente",
"quit": "Esci",
"restart": "Riavvia l'app",
"show": "Mostra finestra"
"show": "Mostra finestra",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -199,14 +204,26 @@
"menu": {
"blocker": "Blocco"
},
"name": "Adblocker"
"name": "Ad blocker"
},
"album-actions": {
"description": "Aggiunge i pulsanti Undislike, Dislike, Like e Unlike a tutti i brani di una playlist o di un album",
"name": "Azioni album"
},
"album-color-theme": {
"description": "Applica un tema dinamico e degli effetti visivi basandosi sul colore dell'album",
"name": "Tema Colore Album"
"menu": {
"color-mix-ratio": {
"label": "Percentiuale colore",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Tema abbinato a colore album"
},
"ambient-mode": {
"description": "Applica un effetto di illuminazione proiettando i colori delicati del video sullo sfondo dello schermo.",
"description": "Applica un effetto di illuminazione proiettando i colori delicati del video sullo sfondo dello schermo",
"menu": {
"blur-amount": {
"label": "Intensità sfocatura",
@ -241,7 +258,7 @@
"smoothness-transition": {
"label": "Fluidità transizione",
"submenu": {
"during": "Per {{interpolationTime}}"
"during": "Per {{interpolationTime}} _s"
}
},
"use-fullscreen": {
@ -252,15 +269,15 @@
},
"audio-compressor": {
"description": "Attiva la compressione audio (abbassa il volume delle parti più alte e alza quello delle parti più basse del segnale)",
"name": "Compressore Audio"
"name": "Compressore audio"
},
"blur-nav-bar": {
"description": "Rende la barra di navigazione trasparente e sfuocata",
"name": "Sfuoca Barra di Navigazione"
"name": "Barra di navigazione trasparente"
},
"bypass-age-restrictions": {
"description": "Bypassa la verifica dell'età di YouTube",
"name": "Bypassa le Restrizioni d'Età"
"name": "Aggira i limiti d'età"
},
"captions-selector": {
"description": "Selettore sottotitolo per le tracce audio di YouTube",
@ -282,7 +299,7 @@
},
"compact-sidebar": {
"description": "Imposta sempre la barra laterale in modalità compatta",
"name": "Barra Laterale Compatta"
"name": "Barra laterale compatta"
},
"crossfade": {
"description": "Crossfade tra i brani",
@ -293,8 +310,8 @@
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Durata dissolvenza in entrata (millisecondi)",
"fade-out-duration": "Durata dissolvenza in uscita (millisecondi)",
"fade-in-duration": "Durata dissolvenza in entrata (ms)",
"fade-out-duration": "Durata dissolvenza in uscita (ms)",
"fade-scaling": {
"label": "Transizione dissolvenza",
"linear": "Lineare",
@ -311,7 +328,7 @@
"menu": {
"apply-once": "Solo all'avvio"
},
"name": "Disattiva Autoplay"
"name": "Disattiva autoplay"
},
"discord": {
"backend": {
@ -399,7 +416,7 @@
},
"exponential-volume": {
"description": "Rende esponenziale il cursore del volume, in modo da facilitare la selezione di volumi più bassi.",
"name": "Volume Esponenziale"
"name": "Volume esponenziale"
},
"in-app-menu": {
"description": "Migliora l'aspetto delle barre del menu con un look scuro o basato sul colore dell'album",
@ -408,13 +425,9 @@
},
"name": "Menu In-App"
},
"last-fm": {
"description": "Aggiungi supporto per lo scrobbling su Last.fm",
"name": "Last.fm"
},
"lumiastream": {
"description": "Aggiungi supporto per Lumia Stream",
"name": "Lumia Stream [beta]"
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Aggiunge il supporto dei testi per la maggior parte delle canzoni",
@ -426,13 +439,59 @@
"fetched-lyrics": "Testi recuperati per Genius"
}
},
"music-together": {
"description": "Condividi una playlist con altri. Quando l'Host riproduce un brano, tutti gli altri ascolteranno lo stesso brano",
"dialog": {
"enter-host": "Inserisci l'ID dell'Host"
},
"internal": {
"save": "Salva",
"track-source": "Traccia sorgente",
"unknown-user": "Utente sconosciuto"
},
"menu": {
"click-to-copy-id": "Copia l'ID dell'Host",
"close": "Chiudi Music Together",
"connected-users": "Utenti connessi",
"disconnect": "Disconetti Music Together",
"empty-user": "Utenti non connessi",
"host": "Music Together Host",
"join": "Unisciti a Music Together",
"permission": {
"all": "Consenti ai Guest di controllare la playlist e il player",
"host-only": "Solo l'Host può controllare la playlist e il player",
"playlist": "Consenti ai Guest di controllare la playlist"
},
"set-permission": "Cambia autorizzazione di controllo",
"status": {
"disconnected": "Disconnesso",
"guest": "Connesso come Guest",
"host": "Connesso come Host"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Impossibile aggiungere il brano",
"closed": "Music Together chiuso",
"disconnected": "Music Together disconnesso",
"host-failed": "Impossibile ospitare Music Together",
"id-copied": "L'ID dell Host è stato copiato negli appunti",
"id-copy-failed": "Impossibile copiare l'ID dell'host negli appunti",
"join-failed": "Impossibile unirsi a Music Together",
"joined": "Unito a Music Together",
"permission-changed": "L'autorizzazione di Music Together è cambiata in {{permission}}",
"remove-song-failed": "Impossibile rimuovere il brano",
"user-connected": "{{name}} si è unito a Music Together",
"user-disconnected": "{{name}} ha lasciato Music Together"
}
},
"navigation": {
"description": "Frecce di navigazione Avanti/Indietro integrate direttamente nell'interfaccia, come nel tuo browser preferito",
"name": "Navigazione"
},
"no-google-login": {
"description": "Rimuovi i pulsanti di accesso e i link di Google dall'interfaccia",
"name": "Nessun Login di Google"
"name": "Nessun login di Google"
},
"notifications": {
"description": "Mostra una notifica quando viene riprodotto un brano (le notifiche interattive sono disponibili su Windows)",
@ -462,22 +521,22 @@
"keybind-options": {
"hotkey": "Hotkey"
},
"label": "Scegliere un'hotkey per attivare Picture-in-Picture",
"title": "Picture-in-Picture Hotkey"
"label": "Scegliere un'hotkey per attivare Picture-in-picture",
"title": "Picture-in-picture Hotkey"
}
},
"save-window-position": "Salva la posizione della finestra",
"save-window-size": "Salva la dimensione della finestra",
"use-native-pip": "Usa il PiP nativo del browser"
},
"name": "Picture in Picture",
"name": "Picture-in-Picture",
"templates": {
"button": "Picture in Picture"
"button": "Picture-in-Picture"
}
},
"playback-speed": {
"description": "Ascolto veloce, ascolto lento! Aggiunge un cursore che controlla la velocità di riproduzione del brano",
"name": "Velocità Riproduzione",
"name": "Velocità riproduzione",
"templates": {
"button": "Velocità"
}
@ -489,7 +548,7 @@
"custom-volume-steps": "Imposta incrementi di volume personalizzati",
"global-shortcuts": "Hotkey globali"
},
"name": "Volume Preciso",
"name": "Volume preciso",
"prompt": {
"global-shortcuts": {
"keybind-options": {
@ -518,6 +577,39 @@
"description": "Permette di cambiare la qualità del video con un pulsante in sovrimpressione",
"name": "Cambia qualità video"
},
"scrobbler": {
"description": "Aggiunge il supporto per lo scrobbling (Last.fm, Listenbrainz ecc.)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Impossibile autenticarsi con Last.fm\nNascondi il popup fino al prossimo riavvio.",
"title": "Autenticazione fallita"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Impostazione Last.fm API"
},
"listenbrainz": {
"token": "Inserire il token utente per ListenBrainz"
},
"scrobble-other-media": "Scrobble altri media"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "API key per Last.fm",
"api-secret": "API secret per Last.fm"
},
"listenbrainz": {
"token": {
"label": "Inserisci il tuo token utente ListenBrainz:",
"title": "Token ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Consente di impostare tasti di scelta rapida globali per la riproduzione (riproduci/pausa/successivo/precedente) + disabilita l'OSD multimediale sovrascrivendo i tasti multimediali + abilita Ctrl/CMD + F per la ricerca + abilita il supporto Linux MPRIS per i tasti multimediali + tasti di scelta rapida personalizzati per utenti avanzati",
"menu": {
@ -537,21 +629,25 @@
}
}
},
"skip-disliked-songs": {
"description": "Salta i brani che non ti piacciono",
"name": "Salta i brani che non ti piacciono"
},
"skip-silences": {
"description": "Salta automaticamente le parti silenziose nei brani",
"name": "Salta Silenzi"
"name": "Salta silenzi"
},
"sponsorblock": {
"description": "Salta automaticamente le parti non musicali, come l'intro/outro delle canzoni o le parti dei video musicali in cui non viene riprodotto il brano",
"name": "SponsorBlock"
"name": "Blocco sponsor"
},
"taskbar-mediacontrol": {
"description": "Controlla riproduzione dalla taskbar di Windows",
"name": "Controlli Multimediali Taskbar"
"name": "Controlli multimediali sulla taskbar"
},
"touchbar": {
"description": "Aggiunge un widget TouchBar per gli utenti macOS",
"name": "Touch Bar"
"name": "Touch Bar (per MacOS)"
},
"tuna-obs": {
"description": "Integrazione con il plugin OBS Tuna",
@ -573,7 +669,7 @@
"label": "Modalità",
"submenu": {
"custom": "Brano/Video personalizzato",
"disabled": "Disabilitato",
"disabled": "Disattivato",
"native": "Brano/Video nativo"
}
}
@ -588,7 +684,7 @@
"menu": {
"visualizer-type": "Tipo di visualizzazione"
},
"name": "Visualizzatore"
"name": "Visualizzatore grafico"
}
}
}

View File

@ -105,7 +105,7 @@
"label": "プロキシ",
"prompt": {
"label": "プロキシのアドレスを入力: (空にすると無効化)",
"placeholder": "例: socks5://127.0.0.1:9999",
"placeholder": "例: SOCKS5://127.0.0.1:9999",
"title": "プロキシ"
}
},
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "有効",
"label": "プラグイン"
"label": "プラグイン",
"new": "新着"
},
"view": {
"label": "表示",
@ -190,7 +191,11 @@
"previous": "前の曲",
"quit": "終了",
"restart": "アプリを再起動",
"show": "ウィンドウを表示"
"show": "ウィンドウを表示",
"tooltip": {
"default": "YouTube ミュージック",
"with-song-info": "YouTube ミュージック: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -199,14 +204,26 @@
"menu": {
"blocker": "ブロッカー"
},
"name": "Adblocker"
"name": "広告ブロッカー"
},
"album-actions": {
"description": "「Undislike嫌いではない」「Dislike嫌い」「Like好き」「Unlike好きではない」ボタンを追加し、プレイリストやアルバム内のすべての曲にこれらを適用します",
"name": "アルバムアクション"
},
"album-color-theme": {
"description": "アルバムカバーの色をベースにして動的テーマと視覚効果を適用します",
"menu": {
"color-mix-ratio": {
"label": "カラー混合比率",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "アルバムカラーベースのテーマ"
},
"ambient-mode": {
"description": "動画の間接照明を画面背景に投射します",
"description": "動画の内容に合った淡い色に画面背景を変化させるライティング効果を適応します",
"menu": {
"blur-amount": {
"label": "ぼかしの強さ",
@ -239,9 +256,9 @@
}
},
"smoothness-transition": {
"label": "スムーズな切り替え",
"label": "スムーズな切り替え",
"submenu": {
"during": "{{interpolationTime}}秒間切り替え"
"during": "{{interpolationTime}}秒間切り替え"
}
},
"use-fullscreen": {
@ -289,7 +306,7 @@
"menu": {
"advanced": "詳細設定"
},
"name": "クロスフェード[ベータ]",
"name": "クロスフェード [ベータ]",
"prompt": {
"options": {
"multi-input": {
@ -408,10 +425,6 @@
},
"name": "アプリ内メニュー"
},
"last-fm": {
"description": "Last.fmのscrobblingサポートを追加",
"name": "Last.fm"
},
"lumiastream": {
"description": "Lumia Streamのサポートを追加",
"name": "Lumia Stream [ベータ]"
@ -426,6 +439,52 @@
"fetched-lyrics": "Geniusから歌詞取得完了"
}
},
"music-together": {
"description": "プレイリストを他の人と共有します。 ホストが曲を再生すると、他の全員にも同じ曲が聞こえます",
"dialog": {
"enter-host": "ホストIDを入力"
},
"internal": {
"save": "保存",
"track-source": "トラックソース",
"unknown-user": "不明なユーザー"
},
"menu": {
"click-to-copy-id": "ホストIDをコピー",
"close": "一緒に音楽を閉じる",
"connected-users": "接続されているユーザー",
"disconnect": "一緒に音楽を切断する",
"empty-user": "接続中のユーザーはいません",
"host": "Music Together ホスト",
"join": "一緒に音楽に参加",
"permission": {
"all": "ゲストがプレイリストとプレーヤーを制御できるようにする",
"host-only": "ホストのみがプレイリストとプレーヤーを制御できます",
"playlist": "ゲストによるプレイリストの制御を許可する"
},
"set-permission": "制御権限を変更",
"status": {
"disconnected": "切断されました",
"guest": "ゲストとして接続しました",
"host": "ホストとして接続されています"
}
},
"name": "一緒に音楽 [ベータ版]",
"toast": {
"add-song-failed": "曲の追加に失敗しました",
"closed": "一緒に音楽が閉じられました",
"disconnected": "一緒に音楽が切断されました",
"host-failed": "一緒に音楽のホストに失敗しました",
"id-copied": "ホストIDがクリップボードにコピーされました",
"id-copy-failed": "ホストIDをクリップボードにコピー出来ませんでした",
"join-failed": "一緒に音楽に参加出来ませんでした",
"joined": "一緒に音楽に参加しました",
"permission-changed": "一緒に音楽の権限が \"{{permission}}\" に変更されました",
"remove-song-failed": "曲の削除に失敗しました",
"user-connected": "{{name}} が一緒に音楽に参加しました",
"user-disconnected": "{{name}} が一緒に音楽を退出しました"
}
},
"navigation": {
"description": "ブラウザの戻る・進むボタンのようにUIからコントロールできるボタン",
"name": "ナビゲーション"
@ -518,8 +577,41 @@
"description": "ビデオオーバーレイのボタンを使用してビデオ品質を変更できるようにします",
"name": "ビデオ品質チェンジャー"
},
"scrobbler": {
"description": "スクロブリング対応を追加しますlast.fm、Listenbrainzなど",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm の認証に失敗しました\n次の再起動までポップアップは非表示になります。",
"title": "認証に失敗"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API 設定"
},
"listenbrainz": {
"token": "ListenBrainzユーザートークンを入力してください"
},
"scrobble-other-media": "他のメディアを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 サポートを有効にする + 上級ユーザー向けのカスタム ホットキー を可能にします",
"description": "再生用のグローバル ホットキー (再生/一時停止/次/前) の設定メディア キーをオーバーライドしてメディア OSD を無効にするCtrl/CMD + F による検索を有効にする メディアキーの Linux mpris サポートを有効にする 上級ユーザー向けのカスタム ホットキー を可能にします",
"menu": {
"override-media-keys": "メディアキーを上書き",
"set-keybinds": "グローバルソングコントロールを設定する"
@ -551,7 +643,7 @@
},
"taskbar-mediacontrol": {
"description": "Windowsタスクバーから再生をコントロール",
"name": "Taskbar Media Control"
"name": "タスクバーメディアコントロール"
},
"touchbar": {
"description": "masOSユーザー向けにTouchBarウィジェットを追加",

View File

@ -105,7 +105,7 @@
"label": "프록시 설정",
"prompt": {
"label": "프록시 주소를 입력하세요: (비워두면 비활성화됨)",
"placeholder": "예제: socks5://127.0.0.1:9999",
"placeholder": "예제: SOCKS5://127.0.0.1:9999",
"title": "프록시 설정"
}
},
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "활성화",
"label": "확장"
"label": "확장",
"new": "NEW"
},
"view": {
"label": "보기",
@ -190,23 +191,39 @@
"previous": "이전",
"quit": "종료",
"restart": "앱 재시작",
"show": "창 표시"
"show": "창 표시",
"tooltip": {
"default": "유튜브 뮤직",
"with-song-info": "유튜브 뮤직: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "모든 광고와 트래커를 즉시 차단합니다",
"menu": {
"blocker": "애드블록 타입"
"blocker": "광고 차단 타입"
},
"name": "애드블록"
"name": "광고 차단기"
},
"album-actions": {
"description": "좋아요, 싫어요 버튼을 추가하고, 결과를 재생 목록 또는 앨범의 모든 노래에 적용합니다",
"name": "앨범 액션"
},
"album-color-theme": {
"description": "앨범 색상 팔레트를 기반으로 동적 테마 및 시각 효과를 적용합니다",
"menu": {
"color-mix-ratio": {
"label": "색상 혼합 비율",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "앨범 컬러 기반 테마"
},
"ambient-mode": {
"description": "영상의 간접 조명을 화면 배경에 투사합니다.",
"description": "영상의 간접 조명을 화면 배경에 투사합니다",
"menu": {
"blur-amount": {
"label": "흐림 효과 강도",
@ -408,10 +425,6 @@
},
"name": "인앱 메뉴"
},
"last-fm": {
"description": "Last.fm에 대한 스크러블 지원을 추가합니다",
"name": "Last.fm"
},
"lumiastream": {
"description": "Lumia Stream 지원을 추가합니다",
"name": "Lumia Stream [베타]"
@ -426,6 +439,52 @@
"fetched-lyrics": "Genius에서 가사 불러옴"
}
},
"music-together": {
"description": "여러명과 함께 플레이리스트를 공유합니다. 호스트가 음악을 재생하면, 다른 사용자들도 같은 노래를 들을 수 있습니다",
"dialog": {
"enter-host": "호스트 아이디를 입력하세요"
},
"internal": {
"save": "저장",
"track-source": "재생 중인 트랙 출처",
"unknown-user": "알 수 없는 사용자"
},
"menu": {
"click-to-copy-id": "호스트 아이디 복사",
"close": "Music Together 닫기",
"connected-users": "연결된 사용자",
"disconnect": "Music Together 연결 끊기",
"empty-user": "연결된 사용자 없음",
"host": "Music Together 호스트",
"join": "Music Together 참여",
"permission": {
"all": "게스트가 모두 제어 가능",
"host-only": "호스트만 제어 가능",
"playlist": "게스트가 재생목록 제어 가능"
},
"set-permission": "제어 권한 변경",
"status": {
"disconnected": "연결 끊김",
"guest": "게스트로 연결됨",
"host": "호스트로 연결됨"
}
},
"name": "Music Together [베타]",
"toast": {
"add-song-failed": "노래 추가 실패",
"closed": "Music Together가 닫혔습니다",
"disconnected": "Music Together 연결이 끊어졌습니다",
"host-failed": "Music Together를 열 수 없습니다",
"id-copied": "호스트 아이디가 클립보드에 복사되었습니다",
"id-copy-failed": "호스트 ID를 클립보드에 복사하지 못했습니다",
"join-failed": "Music Together에 참여할 수 없습니다",
"joined": "Music Together에 참여했습니다",
"permission-changed": "Music Together 제어 권한이 \"{{permission}}\"(으)로 변경되었습니다",
"remove-song-failed": "노래 제거 실패",
"user-connected": "{{name}}님이 Music Together에 참여했습니다",
"user-disconnected": "{{name}}님이 Music Together에서 나갔습니다"
}
},
"navigation": {
"description": "브라우저에서처럼, UI에 직접 통합된 앞으로/뒤로 탐색하는 화살표",
"name": "탐색"
@ -518,8 +577,41 @@
"description": "영상 오버레이의 버튼으로 영상 품질을 변경할 수 있습니다",
"name": "영상 품질 체인저"
},
"scrobbler": {
"description": "스크로블링 지원을 추가합니다 (예: last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm 인증에 실패했습니다\n다음에 다시 시작할 때까지 팝업을 숨깁니다.",
"title": "인증 실패"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API 설정"
},
"listenbrainz": {
"token": "ListenBrainz 유저 토큰 입력"
},
"scrobble-other-media": "다른 미디어 스크로블하기"
},
"name": "스크로블러",
"prompt": {
"lastfm": {
"api-key": "Last.fm API 키",
"api-secret": "Last.fm API 비밀 키"
},
"listenbrainz": {
"token": {
"label": "ListenBrainz 유저 토큰을 입력하세요:",
"title": "ListenBrainz 토큰"
}
}
}
},
"shortcuts": {
"description": "재생을 위한 전역 단축키 설정 허용 (재생/일시 정지/다음/이전) + 미디어 키를 재정의하여 미디어 OSD 비활성화 + Ctrl/CMD + F 검색 활성화 + 미디어 키에 대한 리눅스 MPRIS 지원 활성화 + 고급 사용자를 위한 사용자 지정 단축키 지원",
"description": "재생을 위한 전역 단축키 설정 허용 (재생/일시 정지/다음/이전), 미디어 키를 재정의하여 미디어 OSD 비활성화, Ctrl/CMD + F 검색 활성화, 미디어키 지원을 위해 리눅스 MPRIS 지원 활성화, 고급 사용자를 위한 사용자 지정 단축키 지원 추가",
"menu": {
"override-media-keys": "미디어 키 재정의",
"set-keybinds": "전역 노래 제어 설정"

595
src/i18n/resources/lt.json Normal file
View File

@ -0,0 +1,595 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Nepavyko įvykdyti įskiepio {{pluginName}}::{{contextName}}",
"executed-at-ms": "Įskiepis {{pluginName}}::{{contextName}} įvykdytas per {{ms}}ms",
"initialize-failed": "Nepavyko inicijuoti įskiepio \"{{pluginName}}\"",
"load-all": "Kraunama visus įskiepius",
"load-failed": "Nepavyko užkrauti įskiepio \"{{pluginName}}\"",
"loaded": "Įskiepis \"{{pluginName}}\" užkrautas",
"unload-failed": "Nepavyko iškrauti įskiepio \"{{pluginName}}\"",
"unloaded": "Įskiepis \"{{pluginName}}\" iškrautas"
}
}
},
"language": {
"code": "lt",
"local-name": "Lietuvių kalba",
"name": "Lithuanian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Baigta krauti. \"DevTools\" atidaryta"
},
"i18n": {
"loaded": "\"i18n\" užkrauta"
},
"second-instance": {
"receive-command": "Gauta komanda per protokolą: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS failas \"{{cssFile}}\" neegzistuoja, ignoruojama"
},
"unresponsive": {
"details": "Nereguojanti paklaida\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Išvaloma programos talpykla"
},
"window": {
"tried-to-render-offscreen": "Langas bandė vaizduotis už ekrano ribų, langoDydis={{windowSize}}, ekranoDydis={{displaySize}}, pozicija={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Meniu yra paslėpta, naudokite 'Alt', kad ją parodyti (arba 'Escape' jei naudojama programos meniu)",
"message": "\"Paslėpti Meniu\" yra įjungta",
"title": "Įjungta \"Paslėpti Meniu\""
},
"need-to-restart": {
"buttons": {
"later": "Vėliau",
"restart-now": "Perkrauti Dabar"
},
"detail": "\"{{pluginName}}\" įskiepis reikalauja perkrovimą, kad veiktų",
"message": "\"{{pluginName}}\" reikia perkrovimo",
"title": "Reikiamas perkrovimas"
},
"unresponsive": {
"buttons": {
"quit": "Išeiti",
"relaunch": "Perleisti",
"wait": "Palaukti"
},
"detail": "Mes apgailestaujame dėl nepatogumų! prašau pasirinkti ką daryti:",
"message": "Programa Neatsako",
"title": "Langas Neatsako"
},
"update-available": {
"buttons": {
"disable": "Išjungti Atnaujinimus",
"download": "Atsisiųsti",
"ok": "Gerai"
},
"detail": "Nauja versija yra prieinama ir gali būti atsisiųsta {{downloadLink}}",
"message": "Nauja versija yra prieinama",
"title": "Prieinamas Atnaujinimas"
}
},
"menu": {
"about": "Apie",
"navigation": {
"label": "Navigacija",
"submenu": {
"copy-current-url": "Nukopijuoti dabartinį URL",
"go-back": "Grįžti Atgal",
"go-forward": "Eiti į priekį",
"quit": "Išeiti",
"restart": "Perkrauti programą"
}
},
"options": {
"label": "Nustatymai",
"submenu": {
"advanced-options": {
"label": "Išplėstiniai nustatymai",
"submenu": {
"auto-reset-app-cache": "Perkrauti programos talpyklą, kai programa paleidžiama",
"disable-hardware-acceleration": "Išjungti aparatūros pagreitį",
"edit-config-json": "Redaguoti config.json",
"override-user-agent": "Perrašyti \"User-Agent\"",
"restart-on-config-changes": "Perkrauti po config pasikeitimo",
"set-proxy": {
"label": "Nustatyti įgaliotajį serverį",
"prompt": {
"label": "Įvesti Įgaliotojo serverio adresą: (palikti tuščią, kad išjungti)",
"placeholder": "Pavyzdys: SOCKS5://127.0.0.1:9999",
"title": "Nustatyti įgaliotajį serverį"
}
},
"toggle-dev-tools": "Įjungti/Išjungti DevTools"
}
},
"always-on-top": "Visada viršuje",
"auto-update": "Automatinis Atnaujinimas",
"hide-menu": {
"dialog": {
"message": "Meniu bus paslėpta per kitą paleidimą, naudokite [Alt], kad ją parodyti (arba kairinio kirčio ženklą [`] jei naudojama programos meniu)",
"title": "\"Paslėpti Meniu\" įjungtas"
},
"label": "Paslėpti Meniu"
},
"language": {
"dialog": {
"message": "Kalba bus pakeista po perkrovimo",
"title": "Kalba Pakeista"
},
"label": "Kalba",
"submenu": {
"to-help-translate": "Norite padėti išversti? Paspauskite čia"
}
},
"resume-on-start": "Tęsti paskutinę dainą, kai programa bus paleista",
"single-instance-lock": "Vienkartinis užraktas",
"start-at-login": "Pradėti nuo prisijungimo",
"starting-page": {
"label": "Pradžios puslapis",
"unset": "Nenustatyta"
},
"tray": {
"label": "Padėklas",
"submenu": {
"disabled": "Išjungta",
"enabled-and-hide-app": "Įjungta ir slėpti programos langą",
"enabled-and-show-app": "Įjungta ir rodyti programos langą",
"play-pause-on-click": "Paleisti/Pristabdyti ant paspaudimo"
}
},
"visual-tweaks": {
"label": "Vizualiniai patobulinimai",
"submenu": {
"like-buttons": {
"default": "Numatytasis",
"force-show": "Priversti rodyti",
"hide": "Slėpti",
"label": "\"Patinka\" mygtukai"
},
"remove-upgrade-button": "Nerodyti \"Patobulinti\" mygtuko",
"theme": {
"label": "Tema",
"submenu": {
"import-css-file": "Įkelti pasirinktinį CSS failą",
"no-theme": "Be temos"
}
}
}
}
}
},
"plugins": {
"enabled": "Įjungta",
"label": "Įskiepiai",
"new": "NAUJIENA"
},
"view": {
"label": "Vaizdas",
"submenu": {
"force-reload": "Priverstinai perkrauti",
"reload": "Perkrauti",
"reset-zoom": "Tikras dydis",
"toggle-fullscreen": "Įjungti/Išjungti Pilną Ekraną",
"zoom-in": "Priartinti",
"zoom-out": "Nutolinti"
}
}
},
"tray": {
"next": "Kitas",
"play-pause": "Paleisti/Pristabdyti",
"previous": "Ankstesnis",
"quit": "Išeiti",
"restart": "Perkrauti programą",
"show": "Rodyti langą"
}
},
"plugins": {
"adblocker": {
"description": "Blokuoti visas reklamas ir seklius",
"menu": {
"blocker": "Blokuotojas"
},
"name": "Reklamų blokuotojas"
},
"album-color-theme": {
"description": "Pritaiko dinamišką temą ir vizualinius efektus pagal albumo spalvų paletę",
"name": "Albumo Spalvų Tema"
},
"ambient-mode": {
"description": "Pritaiko apšvietimo efektą, perteikdamas švelnias vaizdo įrašo spalvas į ekrano foną.",
"menu": {
"blur-amount": {
"label": "Suliejimo kiekis",
"submenu": {
"pixels": "{{blurAmount}} pikseliai"
}
},
"buffer": {
"label": "Buferis",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Skaidrumas",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Kokybė",
"submenu": {
"pixels": "{{quality}} pikseliai"
}
},
"size": {
"label": "Dydis",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Perliejimo švelnumas",
"submenu": {
"during": "Per {{interpolationTime}}s"
}
},
"use-fullscreen": {
"label": "Naudojamas visas ekranas"
}
},
"name": "Aplinkos rėžimas"
},
"audio-compressor": {
"description": "Pritaikyti garso kompresiją (sumažina garsiausių signalo dalių garsumą ir padidina švelniausių dalių garsumą)",
"name": "Garso Kompresorius"
},
"blur-nav-bar": {
"description": "Padaro navigacijos lentą permatomą ir susiliejusią",
"name": "Sulieti Navigacijos Lentą"
},
"bypass-age-restrictions": {
"description": "Apeiti \"Youtube\" amžiaus patikrinimą",
"name": "Apeiti Amžiaus Apribojimus"
},
"captions-selector": {
"description": "„YouTube Music“ Garso takelių antraščių parinkiklis",
"menu": {
"autoload": "Automatiškai pasirinkti paskutinę naudotą antraštę",
"disable-captions": "Pagal numatytuosius nustatymus išjungti antraštės"
},
"name": "Antraščių parinkiklis",
"prompt": {
"selector": {
"label": "Dabartinė antraščių kalba: {{language}}",
"none": "Joks",
"title": "Pasirinkti antraščių kalbą"
}
},
"templates": {
"title": "Atidaryti antraščių parinkiklį"
}
},
"compact-sidebar": {
"description": "Visada nustatyti šoninę juostą kompaktiniame rėžime",
"name": "Kompaktinė šoninė juosta"
},
"crossfade": {
"description": "Perliejimas tarp dainų",
"menu": {
"advanced": "Išplėstinė"
},
"name": "Perliejimas [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Išblukimo trukmė (ms)",
"fade-out-duration": "Išnykimo trukmė (ms)",
"fade-scaling": {
"label": "Išblukimo stiprumas",
"linear": "Linijinis",
"logarithmic": "Logaritminis"
},
"seconds-before-end": "Pradėti lieti dainas N sekundžių prieš pabaigą"
},
"title": "Perliejimo nustatymai"
}
}
},
"disable-autoplay": {
"description": "Pradeda dainą pristabdytame rėžime",
"menu": {
"apply-once": "Pritaiko tik per programos paleidimą"
},
"name": "Išjungti Automatinį leidimą"
},
"discord": {
"backend": {
"already-connected": "Bandyta prisijungti naudojant aktyvų ryšį",
"connected": "Prisijungta prie \"Discord\"",
"disconnected": "Atsijungta nuo \"Discord\""
},
"description": "Parodyk savo draugams ko tu klausaisi su \"Turtingas Buvimas\" (Rich Presence)",
"menu": {
"auto-reconnect": "Automatiškai prisijungti",
"clear-activity": "Išvalyti veiklą",
"clear-activity-after-timeout": "Išvalyti veiklą po skirtojo laiko",
"connected": "Prisijungta",
"disconnected": "Atsijungta",
"hide-duration-left": "Slėpti kiek liko laiko",
"hide-github-button": "Slėpti \"GitHub\" nuorodos mygtuką",
"play-on-youtube-music": "Leisti ant \"Youtube Music\"",
"set-inactivity-timeout": "Nustatyti neveiklumo laiką"
},
"name": "\"Discord\" Turtingas Buvimas (Rich Presence)",
"prompt": {
"set-inactivity-timeout": {
"label": "Įveskite neveiklumo skirtąjį laiką sekundėmis:",
"title": "Nustatyti neveiklumo laiką"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Gerai"
},
"message": "Aaa! Apgailestaujame, nepavyko atsisiųsti…",
"title": "Paklaida atsisiunčiant!"
},
"start-download-playlist": {
"buttons": {
"ok": "Gerai"
},
"detail": "({{playlistSize}} dainos)",
"message": "Atsisiunčiama {{playlistTitle}} grojaraštį",
"title": "Prasidėjo atsisiuntimas"
}
},
"feedback": {
"conversion-progress": "Konversija: {{percent}}%",
"converting": "Konvertuojama…",
"done": "Baigta: {{filePath}}",
"download-info": "Atsiunčiama {{artist}} - {{title}} {{videoId}}",
"download-progress": "Atsisiuntimas: {{percent}}%",
"downloading": "Atsisiunčiama…",
"downloading-counter": "Atsisiunčiama {{current}}/{{total}}…",
"downloading-playlist": "Atsisiunčiamas grojaraštis \"{{playlistTitle}}\" - {{playlistSize}} dainų {{playlistId}}",
"error-while-downloading": "Paklaida atsisiunčiant \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "Aplankas {{playlistFolder}} jau egzistuoja",
"getting-playlist-info": "Gaunama grojaraščio informacija…",
"loading": "Kraunama…",
"playlist-has-only-one-song": "Grojaraštis turi tik vieną elementą, jis atsisiunčiamas tiesiogiai",
"playlist-id-not-found": "Grojaraščio ID nerastas",
"playlist-is-empty": "Grojaraštis yra tuščias",
"playlist-is-mix-or-private": "Paklaida gaunant grojaraščio informaciją: Pasitikrink, kad jis nėra privatus ar \"Surinkta specialiai jums\" grojaraštis\n\n{{error}}",
"preparing-file": "Failas paruošiamas…",
"saving": "Išsaugojama…",
"trying-to-get-playlist-id": "Bandoma gauti grojaraščio ID: {{playlistId}}",
"video-id-not-found": "Vaizdo įrašas nerastas",
"writing-id3": "Rašoma ID3 žymes…"
}
},
"description": "Atsisiunčia MP3 / šaltinio garsą tiesiogiai iš sąsajos",
"menu": {
"choose-download-folder": "Pasirinkti atsisiuntimų aplanką",
"download-playlist": "Atsisiųsti grojaraštį",
"presets": "Iš anksto nustatyti nustatymai",
"skip-existing": "Praleisti egzistuojančius failus"
},
"name": "Atsiuntėjas",
"renderer": {
"can-not-update-progress": "Nepavyko atnaujinti eigos"
},
"templates": {
"button": "Atsisiųsti"
}
},
"exponential-volume": {
"description": "Padaro garsumo slankiklį eksponentinį, kad būtų lengviau pasirinkti mažesnį garsumą.",
"name": "Eksponentinis garsas"
},
"in-app-menu": {
"description": "Duoda meniu lentoms įmantrią, tamsią ar albumo spalvos išvaizdą",
"menu": {
"hide-dom-window-controls": "Slėpti DOM lango kontroles"
},
"name": "Programos Meniu"
},
"lumiastream": {
"description": "Prideda \"Lumia Stream\" palaikymą",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Prideda daugumai dainių žodžių tekstus",
"menu": {
"romanized-lyrics": "Romanizuoti dainų tekstai"
},
"name": "\"Genius\" Žodžių tekstai",
"renderer": {
"fetched-lyrics": "Gauti žodžiai iš „Genius“"
}
},
"navigation": {
"description": "Kitas/Ankstenis navigacijos rodyklės tiesiogiai integruotos sąsajoje, kaip tavo mėgstamiausioje naršyklėje",
"name": "Navigacija"
},
"no-google-login": {
"description": "Pašalinti \"Google\" prisijungimo mygtukus ir nuorodas iš sąsjos",
"name": "Be \"Google\" Prisijungimo"
},
"notifications": {
"description": "Rodyti pranešimą, kai pradeda groti daina (interaktyvūs pranešimai pasiekiami sistemoje \"Windows\")",
"menu": {
"interactive": "Interaktyvūs pranešimai",
"interactive-settings": {
"label": "Interaktyvūs nustatymai",
"submenu": {
"hide-button-text": "Paslėpti mygtuko tekstą",
"refresh-on-play-pause": "Atnaujinti ant Paleidimo/Pristabdymo",
"tray-controls": "Atidaryti/Uždaryti ant padėklo paspaudimo"
}
},
"priority": "Pranešimų pirminybė",
"toast-style": "Skrudintas stilius",
"unpause-notification": "Rodyti pranešimus po dainos paleidimo"
},
"name": "Pranešimai"
},
"picture-in-picture": {
"description": "Leidžia pakeisti programą į \"picture-in-picture\" rėžimą",
"menu": {
"always-on-top": "Visada ant viršaus",
"hotkey": {
"label": "Spartusis klavišas",
"prompt": {
"keybind-options": {
"hotkey": "Spartusis klavišas"
},
"label": "Pasirinkti spartujį klaviša, kad įjungti/išjungti \"picture-in-picture\"",
"title": "\"Picture-in-picture\" Spartusis klavišas"
}
},
"save-window-position": "Išsaugoti lango poziciją",
"save-window-size": "Išsaugoti lango dydį",
"use-native-pip": "Naudoti naršyklės savajį PiP"
},
"name": "Picture-in-picture",
"templates": {
"button": "Picture-in-picture"
}
},
"playback-speed": {
"description": "Klausyk greitai, klausyk lėtai! Prideda slankiklį, kuris valdo dainos greitį",
"name": "Atkūrimo Greitis",
"templates": {
"button": "Greitis"
}
},
"precise-volume": {
"description": "Tiksliai valdykite garsumą naudodami pelės ratuką / sparčiuosius klavišus, naudodami pritaikytą HUD ir pritaikomus garsumo žingsnius",
"menu": {
"arrows-shortcuts": "Vietiniai rodyklių klavišai valdikliai",
"custom-volume-steps": "Nustatykite Pasirinktinius Garsumo Žingsnius",
"global-shortcuts": "Pasauliniai spartieji klavišai"
},
"name": "Tikslus Garsas",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Pamažinti Garsą",
"increase": "Padidinti Garsą"
},
"label": "Pasirinkti Pasaulinius garso klavišus:",
"title": "Pasauliniai Garso Klavišai"
},
"volume-steps": {
"label": "Pasirinkti Garso Didinimo/Mažinimo Žingsnius",
"title": "Garso Žingsniai"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Dabartinė Kokybė: {{quality}}",
"message": "Pasirinkite Vaizdo Kokybę:",
"title": "Pasirinkite Vaizdo Kokybę"
}
}
},
"description": "Leidžia pakeisti vaizdo kokybę su mygtuku ant vaizdo perdangos",
"name": "Vaizdo Kokybės Pakeitėjas"
},
"shortcuts": {
"description": "Leidžia nustatyti visuotinius atkūrimo sparčiuosius klavišus (paleisti / pristabdyti / kitą / ankstesnį) ir išjungti medijos OSD nepaisant medijos klavišų, įjungti Ctrl / CMD + F ieškoti, įjungti Linux MPRIS palaikymą medijos klavišams ir pasirinktinius sparčiuosius klavišus pažengusiems vartotojams.",
"menu": {
"override-media-keys": "Perrašyti Medijos klavišus",
"set-keybinds": "Nustatyti Pasaulines Dainų Kontroles"
},
"name": "Spartieji klavišai (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Kitas",
"play-pause": "Paleisti / Pristabdyti",
"previous": "Ankstesnis"
},
"label": "Pasirinkti Pasaulinius Klavišus Dainų Kontroliavimui:",
"title": "Pasauliniai Klavišai"
}
}
},
"skip-disliked-songs": {
"description": "Praleidžia nepatinkančias dainas",
"name": "Praleisti Nepatinkančias Dainas"
},
"skip-silences": {
"description": "Automatiškai praleisti tylos dalis dainose",
"name": "Praleisti Tylumas"
},
"sponsorblock": {
"description": "Automatiškai praleidžia ne muzikines dalis, pvz., įžangą/užvedimą arba muzikinių vaizdo įrašų dalis, kuriose daina negrojama",
"name": "Rėmėjų blokuotojas"
},
"taskbar-mediacontrol": {
"description": "Valdykite atkūrimą iš „Windows“ užduočių juostos",
"name": "Užduočių juostos medijos valdymas"
},
"touchbar": {
"description": "Pridedamas jutiklinės juostos valdiklis MacOS vartotojams",
"name": "TouchBar"
},
"tuna-obs": {
"description": "Integracija su OBS papildiniu \"Tuna\"",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Pridedamas mygtukas, skirtas perjungti vaizdo įrašo/dainos režimą. taip pat galite pasirinktinai pašalinti visą vaizdo įrašo skirtuką",
"menu": {
"align": {
"label": "Lygiavimas",
"submenu": {
"left": "Kairė",
"middle": "Vidurys",
"right": "Dešinė"
}
},
"force-hide": "Priverstinai pašalinti vaizdo įrašo skirtuką",
"mode": {
"label": "Rėžimas",
"submenu": {
"custom": "Pasirinktinis perjungimas",
"disabled": "Išjungta",
"native": "Vietinis perjungimas"
}
}
},
"name": "Vaizdo įrašo perjungimas",
"templates": {
"button": "Daina"
}
},
"visualizer": {
"description": "Prie grotuvo pridedamas vizualizatorius",
"menu": {
"visualizer-type": "Vizualizatoriaus tipas"
},
"name": "Vizualizatorius"
}
}
}

View File

@ -1,25 +1,160 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Klarte ikke å kjøre programtillegg {{pluginName}}::{{contextName}}",
"executed-at-ms": "Det tok {{ms}} ms å kjøre {{pluginName}}::{{contextName}}",
"initialize-failed": "Klarte ikke å igangsette «{{pluginName}}»",
"load-all": "Laster inn alle programtillegg",
"load-failed": "Klarte ikke å laste inn {{pluginName}}-programtillegget",
"loaded": "Lastet inn {{pluginName}}-programtillegget",
"unload-failed": "Kunne ikke skru av {{pluginName}}-programtillegget",
"unloaded": "{{pluginName}}-programtillegg avskrudd"
}
}
},
"language": {
"code": "nb_NO",
"local-name": "Norsk bokmål",
"name": "Norwegian Bokmål"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Innlasting fullført. Utviklerverktøy åpnet."
},
"i18n": {
"loaded": "språkstøtte innlastet"
},
"second-instance": {
"receive-command": "Mottok kommando over protokoll: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS-filen «{{cssFile}}» finnes ikke. Ignorerer."
},
"unresponsive": {
"details": "Svarer ikke\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Tømmer programhurtigbuffer"
},
"window": {
"tried-to-render-offscreen": "Prøvde å tegne vindu utenfor skjermen, størrelse={{windowSize}}, skjermstørrelse={{displaySize}}, posisjon={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menyen er skjult, bruk 'Alt' for å vise den (eller 'Escape' for å bruke menyen i programmet)",
"message": "Meny skjult",
"title": "Meny vist"
},
"need-to-restart": {
"buttons": {
"later": "Senere",
"restart-now": "Start på ny nå"
},
"detail": "{{pluginName}}-programtillegget krever programomstart før bruk.",
"message": "{{pluginName}}-programtillegget krever programomstart.",
"title": "Programomstart kreves"
},
"unresponsive": {
"buttons": {
"quit": "Avslutt",
"relaunch": "Start igjen",
"wait": "Vent"
},
"detail": "Velg blandt følgende:",
"message": "Programmet svarer ikke",
"title": "Vinduet svarer ikke"
},
"update-available": {
"buttons": {
"disable": "Skru av oppgraderinger",
"download": "Last ned",
"ok": "OK"
},
"detail": "En ny versjon er tilgjengelig og kan lastes ned fra {{downloadLink}}",
"message": "En ny versjon er tilgjengelig",
"title": "Oppgradering tilgjengelig"
}
},
"menu": {
"about": "Om",
"navigation": {
"label": "Navigasjon",
"submenu": {
"copy-current-url": "Kopier nåværende nettadresse",
"go-back": "Tilbake",
"go-forward": "Framover",
"quit": "Avslutt",
"restart": "Programomstart"
}
},
"options": {
"label": "Alternativer",
"submenu": {
"advanced-options": {
"label": "Avanserte alternativer",
"submenu": {
"auto-reset-app-cache": "Tilbakestill programhurtigbuffer når programmet startes",
"disable-hardware-acceleration": "Skru av maskinvareakselerasjon",
"edit-config-json": "Rediger config.json",
"override-user-agent": "Overstyr brukeragent",
"restart-on-config-changes": "Omstart ved oppsettsendringer",
"set-proxy": {
"label": "Sett mellomtjener",
"prompt": {
"label": "Skriv inn mellomtjeneradresse: (la stå tom for å skru av)",
"placeholder": "Eksempel: socks5://127.0.0.1:9999",
"title": "Sett mellomtjener"
}
},
"toggle-dev-tools": "Skru av/på utviklerverktøy"
}
},
"always-on-top": "Alltid på toppen",
"auto-update": "Auto-oppdatering",
"hide-menu": {
"dialog": {
"message": "Menyen vil bli skjult ved neste programstart. Bruk [Alt] for å vise den, eller gravistegn [`] hvis du bruker menyen i programmet).",
"title": "Skjuler meny"
},
"label": "Skjul meny"
},
"language": {
"dialog": {
"message": "Nytt språk vises når programmet startes på ny",
"title": "Språk endret"
},
"label": "Språk",
"submenu": {
"to-help-translate": "Klikk her for å bistå oversettelsen"
}
},
"resume-on-start": "Gjenoppta siste spor ved programstart",
"single-instance-lock": "Sperr én instans",
"start-at-login": "Start ved innlogging",
"starting-page": {
"label": "Startside",
"unset": "Opphev"
},
"tray": {
"label": "Systemkurv",
"submenu": {
"disabled": "Avskrudd"
"disabled": "Avskrudd",
"play-pause-on-click": "Spill av/pause ved klikk"
}
},
"visual-tweaks": {
"label": "Visuelle tilpasninger",
"submenu": {
"like-buttons": {
"default": "Forvalg",
"force-show": "Tving visning",
"hide": "Skjul",
"label": "Begunstningsknapper"
},
"remove-upgrade-button": "Fjern oppgraderingsknapp",
"theme": {
"label": "Drakt",
"submenu": {
@ -32,8 +167,28 @@
}
},
"plugins": {
"enabled": "Påskrudd",
"label": "Programtillegg"
},
"view": {
"label": "Vis",
"submenu": {
"force-reload": "Tving gjeninnlasting",
"reload": "Gjeninnlast",
"reset-zoom": "Faktisk størrelse",
"toggle-fullscreen": "Veksle fullskjermsvisning",
"zoom-in": "Forstørr",
"zoom-out": "Forminsk"
}
}
},
"tray": {
"next": "Neste",
"play-pause": "Spill av/pause",
"previous": "Forrige",
"quit": "Avslutt",
"restart": "Programomstart",
"show": "Vis vindu"
}
},
"plugins": {
@ -49,6 +204,7 @@
"name": "Albumsfargedrakt"
},
"ambient-mode": {
"description": "Ifører lyseffekt ved å hente myke farger fra videoen inn i skjermens bakgrunn.",
"menu": {
"blur-amount": {
"label": "Tilsløringsmengde",
@ -56,6 +212,12 @@
"pixels": "{{blurAmount}} piksler"
}
},
"buffer": {
"label": "Mellomlager",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Dekkevne",
"submenu": {
@ -73,10 +235,38 @@
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Mykhetsovergang",
"submenu": {
"during": "I løpet av {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Ved bruk av fullskjerm"
}
}
},
"name": "Omgivelsesmodus"
},
"audio-compressor": {
"description": "Anvend kompresjon for lyd (senker lydstyrken for de kraftigste delene av signalet og øker nivået i de svakeste)",
"name": "Lydkompressor"
},
"blur-nav-bar": {
"description": "Gjør navigeringsbjelken gjennomsiktig og tilslørt",
"name": "Tilslør navigasjonsfelt"
},
"bypass-age-restrictions": {
"description": "Omgå YouTube sin aldersgrenser",
"name": "Omgå aldersgrense"
},
"captions-selector": {
"description": "Undertekstverktøy for lydspor i YouTube Music",
"menu": {
"autoload": "Auto-velg sist brukte undertekst",
"disable-captions": "Ingen undertekst som forvalg"
},
"name": "Undertekstvelger",
"prompt": {
"selector": {
"label": "Nåværende tekstingsspråk: {{language}}",
@ -88,27 +278,63 @@
"title": "Åpne undertekstvelger"
}
},
"compact-sidebar": {
"description": "Alltid sett sidefeltet i kompakt modus",
"name": "Kompakt sidefelt"
},
"crossfade": {
"description": "Overgang mellom spor",
"menu": {
"advanced": "Avansert"
},
"name": "Overgang [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Inntoningsvarighet (ms)",
"fade-out-duration": "Uttoningsvarighet (ms)",
"fade-scaling": {
"label": "Overgangsskalering",
"linear": "Lineær",
"logarithmic": "Logaritmisk"
}
}
},
"seconds-before-end": "Overgang antall sekunder før slutt"
},
"title": "Overgangsalternativer"
}
}
},
"disable-autoplay": {
"description": "Merkerer sporstart i «pauset» modus",
"menu": {
"apply-once": "Har kun innvirkning ved oppstart"
},
"name": "Skru av autospilling"
},
"discord": {
"backend": {
"already-connected": "Forsøkte å koble til med aktiv tilkobling",
"connected": "Tilkoblet Discord",
"disconnected": "Frakoblet fra Discord"
},
"description": "Vis venne dine hva du lytter til med rik tilstedeværelse",
"menu": {
"auto-reconnect": "Automatisk retilkobling",
"clear-activity": "Tøm aktivitet",
"clear-activity-after-timeout": "Tøm aktivitet etter tidsavbrudd",
"connected": "Tilkoblet",
"disconnected": "Frakoblet",
"hide-duration-left": "Skjul gjenværende tid",
"hide-github-button": "Skjul GitHub-lenkeknapp",
"play-on-youtube-music": "Spill på YouTube Music",
"set-inactivity-timeout": "Sett tid før tidsavbrudd"
},
"name": "Rik tilstedeværelse for Discord",
"prompt": {
"set-inactivity-timeout": {
"label": "Skriv inn antall sekunder for inaktivitetstidsavbrudd:",
"title": "Sett inaktivitetstidsavbrudd"
}
}
},
"downloader": {
@ -117,12 +343,16 @@
"error": {
"buttons": {
"ok": "OK"
}
},
"message": "Nedlasting mislyktes …",
"title": "Feil i nedlastning."
},
"start-download-playlist": {
"buttons": {
"ok": "OK"
},
"detail": "({{playlistSize}} spor)",
"message": "Laster ned {{playlistTitle}}-spillelisten …",
"title": "Nedlasting startet"
}
},
@ -130,42 +360,143 @@
"conversion-progress": "Konvertering: {{percent}}%",
"converting": "Konverterer …",
"done": "Ferdig: {{filePath}}",
"download-info": "Laster ned {{artist}} — {{title}} [{{videoId}} …",
"download-progress": "Nedlastet: {{percent}}%",
"downloading": "Laster ned …",
"downloading-counter": "Laster ned {{current}}/{{total}} …",
"downloading-playlist": "Laster ned {{playlistTitle}}-spillelisten — {{playlistSize}} spor ({{playlistId}})",
"error-while-downloading": "Kunne ikke laste ned «{{author}} — {{title}}»: {{error}}",
"folder-already-exists": "{{playlistFolder}}-mappen finnes allerede",
"getting-playlist-info": "Henter spillelisteinfo …",
"loading": "Laster inn …",
"playlist-has-only-one-song": "Spillelisten har kun ett element. Laster ned direkte.",
"playlist-id-not-found": "Fant ingen spilleliste-ID",
"playlist-is-empty": "Tom spilleliste",
"playlist-is-mix-or-private": "Kunne ikke hente spillelisteinfo. Forsikre deg om at den ikke er privat eller «Mikset for deg».\n\n{{error}}",
"preparing-file": "Forbereder fil …",
"saving": "Lagrer …"
"saving": "Lagrer …",
"trying-to-get-playlist-id": "Prøver å hente spilleliste-ID: {{playlistId}}",
"video-id-not-found": "Fant ikke videoen",
"writing-id3": "Skriver ID3-tagger …"
}
},
"description": "Laster ned MP3/kildelyd direkte fra grensesnittet",
"menu": {
"choose-download-folder": "Velg nedlastningsmappe",
"download-playlist": "Last ned spilleliste",
"presets": "Forhåndsinnstillinger",
"skip-existing": "Hopp over eksisterende filer"
},
"name": "Nedlaster",
"renderer": {
"can-not-update-progress": "Kan ikke oppdatere framdrift"
},
"templates": {
"button": "Last ned"
}
},
"last-fm": {
"name": "Last.fm"
"exponential-volume": {
"description": "Gjør lydstyrkekontrollen eksponentiell, slik at det er enklere velge lavere lydstyrker.",
"name": "Eksponentiell lydstyrke"
},
"in-app-menu": {
"description": "Gir menybjelkene stilig, mørk, eller albumfarget utseende",
"menu": {
"hide-dom-window-controls": "Skjul DOM-vinduskontroller"
},
"name": "Meny i programmet"
},
"lumiastream": {
"description": "Legger til Lumia Stream-støtte",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Gir sangtekststøtte for de fleste spor",
"menu": {
"romanized-lyrics": "Romaniserte sangtekster"
},
"name": "Sangtekster fra Genius",
"renderer": {
"fetched-lyrics": "Henter sangtekster for Genius"
}
},
"navigation": {
"description": "Direkte integrering av neste/tilbake-navigasjonspilene i grensesnittet, som din favorittnettleser",
"name": "Navigasjon"
},
"no-google-login": {
"description": "Fjern Google-innloggingsknapper og lenker fra grensesnittet",
"name": "Ingen Google-innlogging"
},
"notifications": {
"description": "Vis en merknad når et spor starter avspilling (interaktive merknader er tilgjengelig på Windows)",
"menu": {
"interactive": "Interaktive merknader",
"interactive-settings": {
"label": "Interaktive innstillinger",
"submenu": {
"hide-button-text": "Skjul knappetekst",
"refresh-on-play-pause": "Gjenoppfrisk ved avspilling/pause",
"tray-controls": "Åpne/lukk med klikk i systemkurven"
}
},
"priority": "Merknadsprioritet",
"unpause-notification": "Vis merknad ved oppheving av pause"
},
"name": "Merknader"
},
"picture-in-picture": {
"description": "Tillater å bytte programmet til bilde-i-bilde modus",
"menu": {
"save-window-position": "Lagre vindusposisjon"
"always-on-top": "Alltid på toppen",
"hotkey": {
"label": "Hurtigtast",
"prompt": {
"keybind-options": {
"hotkey": "Hurtigtast"
},
"label": "Velg en hurtigtast for veksling av bilde-i-bilde",
"title": "Hurtigtast for bilde-i-bilde"
}
},
"save-window-position": "Lagre vindusposisjon",
"save-window-size": "Lagre vindusstørrelse",
"use-native-pip": "Bruk nettleserens innebygde bilde-i-bilde"
},
"name": "Bilde-i-bilde",
"templates": {
"button": "Bilde-i-bilde"
}
},
"playback-speed": {
"description": "Legger til glidebryter som kontrollerer avspillingshastighet",
"name": "Avspillingshastighet",
"templates": {
"button": "Hastighet"
}
},
"precise-volume": {
"name": "Presis lydstyrkejustering"
"description": "Kontroller lydstyrken presist ved bruk av musehjul/hurtigtaster, med egendefinert skjermoverlag og tilpassbare steg",
"menu": {
"arrows-shortcuts": "Kontroller for lokale piltaster",
"custom-volume-steps": "Sett egendefinerte lydstyrkesteg",
"global-shortcuts": "Hurtigtaster i hele programmet"
},
"name": "Presis lydstyrkejustering",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Senk lydstyrke",
"increase": "Øk lydstyrke"
},
"label": "Velg tastetilknytninger for lydstyrkejusteringskontroller i hele programmet",
"title": "Tastetilknytninger for lydstyrkejusteringskontroller i hele programmet"
},
"volume-steps": {
"label": "Velg steg for økning/senking av lydstyrke",
"title": "Lydstyrkesteg"
}
}
},
"quality-changer": {
"backend": {
@ -176,30 +507,85 @@
"title": "Velg videokvalitet"
}
}
},
"description": "Tillat endring av videokvalitet med en knapp i videooverlaget",
"name": "Vindukvalitetsvelger"
},
"shortcuts": {
"description": "Tillater bruk av hurtigtaster for hele programmet til avspilling (spill/pause/neste/forrige) + skru av media-videooverlag ved å overstyre mediataster + skru på Ctrl+CMD+F for å søke, pluss å egge til MPRIS støtte på linux for mediataster pluss egendefinerte hurtigtaster for avanserte brukere",
"menu": {
"override-media-keys": "Overstyr mediataster",
"set-keybinds": "Sett kontroller for spor i hele programmet"
},
"name": "Snarveier (og MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Neste",
"play-pause": "Spill av/pause",
"previous": "Forrige"
},
"label": "Velg kontroller for spor i hele programmet:",
"title": "Tastaturtilknytninger i hele programmet"
}
}
},
"skip-disliked-songs": {
"description": "Hopper over mislikte spor",
"name": "Hopp over mislikte spor"
},
"skip-silences": {
"description": "Hopp over stille deler av spor",
"name": "Hopp over pauser"
},
"sponsorblock": {
"description": "Hopper over ikke-musikalske deler, som intro/sluttsats, eller deler av musikkvideoer der ingen musikk spilles",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Kontroller avspilling fra din Windows-oppgavelinje",
"name": "Oppgavelinje-mediakontroll"
},
"touchbar": {
"description": "Legger til et pekefelt-miniprogram for macOS-brukere",
"name": "Pekefelt"
},
"tuna-obs": {
"description": "Integrasjon med Tuna-programtillegget i OBS",
"name": "OBS Tuna"
},
"video-toggle": {
"description": "Leger til en knapp for å bytte mellom video/spormodus. Kan også alternativt fjerne hele videofanen.",
"menu": {
"align": {
"label": "Justering",
"submenu": {
"left": "Venstre",
"middle": "Midten",
"right": "Høyre"
}
},
"force-hide": "Påtving fjerning av videofane",
"mode": {
"label": "Modus"
"label": "Modus",
"submenu": {
"custom": "Egendefinert veksling",
"disabled": "Avskrudd",
"native": "Innebygd veksling"
}
}
},
"name": "Videoveksling",
"templates": {
"button": "Spor"
}
},
"visualizer": {
"description": "Legger til en visualisator i avspilleren",
"menu": {
"visualizer-type": "Visualisatortype"
},
"name": "Visualisator"
}
}
}

View File

@ -0,0 +1,43 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Kan plug-in {{pluginName}}::{{contextName}} niet uitvoeren",
"executed-at-ms": "Plug-in {{pluginName}}::{{contextName}} uitgevoerd in {{ms}}ms",
"initialize-failed": "Kan plug-in \"{{pluginName}}\" niet laden",
"load-all": "Alle plug-ins laden",
"load-failed": "Kan plug-in \"{{pluginName}}\" niet laden",
"loaded": "Plug-in \"{{pluginName}}\" geladen",
"unload-failed": "Kan plug-in \"{{pluginName}}\" niet verwijderen",
"unloaded": "Plug-in \"{{pluginName}}\" geladen"
}
}
},
"language": {
"code": "nl",
"local-name": "Nederlands",
"name": "Dutch"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Klaar met laden, DevTools geopend"
},
"i18n": {
"loaded": "i18n geladen"
},
"second-instance": {
"receive-command": "Ontvangen commando via protocol: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS bestand \"{{cssFile}}\" niet gevonden"
},
"unresponsive": {
"details": "Niet reagerend door fout:\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "App-cache wissen"
}
}
}
}

View File

@ -44,7 +44,7 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menu jest ukryte, użyj 'Alt' aby je pokazać (lub 'Escape' jeśli używasz in-app-menu)",
"detail": "Menu jest ukryte, użyj przycisku [Alt] aby je pokazać (lub [Escape], jeśli używasz menu w aplikacji)",
"message": "Ukrywanie menu jest włączone",
"title": "Ukrywanie Menu Włączone"
},
@ -105,7 +105,7 @@
"label": "Ustaw proxy",
"prompt": {
"label": "Podaj adres Proxy: (zostaw pusty aby wyłączyć)",
"placeholder": "Przykład: socks5://127.0.0.1:9999",
"placeholder": "Przykład: SOCKS5://127.0.0.1:9999",
"title": "Ustaw proxy"
}
},
@ -116,7 +116,7 @@
"auto-update": "Automatyczne aktualizacje",
"hide-menu": {
"dialog": {
"message": "Menu będzie ukryte po następnym uruchomieniu, użyj [Alt] aby je pokazać (lub [`] jeśli używasz in-app-menu)",
"message": "Menu będzie ukryte po następnym uruchomieniu, użyj przycisku [Alt] aby je pokazać (lub [`], jeśli używasz menu w aplikacji)",
"title": "Ukrywanie menu włączone"
},
"label": "Ukryj menu"
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "Włączone",
"label": "Wtyczki"
"label": "Wtyczki",
"new": "NOWOŚĆ"
},
"view": {
"label": "Widok",
@ -190,7 +191,11 @@
"previous": "Poprzedni",
"quit": "Wyjdź",
"restart": "Uruchom ponownie aplikację",
"show": "Pokaż okno"
"show": "Pokaż okno",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "{{title}} (autorstwa {{artist}}) - YT Music"
}
}
},
"plugins": {
@ -201,12 +206,24 @@
},
"name": "Blokowanie reklam"
},
"album-actions": {
"description": "Dodaje przyciski łapek w górę i dół do wszystkich piosenek podczas w albumach lub listach odtwarzania",
"name": "Akcje albumu"
},
"album-color-theme": {
"description": "Stosuje dynamiczny motyw i efekty wizualne w oparciu o paletę kolorów albumu",
"menu": {
"color-mix-ratio": {
"label": "Intensywność koloru",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Motyw kolorów albumu"
},
"ambient-mode": {
"description": "Stosuje efekt świetlny, rzucając delikatne kolory z wideo na tło ekranu.",
"description": "Stosuje efekt świetlny, rzucając delikatne kolory z wideo na tło ekranu",
"menu": {
"blur-amount": {
"label": "Ilość rozmycia",
@ -241,7 +258,7 @@
"smoothness-transition": {
"label": "Płynność przejścia",
"submenu": {
"during": "W czasie {{interpolationTime}}s"
"during": "W czasie {{interpolationTime}} s"
}
},
"use-fullscreen": {
@ -289,12 +306,12 @@
"menu": {
"advanced": "Zaawansowane"
},
"name": "Przenikanie [Beta]",
"name": "Płynne przejście [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Czas wnikania (milisekundy)",
"fade-out-duration": "Czas zanikania (milisekundy)",
"fade-in-duration": "Czas wnikania (ms)",
"fade-out-duration": "Czas zanikania (ms)",
"fade-scaling": {
"label": "Skalowanie zanikania",
"linear": "Liniowe",
@ -406,15 +423,11 @@
"menu": {
"hide-dom-window-controls": "Ukryj kontrolki okna DOM"
},
"name": "In-App menu"
},
"last-fm": {
"description": "Dodanie obsługi scrobblingu dla Last.fm",
"name": "Last.fm"
"name": "Menu w aplikacji"
},
"lumiastream": {
"description": "Dodaje obsługę Lumia Stream",
"name": "Lumia Stream [beta]"
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Dodaje obsługę tekstów dla większości piosenek",
@ -426,6 +439,52 @@
"fetched-lyrics": "Tekst dostarczony przez Genius"
}
},
"music-together": {
"description": "Pozwala na udostępnianie listy odtwarzania z możliwością słuchania tego samego utworu co host",
"dialog": {
"enter-host": "Wpisz ID hosta"
},
"internal": {
"save": "Zapisz",
"track-source": "Źródło utworu",
"unknown-user": "Nieznany użytkownik"
},
"menu": {
"click-to-copy-id": "Kopiuj ID hosta",
"close": "Zakończ host",
"connected-users": "Połączeni użytkownicy",
"disconnect": "Rozłącz z hosta",
"empty-user": "Brak połączonych użytkowników",
"host": "Udostępnij tą listę odtwarzania",
"join": "Połącz z hostem",
"permission": {
"all": "Połączeni użytkownicy mają kontrolę nad listą odtwarzania oraz playerem",
"host-only": "Tylko host może kontrolować listę odtwarzania oraz playera",
"playlist": "Połączeni użytkownicy maja kontrolę tylko nad listą odtwarzania"
},
"set-permission": "Zmień permisję kontroli",
"status": {
"disconnected": "Rozłączony",
"guest": "Połączony jako Użytkownik",
"host": "Połączony jako Host"
}
},
"name": "Słuchanie razem [Beta]",
"toast": {
"add-song-failed": "Wystąpił błąd z dodaniem muzyki",
"closed": "Host słuchania razem został zamknięty pomyślnie",
"disconnected": "Pomyślnie rozłączono z hosta słuchania razem",
"host-failed": "Wystąpił błąd z hostem słuchania razem",
"id-copied": "ID hosta został wklejony do schowka",
"id-copy-failed": "Wystąpił błąd z próbą skopiowania ID do schowka",
"join-failed": "Wystąpił błąd z dołączeniem do hosta",
"joined": "Dołączono pomyślnie do hosta słuchania razem",
"permission-changed": "Permisja hosta została zmieniona na \"{{permission}}\"",
"remove-song-failed": "Wystąpił błąd z usunięciem utworu",
"user-connected": "Do hosta dołączył {{name}}",
"user-disconnected": "{{name}} właśnie wyszedł z hosta"
}
},
"navigation": {
"description": "Strzałki nawigacyjne Dalej/Wstecz zintegrowane bezpośrednio z interfejsem, tak jak w Twojej ulubionej przeglądarce",
"name": "Nawigacja"
@ -463,7 +522,7 @@
"hotkey": "Klawisz skrótu"
},
"label": "Wybierz klawisz skrótu do przełączania trybu obrazu w obrazie",
"title": "Klawisz skrótu Obraz w obrazie"
"title": "Klawisz skrótu obrazu w obrazie"
}
},
"save-window-position": "Zapisz pozycję okna",
@ -518,8 +577,41 @@
"description": "Umożliwia zmianę jakości wideo za pomocą przycisku na nakładce wideo",
"name": "Zmieniacz jakości wideo"
},
"scrobbler": {
"description": "Umożliwia scrobbling utworów do m.in. last.fm lub Listenbrainz",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Podczas autoryzowania z last.fm wystąpił błąd.\nSchowaj pop-up aż do następnego uruchomienia.",
"title": "Podczas autoryzowania wystąpił błąd"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Ustawienia API Last.fm"
},
"listenbrainz": {
"token": "Podaj token użytkownika ListenBrainz"
},
"scrobble-other-media": "Scrobbluj pozostałe multimedia"
},
"name": "Scrobblowanie",
"prompt": {
"lastfm": {
"api-key": "klucz API Last.fm",
"api-secret": "Sekretny klucz Last.fm API (\"secret key\")"
},
"listenbrainz": {
"token": {
"label": "Podaj swój token użytkownika ListenBrainz:",
"title": "Token ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Umożliwia ustawienie globalnych skrótów klawiszowych do odtwarzania (odtwarzanie/pauza/następny/poprzedni) + wyłączanie OSD multimediów poprzez zastąpienie klawiszy multimediów + włączanie Ctrl/CMD + F w celu wyszukiwania + włączanie obsługi linux mpris dla klawiszy multimediów + niestandardowe skróty klawiszowe dla zaawansowanych użytkowników",
"description": "Umożliwia ustawienie globalnych skrótów klawiszowych do odtwarzania (odtwarzanie/pauza/następny/poprzedni) + wyłączanie OSD multimediów poprzez zastąpienie klawiszy multimediów, włączając kombinację klawiszy Ctrl/CMD + F w celu wyszukiwania, obsługę Linux MPRIS dla klawiszy multimediów oraz niestandardowe skróty klawiszowe dla zaawansowanych użytkowników",
"menu": {
"override-media-keys": "Zastąp klawisze multimediów",
"set-keybinds": "Ustaw globalne sterowanie utworem"
@ -537,6 +629,10 @@
}
}
},
"skip-disliked-songs": {
"description": "Pomija nieulubione piosenki (zaznaczone łapką w dół)",
"name": "Pomijanie nieulubionych piosenek"
},
"skip-silences": {
"description": "Automatycznie pomijaj sekcje bez dźwięku w utworach",
"name": "Pomiń ciszę"
@ -547,7 +643,7 @@
},
"taskbar-mediacontrol": {
"description": "Steruj odtwarzaniem z paska zadań systemu Windows",
"name": "Kontrola odtwarzania z paska zadań"
"name": "Kontroler odtwarzania z paska zadań"
},
"touchbar": {
"description": "Dodaje widżet do paska dotykowego dla użytkowników systemu macOS",

View File

@ -31,10 +31,28 @@
},
"theme": {
"css-file-not-found": "Arquivo CSS \"{{cssFile}}\" não existe, ignorando"
},
"unresponsive": {
"details": "Erro sem resposta!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Limpando o cache do aplicativo"
},
"window": {
"tried-to-render-offscreen": "Janela tentou desenhar fora do ecrã, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "O menu está oculto, use a tecla 'Alt' para mostra-lo (ou 'Esc' se estiver usando o menu do aplicativo)",
"message": "Ocultar menu está ativado",
"title": "Ocultar menu ativado"
},
"need-to-restart": {
"buttons": {
"later": "Depois",
"restart-now": "Reiniciar agora"
},
"detail": "O plugin {{pluginName}} precisa ser reiniciado para ter efeito",
"message": "\"{{pluginName}}\" precisa ser reiniciado",
"title": "É necessário reiniciar"
@ -47,7 +65,7 @@
},
"detail": "Lamentamos o inconveniente! Por favor escolha o que fazer:",
"message": "A aplicação não está respondendo",
"title": "Janela não está respondendo"
"title": "A janela não está respondendo"
},
"update-available": {
"buttons": {
@ -81,11 +99,13 @@
"auto-reset-app-cache": "Reiniciar cache do aplicativo quando o aplicativo abrir",
"disable-hardware-acceleration": "Desabilitar aceleração por hardware",
"edit-config-json": "Editar config.json",
"override-user-agent": "Substituir User-Agent",
"restart-on-config-changes": "Reinicie as alterações de configurações feitas",
"set-proxy": {
"label": "Definir proxy",
"prompt": {
"label": "Inserir 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"
}
},
@ -150,7 +170,8 @@
},
"plugins": {
"enabled": "Ativado",
"label": "Plugins"
"label": "Plugins",
"new": "NOVO"
},
"view": {
"label": "Ver",
@ -170,16 +191,488 @@
"previous": "Anterior",
"quit": "Sair",
"restart": "Reiniciar aplicativo",
"show": "Mostrar janela"
"show": "Mostrar janela",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "Bloquear todos os anúncios e rastreamento automaticamente",
"name": "Adblocker"
"menu": {
"blocker": "Bloqueador"
},
"name": "Bloqueador de anúncios"
},
"album-actions": {
"description": "Adiciona os botões Gostei e Não Gostei para ser aplicado a todas as músicas em uma lista de reprodução ou álbum.",
"name": "Ações no álbum"
},
"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 com base na paleta de cores do álbum",
"menu": {
"color-mix-ratio": {
"submenu": {
"percent": "Proporção"
}
}
},
"name": "Tema de cores do álbum"
},
"ambient-mode": {
"description": "Aplica um efeito de iluminação lançando cores suaves do vídeo no fundo da tela.",
"menu": {
"blur-amount": {
"label": "Quantidade de desfoque",
"submenu": {
"pixels": "{{blurAmount}} píxeis"
}
},
"buffer": {
"label": "Buffer",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Opacidade",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Qualidade",
"submenu": {
"pixels": "{{quality}} píxeis"
}
},
"size": {
"label": "Tamanho",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Transição suave",
"submenu": {
"during": "Durante {{interpolationTime}}s"
}
},
"use-fullscreen": {
"label": "Tela cheia"
}
},
"name": "Modo Ambiente"
},
"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)",
"name": "Compressor de áudio"
},
"blur-nav-bar": {
"description": "Torna a barra de navegação transparente e desfocada",
"name": "Barra de navegação desfocada"
},
"bypass-age-restrictions": {
"description": "Ignorar a verificação de idade do YouTube",
"name": "Ignorar restrições de idade"
},
"captions-selector": {
"description": "Seletor de legenda para faixas de áudio do YouTube Music",
"menu": {
"autoload": "Selecionar automaticamente a última legenda usada",
"disable-captions": "Sem legendas por padrão"
},
"name": "Seletor de legendas",
"prompt": {
"selector": {
"label": "Idioma da legenda atual: {{language}}",
"none": "Nenhuma",
"title": "Selecione o idioma da legenda"
}
},
"templates": {
"title": "Seletor de legendas aberto"
}
},
"compact-sidebar": {
"description": "Definir sempre a barra lateral no modo compacto",
"name": "Barra lateral compacta"
},
"crossfade": {
"description": "Transição entre músicas",
"menu": {
"advanced": "Avançado"
},
"name": "Transição entre músicas [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Duração da transição no início (ms)",
"fade-out-duration": "Duração da transição no final (ms)",
"fade-scaling": {
"label": "Escala da transição",
"linear": "Linear",
"logarithmic": "Logarítmica"
},
"seconds-before-end": "Realizar transição N segundos antes do final"
},
"title": "Opções de transição"
}
}
},
"disable-autoplay": {
"description": "Faz a música começar no modo \"pausado\"",
"menu": {
"apply-once": "Aplicar apenas na inicialização"
},
"name": "Desativar reprodução automática"
},
"discord": {
"backend": {
"already-connected": "Tentativa de conexão com conexão já ativa",
"connected": "Conectado ao Discord",
"disconnected": "Desconectado do Discord"
},
"description": "Mostre aos seus amigos o que você ouve com Rich Presence",
"menu": {
"auto-reconnect": "Reconexão automática",
"clear-activity": "Limpar atividade",
"clear-activity-after-timeout": "Limpar atividade após o tempo limite",
"connected": "Conectado",
"disconnected": "Desconectado",
"hide-duration-left": "Ocultar duração restante",
"hide-github-button": "Ocultar botão de link do GitHub",
"play-on-youtube-music": "Reproduzir no YouTube Music",
"set-inactivity-timeout": "Definir tempo limite de inatividade"
},
"name": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "Insira o tempo limite de inatividade em segundos:",
"title": "Definir tempo limite de inatividade"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "OK"
},
"message": "Poxa! Desculpe, o download falhou…",
"title": "Erro no download!"
},
"start-download-playlist": {
"buttons": {
"ok": "OK"
},
"detail": "({{playlistSize}} músicas)",
"message": "Baixando lista de reprodução {{playlistTitle}}",
"title": "Download iniciado"
}
},
"feedback": {
"conversion-progress": "Conversão: {{percent}}%",
"converting": "Convertendo…",
"done": "Finalizado: {{filePath}}",
"download-info": "Baixando {{artist}} - {{title}} {{videoId}}",
"download-progress": "Baixando: {{percent}}%",
"downloading": "Baixando…",
"downloading-counter": "Baixando {{current}}/{{total}}…",
"downloading-playlist": "Baixando lista de reprodução \"{{playlistTitle}}\" - {{playlistSize}} músicas ({{playlistId}})",
"error-while-downloading": "Erro ao baixar \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "A pasta {{playlistFolder}} já existe",
"getting-playlist-info": "Obtendo informações da lista de reprodução…",
"loading": "Carregando…",
"playlist-has-only-one-song": "A lista de reprodução possui apenas um item, baixando-o diretamente",
"playlist-id-not-found": "ID da lista de reprodução não encontrado",
"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}}",
"preparing-file": "Preparando arquivos…",
"saving": "Salvando…",
"trying-to-get-playlist-id": "Tentando pegar ID da lista de reprodução: {{playlistId}}",
"video-id-not-found": "Vídeo não encontrado",
"writing-id3": "Escrevendo tags ID3…"
}
},
"description": "Baixa MP3 / fonte de áudio diretamente da interface",
"menu": {
"choose-download-folder": "Escolha a pasta de download",
"download-playlist": "Baixar lista de reprodução",
"presets": "Predefinições",
"skip-existing": "Ignorar arquivos existentes"
},
"name": "Downloader",
"renderer": {
"can-not-update-progress": "Não é possível atualizar o progresso"
},
"templates": {
"button": "Baixar"
}
},
"exponential-volume": {
"description": "Torna o controle deslizante de volume exponencial, facilitando a seleção de volumes mais baixos.",
"name": "Volume Exponencial"
},
"in-app-menu": {
"description": "Dá às barras de menu uma aparência sofisticada, escura ou com a cor do álbum",
"menu": {
"hide-dom-window-controls": "Ocultar controles da janela DOM"
},
"name": "Menu no aplicativo"
},
"lumiastream": {
"description": "Adiciona suporte Lumia Stream",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Adiciona suporte a letras para a maioria das músicas",
"menu": {
"romanized-lyrics": "Letras romanizadas"
},
"name": "Letras Genius",
"renderer": {
"fetched-lyrics": "Buscar letras no Genius"
}
},
"music-together": {
"description": "Compartilha a playlist com outros. Quando o host tocar uma música, todos poderão ouvir a mesma canção",
"dialog": {
"enter-host": "Digite o ID do Host"
},
"internal": {
"save": "Salvar",
"track-source": "Fonte da faixa",
"unknown-user": "Usuário Desconhecido"
},
"menu": {
"click-to-copy-id": "Copiar ID do Host",
"close": "Fechar o Música Juntos",
"connected-users": "Usuários Conectados",
"disconnect": "Desconectar do Música Juntos",
"empty-user": "Sem usuários conectados",
"host": "Host do Música Juntos",
"join": "Juntar ao Música Juntos",
"permission": {
"all": "Permita que outros controlem a playlist e ao player",
"host-only": "Apenas o host pode controlar a playlist e ao player",
"playlist": "Permitir que outros controlem a playlist"
},
"set-permission": "Alterar permissões de controle",
"status": {
"disconnected": "Desconectado",
"guest": "Conectado como Convidado",
"host": "Conectado como Host"
}
},
"name": "Música Juntos [Beta]",
"toast": {
"add-song-failed": "Falha ao adicionar canção",
"closed": "Música Juntos encerrado",
"disconnected": "Música Juntos foi desconectado",
"host-failed": "Falha ao hospedar o Música Juntos",
"id-copied": "ID de 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",
"join-failed": "Falha ao entrar em Música Juntos",
"joined": "Entrou em Música Juntos",
"permission-changed": "A permissão do Música Juntos foi alterada para \"{{permission}}\"",
"remove-song-failed": "Falha ao remover música",
"user-connected": "{{name}} entrou em Música Juntos",
"user-disconnected": "{{name}} saiu do Música Juntos"
}
},
"navigation": {
"description": "Setas de navegação Próximo/Voltar integradas diretamente na interface, como no seu navegador favorito",
"name": "Navegação"
},
"no-google-login": {
"description": "Remove os botões e links de login do Google da interface",
"name": "Sem login do Google"
},
"notifications": {
"description": "Exibir uma notificação quando uma música começar a tocar (notificações interativas estão disponíveis no Windows)",
"menu": {
"interactive": "Notificações interativas",
"interactive-settings": {
"label": "Configurações interativas",
"submenu": {
"hide-button-text": "Ocultar texto do botão",
"refresh-on-play-pause": "Atualizar ao reproduzir/pausar",
"tray-controls": "Abrir/Fechar no clique da bandeja"
}
},
"priority": "Prioridade de notificação",
"toast-style": "Estilo de alerta",
"unpause-notification": "Mostrar notificação ao despausar"
},
"name": "Notificações"
},
"picture-in-picture": {
"description": "Permite mudar o aplicativo para o modo picture-in-picture",
"menu": {
"always-on-top": "Sempre no topo",
"hotkey": {
"label": "Tecla de atalho",
"prompt": {
"keybind-options": {
"hotkey": "Tecla de atalho"
},
"label": "Escolha uma tecla de atalho para alternar o picture-in-picture",
"title": "Tecla de atalho picture-in-picture"
}
},
"save-window-position": "Salvar posição da janela",
"save-window-size": "Salvar tamanho da janela",
"use-native-pip": "Use PiP nativo do navegador"
},
"name": "Picture-in-picture",
"templates": {
"button": "Picture-in-picture"
}
},
"playback-speed": {
"description": "Ouça rápido, ouça devagar! Adiciona um controle deslizante que controla a velocidade da música",
"name": "Velocidade de reprodução",
"templates": {
"button": "Velocidade"
}
},
"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",
"menu": {
"arrows-shortcuts": "Controles locais das teclas de seta",
"custom-volume-steps": "Definir etapas de volume personalizadas",
"global-shortcuts": "Teclas de atalho globais"
},
"name": "Volume preciso",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Diminuir o volume",
"increase": "Aumentar o volume"
},
"label": "Escolha atalhos de teclado de volume global:",
"title": "Atalhos de teclado de volume global"
},
"volume-steps": {
"label": "Escolha as etapas de aumento/diminuição de volume",
"title": "Etapas de volume"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Qualidade atual: {{quality}}",
"message": "Escolha a qualidade do vídeo:",
"title": "Escolha a qualidade do vídeo"
}
}
},
"description": "Permite alterar a qualidade do vídeo com um botão na sobreposição de vídeo",
"name": "Trocador de qualidade do vídeo"
},
"scrobbler": {
"dialog": {
"lastfm": {
"auth-failed": {
"title": "Falha na autenticação"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Configurações de API Last.fm"
}
},
"prompt": {
"listenbrainz": {
"token": {
"label": "Insira seu token de usuário do ListenBrainz:",
"title": "Token ListenBrainz"
}
}
}
},
"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",
"menu": {
"override-media-keys": "Substituir teclas de mídia",
"set-keybinds": "Definir controles globais de música"
},
"name": "Atalhos (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Próximo",
"play-pause": "Reproduzir/Pausar",
"previous": "Anterior"
},
"label": "Escolha atalhos de teclado globais para controle de músicas:",
"title": "Atalhos globais do teclado"
}
}
},
"skip-disliked-songs": {
"description": "Pula músicas com 'não gostei'",
"name": "Pular músicas com 'não gostei'"
},
"skip-silences": {
"description": "Pular automaticamente seções de silêncio nas músicas",
"name": "Pular silêncios"
},
"sponsorblock": {
"description": "Ignora automaticamente partes não musicais, como introdução/final ou partes de videoclipes onde a música não está tocando",
"name": "SponsorBlock (bloqueador de patrocínios)"
},
"taskbar-mediacontrol": {
"description": "Controle a reprodução na barra de tarefas do Windows",
"name": "Controle de mídia da barra de tarefas"
},
"touchbar": {
"description": "Adiciona um widget TouchBar para usuários do macOS",
"name": "Barra de toque"
},
"tuna-obs": {
"description": "Integração com o plugin Tuna do OBS",
"name": "Tuna OBS"
},
"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",
"menu": {
"align": {
"label": "Alinhamento",
"submenu": {
"left": "Esquerda",
"middle": "Centro",
"right": "Direita"
}
},
"force-hide": "Forçar remoção da guia de vídeo",
"mode": {
"label": "Modo",
"submenu": {
"custom": "Alternar personalizado",
"disabled": "Desabilitado",
"native": "Alternar nativo"
}
}
},
"name": "Botão de Alternar Vídeo",
"templates": {
"button": "Música"
}
},
"visualizer": {
"description": "Adiciona um visualizador ao player",
"menu": {
"visualizer-type": "Tipo de visualizador"
},
"name": "Visualizer"
}
}
}

690
src/i18n/resources/ro.json Normal file
View File

@ -0,0 +1,690 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Nu s-a reusit executarea plugin-ului {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin-ul {{pluginName}}::{{contextName}} s-a executat in {{ms}} ms",
"initialize-failed": "Initializarea plugin-ului \"{{pluginName}}\" a esuat",
"load-all": "Se incarca toate plugin-urile",
"load-failed": "Esec la incarcarea plugin-ului \"{{pluginName}}\"",
"loaded": "Plugin-ul \"{{pluginName}}\" s-a incarcat",
"unload-failed": "Esec la oprirea plugin-ului \"{{pluginName}}\"",
"unloaded": "Plugin-ul \"{{pluginName}}\" s-a terminat"
}
}
},
"language": {
"code": "ro",
"local-name": "Română",
"name": "Romanian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "S-a terminat incarcarea. Panoul de developer e deschis"
},
"i18n": {
"loaded": "i18n incarcat"
},
"second-instance": {
"receive-command": "Comanda primita prin protocol: \"{{command}}\""
},
"theme": {
"css-file-not-found": "Fisierul CSS \"{{cssFile}}\" nu exista, se ignora"
},
"unresponsive": {
"details": "Eroare, procesul nu raspunde\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Se sterge cache-ul aplicatiei"
},
"window": {
"tried-to-render-offscreen": "Fereastra a incercat sa fie randata in afara ecranului, marimeaFerestrei={{windowSize}}, marimeaEcranului={{displaySize}}, pozitia={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Meniul este ascuns, folositi tasta 'Alt' pentru a-l face sa apara (sau tasta 'Esc' daca folositi meniul din aplicatie)",
"message": "Ascunderea meniului este activata",
"title": "Ascunderea meniului activata"
},
"need-to-restart": {
"buttons": {
"later": "Mai tarziu",
"restart-now": "Reporneste acum"
},
"detail": "Plugin-ul \"{{pluginName}}\" necesita o repornire pentru a intra in efect",
"message": "Pugin-ul \"{{pluginName}}\" trebuie repornit",
"title": "Repornire necesara"
},
"unresponsive": {
"buttons": {
"quit": "Iesi",
"relaunch": "Reporneste",
"wait": "Asteapta"
},
"detail": "Ne cerem scuze pentru incovenient! va rugam alegeti ce doriti sa faceti:",
"message": "Applicatia nu raspunde",
"title": "Fereastra nu raspunde"
},
"update-available": {
"buttons": {
"disable": "Dezactiveaza actualizarile",
"download": "Descarca",
"ok": "OK"
},
"detail": "O noua versiune este disponibila si poate fi descarcata pe {{downloadLink}}",
"message": "O noua versiune este disponibila",
"title": "Actualizare disponibila"
}
},
"menu": {
"about": "Despre",
"navigation": {
"label": "Navigatie",
"submenu": {
"copy-current-url": "Copiaza URL-ul actual",
"go-back": "Mergi inapoi",
"go-forward": "Mergi inainte",
"quit": "Iesi",
"restart": "Reporneste aplicatia"
}
},
"options": {
"label": "Setari",
"submenu": {
"advanced-options": {
"label": "Setari avansate",
"submenu": {
"auto-reset-app-cache": "Reseteaza cache-ul aplicatiei la pornire",
"disable-hardware-acceleration": "Dezactiveaza acceleratia hardware",
"edit-config-json": "Editeaza config,json",
"override-user-agent": "Suprascrie User-Agent-ul",
"restart-on-config-changes": "Reporneste la modificarea configuratiei",
"set-proxy": {
"label": "Seteaza proxy",
"prompt": {
"label": "Introduceti adresa proxy: (lasati liber pentru a dezactiva)",
"placeholder": "Exemplu: SOCKS5://127.0.0.1:9999",
"title": "Seteaza proxy"
}
},
"toggle-dev-tools": "Deschide uneltele de dezvoltator"
}
},
"always-on-top": "Mereu deasupra",
"auto-update": "Actualizare automata",
"hide-menu": {
"dialog": {
"message": "Meniul va fi ascuns la urmatoarea pornire, folositi [Alt] pentru a-l face sa apara (sau ghilimea intoarsa [`] daca folositi meniul applicatiei)",
"title": "Ascunderea meniului pornita"
},
"label": "Ascunde meniul"
},
"language": {
"dialog": {
"message": "Limba va fi schimbata dupa repornire",
"title": "Limba actualizata"
},
"label": "Limba",
"submenu": {
"to-help-translate": "Vrei sa ajuti la traducere? Apasa aici"
}
},
"resume-on-start": "Continua ultimul cantec ascultat cand porneste aplicatia",
"single-instance-lock": "Oprirea deschiderii mai multor instante",
"start-at-login": "Incepe la autentificare",
"starting-page": {
"label": "Pagina de pornire",
"unset": "Deselectat"
},
"tray": {
"label": "Tray",
"submenu": {
"disabled": "Dezactivat",
"enabled-and-hide-app": "Activeaza si ascunde fereastra aplicatiei",
"enabled-and-show-app": "Activeaza si arata fereastra aplicatiei",
"play-pause-on-click": "Start/Pauza la click"
}
},
"visual-tweaks": {
"label": "Optimizari vizuale",
"submenu": {
"like-buttons": {
"default": "Default",
"force-show": "Forteaza randarea",
"hide": "Ascunde",
"label": "Butoane de like"
},
"remove-upgrade-button": "Elimina butonul de upgrade",
"theme": {
"label": "Tema",
"submenu": {
"import-css-file": "Importa fisiere CSS proprii",
"no-theme": "Fara tema"
}
}
}
}
}
},
"plugins": {
"enabled": "Activat",
"label": "Plugins",
"new": "NOU"
},
"view": {
"label": "Aspect",
"submenu": {
"force-reload": "Reimprospatare fortata",
"reload": "Reimprospateaza",
"reset-zoom": "Marimea actuala",
"toggle-fullscreen": "Porneste Full Screen",
"zoom-in": "Mareste",
"zoom-out": "Micsoreaza"
}
}
},
"tray": {
"next": "Urmatorul",
"play-pause": "Reda/Pauza",
"previous": "Anteriorul",
"quit": "Iesi",
"restart": "Reporneste aplicatia",
"show": "Arata fereastra",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "Blocheaza toate reclamele si trackers",
"menu": {
"blocker": "Blocator"
},
"name": "Blocator de reclame"
},
"album-actions": {
"description": "Adauga butoane pentru Undislike, Like si Unlike pentru toate piesele dintr-un playlist sau album",
"name": "Actiuni pentru album"
},
"album-color-theme": {
"description": "Aplica o tema dinamica si efecte vizuale bazate pe paleta de culori a albumului",
"menu": {
"color-mix-ratio": {
"label": "Raportul amestecului de culori",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Tema de culori a albumului"
},
"ambient-mode": {
"description": "Aplica un efect de iluminare, aplicand culori preluate din video pe fundalul ecranului",
"menu": {
"blur-amount": {
"label": "Cantitatea de blur",
"submenu": {
"pixels": "{{blurAmount}} pixeli"
}
},
"buffer": {
"label": "Buffer",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Opacitate",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Calitate",
"submenu": {
"pixels": "{{quality}} pixeli"
}
},
"size": {
"label": "Marime",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Fluenta tranzitiei",
"submenu": {
"during": "In timpul {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Foloseste fullscreen"
}
},
"name": "Mod ambiental"
},
"audio-compressor": {
"description": "Aplica compresie pe audio (scade volumul partilor cele mai sonore si creste volumul partilor mai putin sonore)",
"name": "Compresor audio"
},
"blur-nav-bar": {
"description": "Fa bara de navigare semi-transparenta",
"name": "Bara de naviagtie semi-transparenta"
},
"bypass-age-restrictions": {
"description": "Treci peste verificarea de varsta a YouTube-ului",
"name": "Ignora restrictiile de varsta"
},
"captions-selector": {
"description": "Selector de subtitrari pentru piesele audio de pe YouTube Music",
"menu": {
"autoload": "Selecteaza automat ultima subtitrare folosita",
"disable-captions": "Fara subtitrari by default"
},
"name": "Selector de subtitrari",
"prompt": {
"selector": {
"label": "Limba curenta a subtitrarilor: {{language}}",
"none": "Niciuna",
"title": "Alege limba subtitrarilor"
}
},
"templates": {
"title": "Deschide selectorul de subtitrari"
}
},
"compact-sidebar": {
"description": "Pastreaza bara laterala mereu in modul compact",
"name": "Bara laterala compacta"
},
"crossfade": {
"description": "Tranzitioneaza intre cantece",
"menu": {
"advanced": "Avansat"
},
"name": "Tranzitie [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Durata tranzitie de inceput (ms)",
"fade-out-duration": "Durata tranzitie de sfarsit (ms)",
"fade-scaling": {
"label": "Scala tranzitiei",
"linear": "Linear",
"logarithmic": "Logaritmic"
},
"seconds-before-end": "Tranzitie N secunde inainte de final"
},
"title": "Optiuni de tranzitie"
}
}
},
"disable-autoplay": {
"description": "Fa cantecul sa inceapa in modul \"pauza\"",
"menu": {
"apply-once": "Se aplica doar la pornirea aplicatiei"
},
"name": "Dezactiveaza redarea automata"
},
"discord": {
"backend": {
"already-connected": "S-a incercat conectarea cu o conexiune activa",
"connected": "Conectat la Discord",
"disconnected": "Deconectat de la Discord"
},
"description": "Arata-le prietenilor ce asculti cu Rich Presence",
"menu": {
"auto-reconnect": "Reconectare automata",
"clear-activity": "Sterge activitatea",
"clear-activity-after-timeout": "Sterge activitatea dupa timeout",
"connected": "Conectat",
"disconnected": "Deconectat",
"hide-duration-left": "Ascunde timpul ramas",
"hide-github-button": "Ascunde butonul cu link-ul GitHub",
"play-on-youtube-music": "Reda pe YouTube Music",
"set-inactivity-timeout": "Seteaza intervalul de inactivitate"
},
"name": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "Introduceti perioada de inactivitate dorita in secunde:",
"title": "Seteaza timpul de inactivitate"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "OK"
},
"message": "Argh! Scuze, descarcarea a esuat…",
"title": "Eroare la descarcare!"
},
"start-download-playlist": {
"buttons": {
"ok": "OK"
},
"detail": "({{playlistSize}} cantece)",
"message": "Se descarca Playlist-ul {{playlistTitle}}",
"title": "Descarcarea a inceput"
}
},
"feedback": {
"conversion-progress": "Conversie: {{percent}}%",
"converting": "Se converteste…",
"done": "Descarcat: {{filePath}}",
"download-info": "Se descarca {{artist}} -{{title}} [{{videoId}}",
"download-progress": "Se descarca: {{percent}}%",
"downloading": "Se descarca…",
"downloading-counter": "Se descarca {{current}}/{{total}}…",
"downloading-playlist": "Se descarca playlist-ul \"{{playlistTitle}}\" - {{playlistSize}} piese ({{playlistId}})",
"error-while-downloading": "Eroare la descarcarea piesei \"{{author}} - {{title}}\":{{error}}",
"folder-already-exists": "Folderul {{playlistFolder}} exista deja",
"getting-playlist-info": "Se aduna informatiile despre playlist…",
"loading": "Se incarca…",
"playlist-has-only-one-song": "Playlist-ul are doar un element, acesta va fi descarcat direct",
"playlist-id-not-found": "Niciun ID al playlist-ului nu a fost gasit",
"playlist-is-empty": "Playlist-ul este gol",
"playlist-is-mix-or-private": "Eroare la colectarea informatiilor despre playlist: asigurati-va ca nu este privat sau un playlist \"Mixed for you\"\n\n{{error}}",
"preparing-file": "Se pregateste fisierul…",
"saving": "Se salveaza…",
"trying-to-get-playlist-id": "Se incearca obtinerea ID-ului playlist-ului: {{playlistId}}",
"video-id-not-found": "Video-ul nu a fost gasit",
"writing-id3": "Se scriu tag-urile ID3…"
}
},
"description": "Descarca MP3 / sursa audio direct din interfata",
"menu": {
"choose-download-folder": "Alege folderul de descarcari",
"download-playlist": "Descarca playlist-ul",
"presets": "Setari implicite",
"skip-existing": "Treci peste fisierele existente"
},
"name": "Downloader",
"renderer": {
"can-not-update-progress": "Nu se poate actualiza progresul"
},
"templates": {
"button": "Descarca"
}
},
"exponential-volume": {
"description": "Fa slider-ul de volum exponential pentru a fi mai usor de selectat volumuri reduse.",
"name": "Volum exponential"
},
"in-app-menu": {
"description": "Ofera barelor de meniu un aspect extravagant, intunecat sau de culoarea albumului",
"menu": {
"hide-dom-window-controls": "Ascunde controalele ferestrei DOM"
},
"name": "Meniul aplicatiei"
},
"lumiastream": {
"description": "Adauga asistenta pentru Lumia Stream",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Adauga versuri pentru majoritatea cantecelor",
"menu": {
"romanized-lyrics": "Versuri romantizate"
},
"name": "Lyrics Genius",
"renderer": {
"fetched-lyrics": "Versuri preluate de pe Genius"
}
},
"music-together": {
"description": "Impartaseste playlist-ul cu altii. Cand gazda va pune o piesa, toti ceilalti vor auzi acelasi cantec",
"dialog": {
"enter-host": "Introdu ID-ul host-ului"
},
"internal": {
"save": "Salveaza",
"track-source": "Sursa piesei",
"unknown-user": "Utilizator necunoscut"
},
"menu": {
"click-to-copy-id": "Copiaza ID-ul host-ului",
"close": "Inchide Music Together",
"connected-users": "Utilizatori conectati",
"disconnect": "Deconecteaza Music Together",
"empty-user": "Niciun utilizator conectat",
"host": "Gazda Music Together",
"join": "Alatura-te Music Together",
"permission": {
"all": "Permite invitatilor sa controleze playlist-ul si player-ul",
"host-only": "Doar gazda poate controla playlist-ul si player-ul",
"playlist": "Permite invitatilor controlul asupra playlist-ului"
},
"set-permission": "Schimba controlul permisiunilor",
"status": {
"disconnected": "Deconectat",
"guest": "Conectat ca invitat",
"host": "Conectat ca gazda"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Adaugarea piesei a esuat",
"closed": "Music Together inchis",
"disconnected": "Music Together deconectat",
"host-failed": "Nu s-a reusit gazduirea Music Together",
"id-copied": "ID-ul host-ului a fost copiat in clipboard",
"id-copy-failed": "Eroare la copierea ID-ului host-ului in clipboard",
"join-failed": "Nu s-a reusit alaturarea la Music Together",
"joined": "V-ati alaturat Music Together",
"permission-changed": "Permisiunile Music Together s-au schimbat la \"{{permission}}\"",
"remove-song-failed": "Eroare la indepartarea cantecului",
"user-connected": "{{name}} s-a alaturat la Music Together",
"user-disconnected": "{{name}} a parasit Music Together"
}
},
"navigation": {
"description": "Sagetile pentru Urmatorul/Anteriorul integrate direct in interfata, ca in browser-ul tau preferat",
"name": "Navigatie"
},
"no-google-login": {
"description": "Elimina butonul de autentificare Google si link-urile din interfata",
"name": "Nicio autentificare Google"
},
"notifications": {
"description": "Afiseaza o notificare cand incepe sa cante o piesa (notificarile interactive sunt disponibile pe Windows)",
"menu": {
"interactive": "Notificari interactive",
"interactive-settings": {
"label": "Setari interactive",
"submenu": {
"hide-button-text": "Ascunde textul butoanelor",
"refresh-on-play-pause": "Reimprospateaza la Reda/Pauza",
"tray-controls": "Deschide/Inchide la apasarea icnoitei pentru meniul Tray"
}
},
"priority": "Prioritatea notificarilor",
"toast-style": "Stilul notificarilor",
"unpause-notification": "Arata notificarile la pauza"
},
"name": "Notificari"
},
"picture-in-picture": {
"description": "Permite sa schimbi aplicatie la modul picture-in-picture",
"menu": {
"always-on-top": "Mereu deasupra",
"hotkey": {
"label": "Scurtaturi pe tastatura",
"prompt": {
"keybind-options": {
"hotkey": "Scurtaturi din taste"
},
"label": "Scurtaturi din taste pentru picture-in-picture",
"title": "Scurtatura Picture-in-picture"
}
},
"save-window-position": "Salveaza pozitia ferestrei",
"save-window-size": "Salveaza marimea ferestrei",
"use-native-pip": "Foloseste PiP-ul nativ pentru broswer"
},
"name": "Picture-in-picture",
"templates": {
"button": "Picture-in-picture"
}
},
"playback-speed": {
"description": "Asculta rapid, asculta lent! Adauga un slider pentru viteza de redare a cantecului",
"name": "Viteza de redare",
"templates": {
"button": "Viteza"
}
},
"precise-volume": {
"description": "Controleaza volumul precis folosind rotita mouse-ului/scurtaturi din tastatura, cu un HUD personalizat si incremente de volum personalizate",
"menu": {
"arrows-shortcuts": "Control cu tastele sageti locale",
"custom-volume-steps": "Seteaza incrementele de volum",
"global-shortcuts": "Scurtaturi de tastatura globale"
},
"name": "Volum precis",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Redu volumul audio",
"increase": "Creste volumul audio"
},
"label": "Alege combinatiile de taste globale pentru volumul audio:",
"title": "Combinatii globale de taste pentru volum"
},
"volume-steps": {
"label": "Alege pasii de increment pentru volum audio",
"title": "Incremente de volum"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Calitate actuala: {{quality}}",
"message": "Alegeti calitatea video:",
"title": "Alegeti calitatea video"
}
}
},
"description": "Permite schimbarea calitatii video cu un buton prezent peste video",
"name": "Modificator de calitate video"
},
"scrobbler": {
"description": "Adauga asistenta pentru scrobbling (etc. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Autentificarea cu Last.fm a esuat\nAscunde acest pop-up pana la urmatoarea repornire.",
"title": "Autentificare Esuata"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Setari pentru API-ul Last.fm"
},
"listenbrainz": {
"token": "Introdu token-ul de utilizator ListenBrainz"
},
"scrobble-other-media": "Scrobble alte surse media"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Cheia API Last.fm",
"api-secret": "Secret API Last.fm"
},
"listenbrainz": {
"token": {
"label": "Introdu token-ul tau de utilizator ListenBrainz:",
"title": "Token-ul ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Permite setari globale pentru scurtaturi pe tastatura pentru playback (reda/pauza/urmatorul/anteriorul), pentru oprirea media OSD prin suprascriera tastelor media, pentru folosirea combinatiei Ctrl/CMD + F pentru a cauta, pentru asistenta Linux MPRIS pentru taste media si pentru scurtaturi perosnalizate pentru utilizatori avansati",
"menu": {
"override-media-keys": "Suprascrie tastele media",
"set-keybinds": "Seteaza scurtaturile globale pentru cantece"
},
"name": "Scurtaturi (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Urmatorul",
"play-pause": "Reda / Pauza",
"previous": "Anteriorul"
},
"label": "Alege combinatia de taste globala pentru controlul cantecelor:",
"title": "Scurtaturi pe tastatura globale"
}
}
},
"skip-disliked-songs": {
"description": "Sari peste cantecele disliked",
"name": "Treci peste cantecele disliked"
},
"skip-silences": {
"description": "Treci automat peste sectiunile de liniste din cantece",
"name": "Treci peste liniste"
},
"sponsorblock": {
"description": "Treci automat peste partile non-muzicale precum intro/outro sau parti din video-ul catecului, cand nu se aude cantecul",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Controleaza redarea din Bara de Activitati Windows",
"name": "Control media in Bara de Activitate"
},
"touchbar": {
"description": "Adauga un widget TouchBar pentru utilizatorii macOS",
"name": "TouchBar"
},
"tuna-obs": {
"description": "Integrare cu plugin-ul OBS Tuna",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Adauga un buton ce schimba intre modurile Video/Cantec. se poate optional elimia complet optiunea video",
"menu": {
"align": {
"label": "Aliniere",
"submenu": {
"left": "Stanga",
"middle": "Mijloc",
"right": "Dreapta"
}
},
"force-hide": "Forteaza eliminarea tab-ului video",
"mode": {
"label": "Mod",
"submenu": {
"custom": "Comutatoare personalizate",
"disabled": "Dezactivat",
"native": "Comutatoare native"
}
}
},
"name": "Comutator video",
"templates": {
"button": "Cantec"
}
},
"visualizer": {
"description": "Adauga un visualizer la player",
"menu": {
"visualizer-type": "Tip de visualizer"
},
"name": "Visualizer"
}
}
}

View File

@ -7,7 +7,9 @@
"initialize-failed": "Ошибка инициализации плагина \"{{pluginName}}\"",
"load-all": "Загружаем все плагины",
"load-failed": "Ошибка загрузки плагина \"{{pluginName}}\"",
"loaded": "Плагин \"{{pluginName}}\" загружен"
"loaded": "Плагин \"{{pluginName}}\" загружен",
"unload-failed": "Ошибка выгрузки плагина \"{{pluginName}}\"",
"unloaded": "Плагин \"{{pluginName}}\" выгружен"
}
}
},
@ -17,45 +19,149 @@
"name": "Russian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Загрузка завершена. DevTools открыт"
},
"i18n": {
"loaded": "i18n загружен"
},
"second-instance": {
"receive-command": "Получена команда по протоколу: \"{{command}}\""
},
"theme": {
"css-file-not-found": "CSS файл \"{{cssFile}}\" не существует, игнорирую"
},
"unresponsive": {
"details": "Приложение не отвечает!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Очищаю кеш приложения"
},
"window": {
"tried-to-render-offscreen": "Окно попробовало открыться за пределами экрана, размер окна={{windowSize}}, разрешение экрана={{displaySize}}, местоположение={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Меню скрыто, 'Alt' чтобы показать его ('Escape' если используете внутреннее меню приложения)",
"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": {
"download": "Download",
"disable": "Отключить обновления",
"download": "Скачать",
"ok": "OK"
}
},
"detail": "Новая версия доступна для загрузки на {{downloadLink}}",
"message": "Доступная новая версия",
"title": "Доступно обновление"
}
},
"menu": {
"about": "О приложении",
"navigation": {
"label": "Navigation"
"label": "Навигация",
"submenu": {
"copy-current-url": "Скопировать текущий URL",
"go-back": "Вернуться",
"go-forward": "Вперед",
"quit": "Выйти",
"restart": "Перезапустить приложение"
}
},
"options": {
"label": "Options",
"label": "Настройки",
"submenu": {
"advanced-options": {
"label": "Расширенные настройки",
"submenu": {
"auto-reset-app-cache": "Очищать кеш при запуске приложения",
"disable-hardware-acceleration": "Отключить аппаратное ускорение",
"edit-config-json": "Редактировать config.json",
"override-user-agent": "Переопределить User-Agent",
"restart-on-config-changes": "Перезапускать при изменениях конфига",
"set-proxy": {
"label": "Set proxy",
"label": "Задать прокси",
"prompt": {
"title": "Set proxy"
"label": "Введите прокси адрес (оставьте поле пустым для отключения)",
"placeholder": "Пример: SOCKS5://127.0.0.1:9999",
"title": "Задать прокси"
}
}
},
"toggle-dev-tools": "Включить DevTools"
}
},
"auto-update": "Auto Update",
"start-at-login": "Start at login",
"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": "Tray"
"label": "Трей",
"submenu": {
"disabled": "Отключено",
"enabled-and-hide-app": "Включено и скрывать приложение",
"enabled-and-show-app": "Включено и показывать приложение",
"play-pause-on-click": "Пауза/продолжить при нажатии"
}
},
"visual-tweaks": {
"label": "Визуальные настройки",
"submenu": {
"like-buttons": {
"default": "Default"
"default": "Default",
"force-show": "Всегда показывать",
"hide": "Скрывать",
"label": "Кнопка лайка"
},
"remove-upgrade-button": "Убрать кнопку Youtube Premium",
"theme": {
"label": "Theme",
"label": "Тема",
"submenu": {
"no-theme": "No theme"
"import-css-file": "Импортировать кастомный CSS файл",
"no-theme": "Без темы"
}
}
}
@ -63,10 +169,32 @@
}
},
"plugins": {
"label": "Plugins"
"enabled": "Включено",
"label": "Плагины",
"new": "НОВИНКА"
},
"view": {
"label": "View"
"label": "Вид",
"submenu": {
"force-reload": "Принудительная перезагрузка",
"reload": "Перезагрузить",
"reset-zoom": "Текущий размер",
"toggle-fullscreen": "Включить полноэкранный режим",
"zoom-in": "Приблизить",
"zoom-out": "Отдалить"
}
}
},
"tray": {
"next": "Следующий",
"play-pause": "Пауза/Продолжить",
"previous": "Предыдущий",
"quit": "Выйти",
"restart": "Перезагрузить приложение",
"show": "Показать окно",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
@ -78,12 +206,24 @@
},
"name": "Блокировщик рекламы"
},
"album-actions": {
"description": "Добавляет кнопки Undislike, Dislike и Unlike, чтобы применять их на все композиции в плейлисте или альбоме",
"name": "Действия с альбомом"
},
"album-color-theme": {
"description": "Применяет динамическую тему и визуальные эффекты на основе цветовой палитры альбома",
"menu": {
"color-mix-ratio": {
"label": "Соотношение цветов",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Цветовая тема альбома"
},
"ambient-mode": {
"description": "Применяет световой эффект, отбрасывая мягкие цвета из видео на задний фон вашего экрана.",
"description": "Применяет световой эффект, отбрасывая мягкие цвета из видео на задний фон вашего экрана",
"menu": {
"blur-amount": {
"label": "Степень размытия",
@ -118,7 +258,7 @@
"smoothness-transition": {
"label": "Плавный переход",
"submenu": {
"during": "В течение {{interpolationTime}}s"
"during": "В течение {{interpolationTime}} s"
}
},
"use-fullscreen": {
@ -141,21 +281,78 @@
},
"captions-selector": {
"description": "Выбор субтитров для аудиотреков в YouTube Music",
"menu": {
"autoload": "Автоматически выбирать последние использованные субтитры",
"disable-captions": "Без субтитров по умолчанию"
},
"name": "Выбор субтитров",
"prompt": {
"selector": {
"none": "None"
"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": {
"linear": "Linear"
}
}
"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": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "Введите таймер неактивности в секундах:",
"title": "Задать таймер неактивности"
}
}
},
@ -166,67 +363,328 @@
"buttons": {
"ok": "OK"
},
"message": "Ой-ой! Прошу простить, загрузка дала сбой…",
"title": "Error in download!"
},
"start-download-playlist": {
"buttons": {
"ok": "OK"
}
},
"detail": "({{playlistSize}} песен)",
"message": "Скачиваем плейлист {{playlistTitle}}",
"title": "Загрузка началась"
}
},
"feedback": {
"download-progress": "Download: {{percent}}%"
"conversion-progress": "Конвертация: {{percent}}%",
"converting": "Конвертация…",
"done": "Выполнено: {{filePath}}",
"download-info": "Скачиваем {{artist}}-{{title}} {{videoId}}",
"download-progress": "Download: {{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": "Пытаемся получить ID плейлиста: {{playlistId}}",
"video-id-not-found": "Видео не найдено",
"writing-id3": "Пишем ID3 теги…"
}
},
"description": "Скачивать MP3 / исходное аудио напрямую из интерфейса",
"menu": {
"choose-download-folder": "Выберите папку для загрузок",
"download-playlist": "Скачать плейлист",
"presets": "Пресеты",
"skip-existing": "Пропускать уже существующие файлы"
},
"name": "Загрузчик",
"renderer": {
"can-not-update-progress": "Невозможно обновить прогресс"
},
"templates": {
"button": "Download"
"button": "Скачать"
}
},
"last-fm": {
"name": "Last.fm"
"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": "Романизированный текст (any -> en)"
},
"name": "Тексты песен от Genius",
"renderer": {
"fetched-lyrics": "Текст от Genius был получен"
}
},
"music-together": {
"description": "Поделитесь плейлистом с другими. Когда хост играет песню, все остальные слышат ту же песню",
"dialog": {
"enter-host": "Введите ID хоста"
},
"internal": {
"save": "Сохранить",
"track-source": "Источник трека",
"unknown-user": "Неизвестный пользователь"
},
"menu": {
"click-to-copy-id": "Копировать ID хоста",
"close": "Закрыть Music Together",
"connected-users": "Подключенные пользователи",
"disconnect": "Отключиться от Music Together",
"empty-user": "Нет подключенных пользователей",
"host": "Хост Music Together",
"join": "Подключиться к Music Together",
"permission": {
"all": "Позволить гостям управлять плейлистом и плеером",
"host-only": "Только хост может управлять плейлистом и плеером",
"playlist": "Позволить гостям управлять плейлистом"
},
"set-permission": "Изменить разрешения на управление разрешениями",
"status": {
"disconnected": "Отключено",
"guest": "Подключен как гость",
"host": "Подключен как хост"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Не удалось добавить песню",
"closed": "Music Together закрыт",
"disconnected": "Music Together отключен",
"host-failed": "Не удалось запустить Music Together",
"id-copied": "ID хоста скопирован в буфер обмена",
"id-copy-failed": "Не удалось скопировать айди хоста в буфер обмена",
"join-failed": "Не удалось присоединиться к Music Together",
"joined": "Присоединился к Music Together",
"permission-changed": "Разрешения Music Together изменены на \"{{permission}}\"",
"remove-song-failed": "Не удалось удалить песню",
"user-connected": "{{name}} присоединился к Music Together",
"user-disconnected": "{{name}} отключился от Music Together"
}
},
"navigation": {
"name": "Navigation"
"description": "Стрелки навигации \"вперед/назад\" интегрированы в интерфейс, как в вашем любимом браузере",
"name": "Навигация"
},
"no-google-login": {
"name": "No Google Login"
"description": "Убрать из интерфейса кнопки и ссылки для входа через Google",
"name": "Нет входа в систему Google"
},
"notifications": {
"name": "Notifications"
"description": "Показывать уведомления о начале воспроизведения песни (интерактивные уведомления доступны в Windows)",
"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": "Использовать нативный 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": "Добавьте поддержку скробблинга (например, last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Не удалось войти с помощью Last.fm\nСкрыть сообщение до следующего запуска",
"title": "Ошибка аунтефикации"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Настройки API Last.fm"
},
"listenbrainz": {
"token": "Введите токен пользователя ListenBrainz"
},
"scrobble-other-media": "Скробблинг других медиа"
},
"name": "Скробблер",
"prompt": {
"lastfm": {
"api-key": "Ключ API Last.fm",
"api-secret": "Секрет API Last.fm"
},
"listenbrainz": {
"token": {
"label": "Введите токен пользователя ListenBrainz:",
"title": "Токен ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Позволяет задать глобальные горячие клавиши для воспроизведения (play/pause/next/previous) и отключить экранное мультимедийное меню, изменяя мультимедийные клавиши, также включает Ctrl/CMD + F для поиска, добавляет поддержку Linux MPRIS для мультимедийных клавиш, а также пользовательские горячие клавиши для опытных пользователей",
"menu": {
"override-media-keys": "Переопределение мультимедийных клавиш",
"set-keybinds": "Настройка глобальных элементов управления песней"
},
"name": "Ярлыки (и MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Next"
}
"next": "Следующая",
"play-pause": "Воспроизведение / Пауза",
"previous": "Предыдущая"
},
"label": "Выберите глобальные привязки клавиш для управления песнями:",
"title": "Глобальные привязки клавиш"
}
}
},
"skip-disliked-songs": {
"description": "Пропускает непонравившиеся песни",
"name": "Пропустить непонравившиеся песни"
},
"skip-silences": {
"description": "Автоматически пропускает тихие моменты в песнях",
"name": "Пропустить тишину"
},
"sponsorblock": {
"description": "Автоматически пропускает не музыкальные фрагменты, например интро/аутро или фрагменты музыкальных клипов, в которых песня не звучит (тишина)",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Управляйте воспроизведением с панели задач Windows",
"name": "Управление мультимедиа на панели задач"
},
"touchbar": {
"name": "TouchBar"
"description": "Добавляет виджет тачбара для пользователей macOS",
"name": "Тачбар"
},
"tuna-obs": {
"description": "Интеграция с плагином Tuna от OBS",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Добавляет кнопку для переключения между режимами видео и песни. Также можно удалить всю вкладку с видео",
"menu": {
"align": {
"label": "Выравнивание",
"submenu": {
"middle": "Middle",
"right": "Right"
"left": "Слева",
"middle": "По центру",
"right": "Справа"
}
},
"force-hide": "Принудительное скрыть видео",
"mode": {
"label": "Mode"
"label": "Режим",
"submenu": {
"custom": "Кастомный переключатель",
"disabled": "Отключен",
"native": "Стандартный переключатель"
}
}
},
"name": "Переключатель видео",
"templates": {
"button": "Song"
"button": "Песня"
}
},
"visualizer": {
"description": "Заменяет обложку визуализатором музыки",
"menu": {
"visualizer-type": "Вид визуализации"
},
"name": "Визуалайзер"
}
}
}

479
src/i18n/resources/th.json Normal file
View File

@ -0,0 +1,479 @@
{
"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": "th",
"local-name": "ภาษาไทย",
"name": "Thai"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "การโหลดเสร็จสิ้น. โหมดนักพัฒนาสามรถใช้งานได้แล้ว"
},
"i18n": {
"loaded": "โหลด i18n แล้ว"
},
"second-instance": {
"receive-command": "รับคำสั่งผ่านโปรโตคอล: \"{{command}}\""
},
"theme": {
"css-file-not-found": "ไม่พบไฟล์ CSS \"{{cssFile}}\" กำลังข้าม"
},
"unresponsive": {
"details": "พบข้อผิดพลาด!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "กำลังล้างแคชแอป"
},
"window": {
"tried-to-render-offscreen": "หน้าต่างพยายามแสดงผลเกินขนาดหน้าจอ windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "เมนูถูกซ่อนไว้ กด'Alt' เพื่อแสดงเมนู (หรือ 'Escape' หากอยู่ในเมนูแอป)",
"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": "คัดลอก 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": "แทนที่ User-Agent",
"restart-on-config-changes": "รีสตาร์ทเมื่อมีการเปลี่ยนแปลงคอนฟิก",
"set-proxy": {
"label": "ตั้งค่าพร็อกซี่",
"prompt": {
"label": "ใส่ที่อยู่พร็อกซี่: (ปล่อยให้ว่างเพื่อปิดใช้งาน)",
"placeholder": "ตัวอย่าง: SOCKS5://127.0.0.1:9999",
"title": "ตั้งค่าพร็อกซี่"
}
},
"toggle-dev-tools": "เปิด-ปิด DevTools"
}
},
"always-on-top": "อยู่ด้านบนตลอดเวลา",
"auto-update": "อัปเดตอัตโนมัติ",
"hide-menu": {
"dialog": {
"message": "เมนูจะถูกซ่อนในการเปิดครั้งถัดไป กด [Alt] เพื่อแสดงเมนู (หรือใช้ backtick [`] หากอยู่ในเมนูแอป)",
"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": {
"label": "ธีม",
"submenu": {
"import-css-file": "นำเข้าไฟล์ CSS ที่กำหนดเอง",
"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": "ยูทูปมิวสิค: {{artist}} - {{title}}"
}
}
},
"plugins": {
"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}} วินาที"
}
},
"use-fullscreen": {
"label": "ใช้โหมดเต็มหน้าจอ"
}
},
"name": "โหมดสภาพแวดล้อม"
},
"audio-compressor": {
"description": "ใช้การบีบอัดเสียง (ลดระดับเสียงของส่วนที่ดังที่สุดของสัญญาณและเพิ่มระดับเสียงของส่วนที่เบาที่สุด)",
"name": "เครื่องมือบีบอัดเสียง"
},
"blur-nav-bar": {
"description": "ทำให้แถบนำทางโปร่งแสงและเบลอ",
"name": "เบลอแถบนำทาง"
},
"bypass-age-restrictions": {
"description": "ข้ามการตรวจสอบอายุของยูทูป",
"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": "เชื่อมต่อกับดิสคอร์ดแล้ว",
"disconnected": "ตัดการเชื่อมต่อออกจากดิสคอร์ด"
},
"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": "เล่นบนยูทูปมิวสุค",
"set-inactivity-timeout": "ตั้งระยะเวลาไม่มีกิจกรรม"
},
"name": "Discord Rich Presence",
"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": "ไม่พบ ID เพลย์ลิสต์",
"playlist-is-empty": "เพลย์ลิสต์ว่างเปล่า",
"playlist-is-mix-or-private": "เกิดข้อผิดพลาดในการรับข้อมูลเพลย์ลิสต์: ตรวจสอบให้แน่ใจว่าไม่ใช่เพลย์ลิสต์ส่วนตัวหรือเพลย์ลิสต์ \"มิกซ์สำหรับคุณ\"\n\n{{error}}",
"preparing-file": "กำลังเตรียมไฟล์…",
"saving": "กำลังบันทึก…",
"trying-to-get-playlist-id": "กำลังพยายามรับ ID เพลย์ลิสต์: {{playlistId}}",
"video-id-not-found": "ไม่พบวิดีโอ",
"writing-id3": "กำลังเขียนแท็ก ID3…"
}
},
"description": "ดาวน์โหลด MP3 / เสียงต้นฉบับโดยตรงจากอินเทอร์เฟซ",
"menu": {
"choose-download-folder": "เลือกโฟลเดอร์ดาวน์โหลด",
"download-playlist": "ดาวน์โหลดเพลย์ลิสต์",
"presets": "พรีเซ็ต",
"skip-existing": "ข้ามไฟล์ที่มีอยู่แล้ว"
},
"name": "ตัวดาวน์โหลด",
"renderer": {
"can-not-update-progress": "ไม่สามารถอัปเดตความคืบหน้าได้"
},
"templates": {
"button": "ดาวน์โหลด"
}
},
"exponential-volume": {
"description": "ทำให้ตัวเลือกความดังมีลักษณะเอ็กซ์โปเนนเชียล เพื่อให้ง่ายต่อการเลือกระดับความดังที่ต่ำลง",
"name": "ระดับเสียงแบบเอ็กซโปเนนเชียล"
},
"in-app-menu": {
"description": "ให้เมนูบาร์ดูทันสมัย มืดหรือเป็นสีของอัลบั้มอย่างน่าสนใจ",
"menu": {
"hide-dom-window-controls": "ซ่อนตัวควบคุมหน้าต่าง DOM"
},
"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": "ปิด Music Together",
"connected-users": "ผู้ใช้ที่เชื่อมต่อ",
"disconnect": "ตัดการเชื่อมต่อ Music Together",
"empty-user": "ไม่มีผู้ใช้ที่เชื่อมต่อ",
"host": "โฮสต์ Music Together",
"join": "เข้าร่วม Music Together",
"permission": {
"all": "อนุญาตให้แขกควบคุมเพลย์ลิสต์และเครื่องเล่น",
"host-only": "เฉพาะโฮสต์เท่านั้นที่สามารถควบคุมเพลย์ลิสต์และเครื่องเล่นได้",
"playlist": "อนุญาตให้แขกควบคุมเพลย์ลิสต์"
},
"set-permission": "เปลี่ยนการอนุญาตในการควบคุม",
"status": {
"disconnected": "ตัดการเชื่อมต่อแล้ว",
"guest": "เชื่อมต่อเป็นแขก",
"host": "เชื่อมต่อเป็นโฮสต์"
}
},
"name": "Music Together [เบต้า]",
"toast": {
"add-song-failed": "เพิ่มเพลงล้มเหลว",
"closed": "ปิด Music Together แล้ว"
}
}
}
}

View File

@ -1,58 +1,166 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "{{pluginName}}::{{contextName}} eklentisi çalıştırılamadı",
"executed-at-ms": "{{pluginName}}::{{contextName}} eklentisi {{ms}}ms'de çalıştırıldı",
"initialize-failed": "\"{{pluginName}}\" eklentisi başlatılamadı",
"load-all": "Tüm eklentiler yükleniyor",
"load-failed": "\"{{pluginName}}\" eklentisi yüklenemedi",
"loaded": "\"{{pluginName}}\" eklentisi yüklendi",
"unload-failed": "\"{{pluginName}}\" eklentisi çıkartılamadı",
"unloaded": "\"{{pluginName}}\" eklentisi çıkartıldı"
}
}
},
"language": {
"code": "tr",
"local-name": "Türkçe",
"name": "Turkish"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Yükleme tamamlandı. Geliştirici araçlarııldı"
},
"i18n": {
"loaded": "i18n yüklendi"
},
"second-instance": {
"receive-command": "Protokol üzerinden alınan komut: \"{{command}}\""
},
"theme": {
"css-file-not-found": "\"{{cssFile}}\" adlı CSS dosyası bulunamadı, yok sayılıyor"
},
"unresponsive": {
"details": "Yanıt verilmedi!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Uygulama ön belleği temizleme"
},
"window": {
"tried-to-render-offscreen": "Pencere ekranın dışında oluşturulmaya çalışıldı, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"message": "Gizli menüyü etkinleştir"
"detail": "Menü gizli, göstermek için 'Alt' tuşunu kullanın (veya Uygulama İçi Menüyü kullanıyorsanız 'Escape' tuşunu kullanın)",
"message": "Menüyü gizle etkinleştirildi",
"title": "Menüyü gizle etkinleştirildi"
},
"need-to-restart": {
"buttons": {
"later": "Daha Sonra",
"restart-now": "Şimdi yeniden başlat"
},
"detail": "\"{{pluginName}}\" eklentisinin çalışabilmesi için yeniden başlatman gerekiyor",
"message": "\"{{pluginName}}\" için yeniden başlatman gerekiyor",
"title": "Uygulamayı yeniden başlatman gerekiyor"
},
"unresponsive": {
"buttons": {
"quit": ıkış",
"relaunch": "Tekrar Başlat",
"wait": "Bekle"
},
"detail": "Rahatsızlık için özür dileriz! Lütfen ne yapacağınızı seçin:",
"message": "Uygulama yanıt vermiyor",
"title": "Pencere yanıt vermiyor"
},
"update-available": {
"buttons": {
"disable": "Güncellemeleri devre dışı bırak",
"download": "İndir",
"ok": "Tamam"
}
},
"detail": "Yeni bir sürüm mevcut. {{downloadLink}} adresi üzerinden indirebilirsin",
"message": "Yeni bir sürüm mevcut",
"title": "Güncelleme Mevcut"
}
},
"menu": {
"about": "Hakkında",
"navigation": {
"label": "Navigasyon"
"label": "Navigasyon",
"submenu": {
"copy-current-url": "Geçerli Url'yi kopyala",
"go-back": "Geri dön",
"go-forward": "İlerle",
"quit": ıkış",
"restart": "Uygulamayı Yeniden Başlat"
}
},
"options": {
"label": "Seçenekler",
"submenu": {
"advanced-options": {
"label": "Gelişmiş Seçenekler",
"submenu": {
"auto-reset-app-cache": "Uygulama başlatıldığında uygulama önbelleğini sıfırla",
"disable-hardware-acceleration": "Donanım hızlandırmayı devre dışı bırak",
"edit-config-json": "Düzenle config.json",
"override-user-agent": "\"User-Agent \"ı geçersiz kıl",
"restart-on-config-changes": "Yapılandırma değişikliğinde yeniden başlat",
"set-proxy": {
"label": "Proxy ayarla",
"prompt": {
"label": "Proxy Adresini Gir: (devre dışı bırakmak için boş bırakın)",
"placeholder": "Örnek: SOCKS5://127.0.0.1:9999",
"title": "Proxy ayarla"
}
}
},
"toggle-dev-tools": "DevTools'u Aç / Kapat"
}
},
"always-on-top": "Her zaman üstte",
"auto-update": "Otomatik Güncelleme",
"language": {
"label": "Dil"
"hide-menu": {
"dialog": {
"message": "Menü bir sonraki açılışta gizlenecektir, göstermek için [Alt] tuşunu kullanın (veya uygulama-içi-menü kullanıyorsanız [`] tuşuna geri basın)",
"title": "Gizli Menü Aktif"
},
"label": "Gizli Menü"
},
"language": {
"dialog": {
"message": "Dil değişikliği yeniden başlattıktan sonra etkinleşecektir",
"title": "Dil değiştirildi"
},
"label": "Dil",
"submenu": {
"to-help-translate": "Çeviriye yardım etmek ister misiniz? Buraya tıklayın"
}
},
"resume-on-start": "Uygulama başlatıldığında son şarkıyı devam ettir",
"single-instance-lock": "Tek Örnek Kilidi",
"start-at-login": "Başlangıçta çalıştır",
"starting-page": {
"label": "Başlangıç sayfası",
"unset": "Ayarlanmadı"
},
"tray": {
"label": "Tepsi",
"submenu": {
"enabled-and-hide-app": "Uygulamayı etkinleştirin gizleyin.",
"play-pause-on-click": "Tıklaynınca Oynat-Duraklat"
"disabled": "Devre Dışı",
"enabled-and-hide-app": "Uygulamayı etkinleştirin gizleyin",
"enabled-and-show-app": "Etkinleştir ve uygulamayı göster",
"play-pause-on-click": "Tıklandığında Oynat/Duraklat"
}
},
"visual-tweaks": {
"label": "Görsel İnce Ayarlar",
"submenu": {
"like-buttons": {
"default": "Varsayılan"
"default": "Varsayılan",
"force-show": "Zorla göster",
"hide": "Gizle",
"label": "Beğenme düğmeleri"
},
"remove-upgrade-button": "Yükseltme düğmesini kaldır",
"theme": {
"label": "Tema",
"submenu": {
"import-css-file": "Özel CSS dosyanı içeri aktar",
"no-theme": "Tema Yok"
}
}
@ -61,10 +169,32 @@
}
},
"plugins": {
"label": "Eklentiler"
"enabled": "Aktif",
"label": "Eklentiler",
"new": "YENİ"
},
"view": {
"label": "Görüntü"
"label": "Görüntü",
"submenu": {
"force-reload": "Zorla yeniden başlat",
"reload": "Yeniden Başlat",
"reset-zoom": "Asıl Boyut",
"toggle-fullscreen": "Tam Ekran'a Geçiş",
"zoom-in": "Yakınlaştır",
"zoom-out": "Uzaklaştır"
}
}
},
"tray": {
"next": "Sonraki",
"play-pause": "Oynat/Durdur",
"previous": "Önceki",
"quit": ıkış",
"restart": "Yeniden başlat",
"show": "Pencereyi görüntüle",
"tooltip": {
"default": "YouTube Müzik",
"with-song-info": "YouTube Müzik: {{artist}} - {{title}}"
}
}
},
@ -72,20 +202,33 @@
"adblocker": {
"description": "Tüm reklamları ve izleyicileri engelle",
"menu": {
"blocker": "Engelleme Yöntemi"
"blocker": "Engelleyici"
},
"name": "Adblocker"
"name": "Reklam Engelleyici"
},
"album-actions": {
"description": "Çalma listesindeki veya albümdeki tüm şarkılara Beğendim ve Beğenmedim düğmeleri ekler",
"name": "Albüm Eylemleri"
},
"album-color-theme": {
"description": "Albümün renk paletine dayalı dinamik bir tema ve efektler uygular.",
"description": "Albümün renk paletine dayalı dinamik bir tema ve efektler uygular",
"menu": {
"color-mix-ratio": {
"label": "Renk karışım oranı",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Albüm Renk Teması"
},
"ambient-mode": {
"description": "Videodaki yumuşak renkleri ekranınızın arka planına yansıtarak bir ışık efekti uygular..",
"description": "Videodaki yumuşak renkleri ekranınızın arka planına yansıtarak bir ışık efekti uygular",
"menu": {
"blur-amount": {
"label": "Bulanıklık miktarı",
"submenu": {
"pixels": "{{blurAmount}} pixels"
"pixels": "{{blurAmount}} piksel"
}
},
"buffer": {
@ -101,53 +244,82 @@
}
},
"quality": {
"label": "Kalite",
"submenu": {
"pixels": "{{quality}} pixels"
"pixels": "{{quality}} piksel"
}
},
"size": {
"label": "Boyut",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Yumuşak Geçiş",
"submenu": {
"during": "{{interpolationTime}} saniye içinde"
"during": "{{interpolationTime}} saniye boyunca"
}
},
"use-fullscreen": {
"label": "Tam ekran kullanılıyor"
}
}
},
"name": "Ambiyans Modu"
},
"audio-compressor": {
"description": "Ses sıkıştırma (dalganın en gürültülü bölümlerinin ses düzeyini azaltır ve daha yumuşak bölümlerin ses düzeyini artırır)"
"description": "Ses sıkıştırma (dalganın en gürültülü bölümlerinin ses düzeyini azaltır ve daha yumuşak bölümlerin ses düzeyini artırır)",
"name": "Ses Sıkıştırma"
},
"blur-nav-bar": {
"description": "Gezinme çubuğunu şeffaf ve bulanık yapar"
"description": "Gezinme çubuğunu şeffaf ve bulanık yapar",
"name": "Navigasyon barını bulanıklaştır"
},
"bypass-age-restrictions": {
"description": "YouTube yaş doğrulamasını atla"
"description": "YouTube yaş doğrulamasını atla",
"name": "Yaş doğrulamasını atla"
},
"captions-selector": {
"description": "YouTube Music için altyazı seçici",
"menu": {
"autoload": "Son kullanılan altyazıyı otomatik olarak seç",
"disable-captions": "Varsayılan olarak altyazı yok"
},
"name": "Altyazı Seçici",
"prompt": {
"selector": {
"none": "Hiçbiri"
"label": "Geçerli altyazı dili: {{language}}",
"none": "Hiçbiri",
"title": "Altyazı dilini seç"
}
},
"templates": {
"title": "Altyazı seçiciyi aç"
}
},
"compact-sidebar": {
"description": "Her zaman kompakt kenar çubugu"
"description": "Her zaman kompakt kenar çubugu",
"name": "Kompakt Kenar Çubuğu"
},
"crossfade": {
"description": "Şarkılar arasında Çapraz Geçiş",
"menu": {
"advanced": "İleri düzey için"
"advanced": "Gelişmiş"
},
"name": "Çapraz Geçiş [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Güçlenme süresi (ms)",
"fade-out-duration": "Zayıflama süresi (ms)",
"fade-scaling": {
"label": "Zayıflama Ölçeği",
"linear": "Doğrusal",
"logarithmic": "Logaritmik"
}
}
},
"seconds-before-end": "Bitişten N saniye önce çapraz geçiş"
},
"title": "Çapraz Geçiş ayarları"
}
}
},
@ -155,14 +327,33 @@
"description": "Şarkıların otomatik olarak duraklatılmasını sağlar",
"menu": {
"apply-once": "Yalnızca ilk şarkı için geçerlidir"
}
},
"name": "Otomatik oynatmayı devre dışı bırak"
},
"discord": {
"description": "Rich Presence ile Discord'da ne dinlediğinizi gösterin.",
"backend": {
"already-connected": "Aktif bağlantı olduğu halde bağlantı kurulmaya çalışıldı",
"connected": "Discord'a bağlandı",
"disconnected": "Discord ile bağlantı kesildi"
},
"description": "Rich Presence ile Discord'da ne dinlediğinizi gösterin",
"menu": {
"auto-reconnect": "Otomatik yeniden bağlan",
"clear-activity": "Etkinliği temizle",
"clear-activity-after-timeout": "Zaman aşımından sonra etkinliği temizle",
"connected": "Bağlı",
"disconnected": "Bağlantı kesildi",
"hide-duration-left": "Kalan süreyi gizle",
"hide-github-button": "GitHub bağlantısını gizle",
"play-on-youtube-music": "YouTube Music de oynat",
"set-inactivity-timeout": "Hareketsizlik zaman aşımını ayarla"
},
"name": "Discord Etkinlik Durumu",
"prompt": {
"set-inactivity-timeout": {
"label": "Hareketsizlik zaman aşımını saniye cinsinden girin:",
"title": "Hareketsizlik zaman aşımını ayarla"
}
}
},
"downloader": {
@ -172,71 +363,328 @@
"buttons": {
"ok": "Tamam"
},
"title": "İndirmede hata meydana geldi!"
"message": "Argh! Özür dilerim, indirme başarısız oldu…",
"title": "İndirme sırasında bir hata meydana geldi!"
},
"start-download-playlist": {
"buttons": {
"ok": "Tamam"
},
"message": "Çalma listesini indir : {{playlistTitle}}",
"detail": "({{playlistSize}} şarkı)",
"message": "Oynatma listesini indir : {{playlistTitle}}",
"title": "İndirme Başladı"
}
},
"feedback": {
"conversion-progress": "Dönüştürme : {{percent}}%",
"converting": "Dönüştürülüyor…",
"done": "Tamamlandı: {{filePath}}",
"download-info": "{{artist}} - {{title}} [{{videoId}} indiriliyor",
"download-progress": "İndirme : {{percent}}%",
"preparing-file": "Dosya Hazırlanıyor…"
"downloading": "İndiriliyor…",
"downloading-counter": "İndiriliyor {{current}}/{{total}}…",
"downloading-playlist": "\"{{playlistTitle}}\" şarkı listesi indiriliyor - {{playlistSize}} şarkı ({{playlistId}})",
"error-while-downloading": "\"{{author}} - {{title}}\" indirilirken hata oluştu: {{error}}",
"folder-already-exists": "{{playlistFolder}} klasörü zaten mevcut",
"getting-playlist-info": "Oynatma listesi bilgisi alınıyor…",
"loading": "Yükleniyor…",
"playlist-has-only-one-song": "Oynatma listesinde yalnızca bir şarkı var, doğrudan indiriliyor",
"playlist-id-not-found": "Oynatma listesi ID'si bulunamadı",
"playlist-is-empty": "Oynatma listesi boş",
"playlist-is-mix-or-private": "Çalma listesi bilgisi alınırken hata oluştu: özel veya \"Size özel karışık\" bir çalma listesi olmadığından emin olun\n\n{{error}}",
"preparing-file": "Dosya Hazırlanıyor…",
"saving": "Kaydediliyor…",
"trying-to-get-playlist-id": "Çalma listesi ID'si alınmaya çalışılıyor: {{playlistId}}",
"video-id-not-found": "Video bulunamadı",
"writing-id3": "ID3 etiketleri yazılıyor…"
}
},
"description": "MP3 / kaynak sesini doğrudan arayüzden indir",
"menu": {
"choose-download-folder": "İndirme klasörünü seç",
"download-playlist": "Oynatma listesini indir",
"presets": "Hazır Ayarlar",
"skip-existing": "Mevcut dosyaları atla"
},
"name": "İndirici",
"renderer": {
"can-not-update-progress": "İlerleme güncellenemiyor"
},
"templates": {
"button": "İndir"
}
},
"last-fm": {
"name": "Last.fm"
"exponential-volume": {
"description": "Ses seviyesi kaydırıcısını üstel hale getirir, böylece daha düşük ses seviyelerini seçmek daha kolay olur.",
"name": "Üstel Ses Seviyesi"
},
"in-app-menu": {
"description": "Menü çubuklarına süslü, koyu veya albüm renginde bir görünüm verir",
"menu": {
"hide-dom-window-controls": "DOM penceresi kontrollerini gizle"
},
"name": "Uygulama İçi Menü"
},
"lumiastream": {
"description": "Lumia Stream desteği ekler",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Çoğu şarkı için şarkı sözü desteği ekler",
"menu": {
"romanized-lyrics": "Romanlaştırılmış Şarkı Sözleri"
},
"name": "Genius Şarkı Sözleri",
"renderer": {
"fetched-lyrics": "Şarkı sözleri genius tarafından alındı"
}
},
"music-together": {
"description": "Oynatma listesini başkalarıyla paylaşın. Sunucu sahibi bir şarkı çaldığında, diğer herkes aynı şarkıyı duyacak",
"dialog": {
"enter-host": "Sunucu ID'si Girin"
},
"internal": {
"save": "Kaydet",
"track-source": "Parça Kaynağı",
"unknown-user": "Bilinmeyen Kullanıcı"
},
"menu": {
"click-to-copy-id": "Sunucu ID'sini kopyala",
"close": "Birlikte Müziği Kapat",
"connected-users": "Bağlanan Kullanıcılar",
"disconnect": "Birlikte Müzik Bağlantısını Kesin",
"empty-user": "Bağlı kullanıcı bulunmuyor",
"host": "Birlikte Müzik Sunucusu",
"join": "Birlikte Müziğe Katıl",
"permission": {
"all": "Konukların oynatma listesini ve oynatıcıyı kontrol etmesine izin ver",
"host-only": "Çalma listesini ve oynatıcıyı yalnızca yönetici kontrol edebilir",
"playlist": "Konukların oynatma listesini kontrol etmesine izin ver"
},
"set-permission": "Kontrol İznini Değiştir",
"status": {
"disconnected": "Bağlantı kesildi",
"guest": "Misafir olarak bağlandı",
"host": "Sunucu Sahibi olarak bağlandı"
}
},
"name": "Birlikte Müzik [Beta]",
"toast": {
"add-song-failed": "Şarkı eklenirken bir hata meydana geldi",
"closed": "Birlikte Müzik kapatıldı",
"disconnected": "Birlikte Müzik bağlantı kesildi",
"host-failed": "Birlikte Müzik sunucusu kurulamadı",
"id-copied": "Sunucu ID'si kopyalandı",
"id-copy-failed": "Sunucu ID'si panoya kopyalanamadı",
"join-failed": "Birlikte Müziğe katılırken bir hata meydana geldi",
"joined": "Birlikte Müziğe Katıldı",
"permission-changed": "Birlikte Müzik yetkisi \"{{permission}}\" olarak değiştirildi",
"remove-song-failed": "Şarkı kaldırılırken bir hata meydana geldi",
"user-connected": "{{name}} Birlikte Müziğe Katıldı",
"user-disconnected": "{{name}} Birlikte Müzik'ten ayrıldı"
}
},
"navigation": {
"description": "Favori tarayıcınızdaki gibi doğrudan arayüze entegre edilmiş İleri/Geri gezinme okları",
"name": "Navigasyon"
},
"no-google-login": {
"description": "Google giriş düğmelerini ve bağlantılarını arayüzden kaldır",
"name": "Google Girişini Kaldır"
},
"notifications": {
"description": "Bir şarkı çalmaya başladığında bir bildirim görüntüler (etkileşimli bildirimler Windows'ta mevcuttur)",
"menu": {
"interactive": "İnteraktif Bildirimler",
"interactive-settings": {
"label": "İnteraktif Ayarlar",
"submenu": {
"hide-button-text": "Buton metnini gizle",
"refresh-on-play-pause": "Oynat/Duraklat'ta Yenile",
"tray-controls": "Tepsi tıklamasıyla Aç/Kapat"
}
},
"priority": "Bildirim Önceliği",
"toast-style": "Bildirim Tarzı",
"unpause-notification": "Şarkı tekrar oynatılınca bildirim göster"
},
"name": "Bildirimler"
},
"shortcuts": {
"picture-in-picture": {
"description": "Uygulamayı resim-içinde-resim moduna geçirmeye izin verir",
"menu": {
"always-on-top": "Her zaman üstte",
"hotkey": {
"label": "Kısayol",
"prompt": {
"keybind-options": {
"hotkey": "Kısayol"
},
"label": "Resim-içinde-resim arasında geçiş yapmak için bir kısayol tuşu seçin",
"title": "Resim-içinde-resim Kısayol Tuşu"
}
},
"save-window-position": "Pencere konumunu kaydet",
"save-window-size": "Pencere boyutunu kaydet",
"use-native-pip": "Tarayıcı yerel PiP'sini kullan"
},
"name": "Resim-içinde-resim",
"templates": {
"button": "Resim-içinde-resim"
}
},
"playback-speed": {
"description": "Hızlı dinle, yavaş dinle! Şarkı hızını kontrol eden bir kaydırıcı ekler",
"name": "Oynatma Hızı",
"templates": {
"button": "Hız"
}
},
"precise-volume": {
"description": "Özel bir HUD ve özelleştirilebilir ses seviyesi adımları ile fare tekerleği / kısayol tuşlarını kullanarak ses seviyesini hassas bir şekilde kontrol edin",
"menu": {
"arrows-shortcuts": "Yerel Ok Tuşu Kontrolleri",
"custom-volume-steps": "Özel Ses Seviyesi Adımlarını Ayarlama",
"global-shortcuts": "Genel Kısayol Tuşları"
},
"name": "Hassas Ses Seviyesi",
"prompt": {
"keybind": {
"global-shortcuts": {
"keybind-options": {
"next": "İler"
"decrease": "Ses Seviyesi Azaltma",
"increase": "Ses Seviyesi Yükseltme"
},
"label": "Genel Ses Tuş Atamalarını seçin:",
"title": "Genel Ses Tuş Atamaları"
},
"volume-steps": {
"label": "Ses Artırma/Azaltma Kademelerini Seçin",
"title": "Ses Kademeleri"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Mevcut Kalite: {{quality}}",
"message": "Video Kalitesini Seçin:",
"title": "Video Kalitesini Seçin"
}
}
},
"description": "Video katmanı üzerindeki bir düğme ile video kalitesinin değiştirilmesine izin verir",
"name": "Video Kalitesi Değiştirici"
},
"scrobbler": {
"description": "Listeleme desteği ekler (lastfm, listenbrainz ve benzeri)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm ile kimlik doğrulaması yapılamadı\nBir sonraki yeniden başlatmaya kadar açılır pencereyi gizle.",
"title": "Kimlik Doğrulama Başarısız"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API Ayarları"
},
"listenbrainz": {
"token": "ListenBrainz kullanıcı kimliğinizi girin"
},
"scrobble-other-media": "Diğer medya ortamlarında listele"
},
"name": "Listeleyici",
"prompt": {
"lastfm": {
"api-key": "Last.fm API anahtarı",
"api-secret": "Last.fm API gizli anahtar"
},
"listenbrainz": {
"token": {
"label": "ListenBrainz kullanıcı kimliğinizi girin:",
"title": "ListenBrainz kimliği"
}
}
}
},
"shortcuts": {
"description": "Oynatma için global kısayol tuşları (oynat/duraklat/sonraki/önceki) ayarlamaya ve medya tuşlarını geçersiz kılarak medya OSD'sini kapatmaya, arama yapmak için Ctrl/CMD + F tuşlarını açmaya, medya tuşları için Linux MPRIS desteğini açmaya ve ileri düzey kullanıcılar için özel kısayol tuşlarına izin verir",
"menu": {
"override-media-keys": "Medya Tuşlarını Geçersiz Kıl",
"set-keybinds": "Global Şarkı Kontrollerini Ayarla"
},
"name": "Kısayollar (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "İler",
"play-pause": "Oynat / Durdur",
"previous": "Önceki"
},
"label": "Şarkı Kontrolü için Genel Tuş Atamaları'nı seçin:",
"title": "Genel Tuş Atamaları"
}
}
},
"skip-disliked-songs": {
"description": "Beğenmediğin şarkıları atlar",
"name": "Beğenmediklerini Atla"
},
"skip-silences": {
"description": "Şarkılardaki sessiz bölümleri otomatik olarak atlar",
"name": "Sessizlikleri Atla"
},
"sponsorblock": {
"description": "Giriş/Çıkış gibi müzik olmayan kısımları veya müzik videolarında şarkının çalmadığı kısımları otomatik olarak atlar",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Windows görev çubuğu üzerinden oynatmayı kontrol edebilmenize olanak sağlar",
"name": "Görev Çubuğu Medya Kontrolü"
},
"touchbar": {
"description": "macOS kullanıcıları için bir TouchBar widget'ı ekler",
"name": "TouchBar"
},
"tuna-obs": {
"description": "OBS eklentisi Tuna ile entegrasyon sağlar",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Video/Şarkı modu arasında geçiş yapmak için bir düğme ekler. ayrıca isteğe bağlı olarak tüm video sekmesini kaldırabilir",
"menu": {
"align": {
"label": "Hizalama",
"submenu": {
"left": "Sol",
"middle": "Orta",
"right": "Sağ"
}
},
"force-hide": "Video sekmesini kaldırmaya zorla",
"mode": {
"label": "Mod"
"label": "Mod",
"submenu": {
"custom": "Özel Ayar",
"disabled": "Devre dışı",
"native": "Yerel geçiş"
}
}
},
"name": "Video Geçiş",
"templates": {
"button": "Şarkı"
}
},
"visualizer": {
"description": "Oynatıcıya bir görselleştirici ekler",
"menu": {
"visualizer-type": "Görselleştirici Tipi"
},
"name": "Görselleştirici"
}
}
}

View File

@ -1,7 +1,690 @@
{
"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": "uk",
"local-name": "Українська",
"name": "Ukrainian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Завантаження завершено. Відкрито DevTools"
},
"i18n": {
"loaded": "i18n завантажено"
},
"second-instance": {
"receive-command": "Отримано команду за протоколом: \"{{command}}\""
},
"theme": {
"css-file-not-found": "Файл CSS \"{{cssFile}}\" не існує, ігноруємо"
},
"unresponsive": {
"details": "Невідповідна помилка!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Очищення кешу програми"
},
"window": {
"tried-to-render-offscreen": "Вікно намагалися відобразитися поза екраном, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Меню приховано, використовуйте \"Alt\", щоб показати його (або \"Escape\", якщо ви використовуєте меню в додатку)",
"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": "Копіювати поточну 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": "Змінити User-Agent",
"restart-on-config-changes": "Перезапуск після зміни конфігурації",
"set-proxy": {
"label": "Задати проксі",
"prompt": {
"label": "Введіть адресу проксі-сервера: (залиште порожнім, щоб вимкнути)",
"placeholder": "Приклад: SOCKS5://127.0.0.1:9999",
"title": "Задати проксі"
}
},
"toggle-dev-tools": "Перемкнути DevTools"
}
},
"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": {
"label": "Тема",
"submenu": {
"import-css-file": "Імпортувати власний CSS файл",
"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": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"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}} с"
}
},
"use-fullscreen": {
"label": "Повноекранний режим"
}
},
"name": "Режим навколишнього середовища"
},
"audio-compressor": {
"description": "Застосувати стиснення аудіо (зменшити гучність найгучніших фрагментів сигналу та збільшити гучність тихих фрагментів)",
"name": "Аудіокомпресор"
},
"blur-nav-bar": {
"description": "Робить панель навігації прозорою та розмитою",
"name": "Розмиття панелі навігації"
},
"bypass-age-restrictions": {
"description": "Обхід перевірки віку на YouTube",
"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": "Тривалість згасання (ms)",
"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": "Активність Discord",
"prompt": {
"set-inactivity-timeout": {
"label": "Введіть тайм-аут бездіяльності в секундах:",
"title": "Встановлення тайм-ауту бездіяльності"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Добре"
},
"message": "Йой! При завантаженні виникла помилка…",
"title": "Помилка при завантаженні!"
},
"start-download-playlist": {
"buttons": {
"ok": "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": "Пишемо ID3-теги…"
}
},
"description": "Завантажує MP3 / джерело аудіо безпосередньо з інтерфейсу",
"menu": {
"choose-download-folder": "Оберіть папку для завантаження",
"download-playlist": "Завантажити плейлист",
"presets": "Попередні налаштування",
"skip-existing": "Пропустити наявні файли"
},
"name": "Завантажувач",
"renderer": {
"can-not-update-progress": "Неможливо оновити прогрес"
},
"templates": {
"button": "Завантажити"
}
},
"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": "Введіть ID хоста"
},
"internal": {
"save": "Зберегти",
"track-source": "Джерело композиції",
"unknown-user": "Невідомий користувач"
},
"menu": {
"click-to-copy-id": "Скопіювати хост ID",
"close": "Вимкнути сумісне прослуховування",
"connected-users": "Підключені користувачі",
"disconnect": "Відключитись від Music Together",
"empty-user": "Немає підключених користувачів",
"host": "Хост Music Together",
"join": "Приєднатися до Music Together",
"permission": {
"all": "Дозволити гостям керувати списком відтворення та плеєром",
"host-only": "Лише хост може керувати списком відтворення та плеєром",
"playlist": "Дозволити гостям керувати списком відтворення"
},
"set-permission": "Змінити дозвіл на керування",
"status": {
"disconnected": "Відключено",
"guest": "Підключено як гість",
"host": "Підключено як хост"
}
},
"name": "Music Together [Бета]",
"toast": {
"add-song-failed": "Не вдалося додати пісню",
"closed": "Music Together закритий",
"disconnected": "Music Together відключено",
"host-failed": "Не вдалося увімкнути Music Together",
"id-copied": "ID хоста скопійовано в буфер обміну",
"id-copy-failed": "Не вдалося скопіювати ID хоста в буфер обміну",
"join-failed": "Не вдалося приєднатися до Music Together",
"joined": "Приєднано до Music Together",
"permission-changed": "Дозвіл Music Together змінено на \"{{permission}}\"",
"remove-song-failed": "Не вдалося видалити пісню",
"user-connected": "{{name}} приєднався до Music Together",
"user-disconnected": "{{name}} вийшов з Music Together"
}
},
"navigation": {
"description": "Стрілки навігації Вперед/Назад безпосередньо інтегровані в інтерфейс, як у вашому браузері, який ви використовуєте",
"name": "Навігація"
},
"no-google-login": {
"description": "Видалити кнопки та посилання для входу через Google з інтерфейсу",
"name": "Без входу в Google"
},
"notifications": {
"description": "Відображати сповіщення, коли пісня починає грати (інтерактивні сповіщення доступні в Windows)",
"menu": {
"interactive": "Інтерактивні сповіщення",
"interactive-settings": {
"label": "Інтерактивні налаштування",
"submenu": {
"hide-button-text": "Сховати текст кнопки",
"refresh-on-play-pause": "Оновлення при відтворенні/паузі",
"tray-controls": "Відкриття/закриття при натисканні на значок в області повідомлень (tray)"
}
},
"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": "Додає підтримку скроблінгу (last.fm, Listenbrainz тощо)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Не вдалося автентифікуватися на Last.fm\nСховати до наступного запуску.",
"title": "Не вдалося автентифікуватися"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Налаштування API Last.fm"
},
"listenbrainz": {
"token": "Ввести токен користувача ListenBrainz"
},
"scrobble-other-media": "Скробилити інші медіа"
},
"name": "Скроблер",
"prompt": {
"lastfm": {
"api-key": "Ключ API Last.fm",
"api-secret": "Секрет API Last.fm"
},
"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"
},
"taskbar-mediacontrol": {
"description": "Керування відтворенням з панелі завдань Windows",
"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": "Візуалізація"
}
}
}

690
src/i18n/resources/vi.json Normal file
View File

@ -0,0 +1,690 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "Lỗi khi bắt đầu phần mở rộng {{pluginName}}::{{contextName}}",
"executed-at-ms": "Phần mở rộng {{pluginName}}::{{contextName}} đã bắt đầu trong {{ms}}ms",
"initialize-failed": "Lỗi khi khởi động phần mở rộng \"{{pluginName}}\"",
"load-all": "Đang tải tất cả phần mở rộng",
"load-failed": "Lỗi khi tải phần mở rộng\"{{pluginName}}\"",
"loaded": "Đã tải phần mở rộng \"{{pluginName}}\"",
"unload-failed": "Lỗi khi hủy tải phần mở rộng \"{{pluginName}}\"",
"unloaded": "Đã hủy tải phần mở rộng \"{{pluginName}}\""
}
}
},
"language": {
"code": "vi",
"local-name": "Tiếng Việt",
"name": "Vietnamese"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Đã tải xong. Đã mở Công cụ dành cho nhà phát triển"
},
"i18n": {
"loaded": "i18n đã được tải"
},
"second-instance": {
"receive-command": "Đã nhận được lệnh qua giao thức: \"{{command}}\""
},
"theme": {
"css-file-not-found": "Tệp tin CSS \"{{cssFile}}\"không tồn tại, đang bỏ qua"
},
"unresponsive": {
"details": "Lỗi không phản hồi!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Xóa bộ nhớ đệm ứng dụng"
},
"window": {
"tried-to-render-offscreen": "Cửa sổ đã cố gắng hiển thị ngoài màn hình, windowSize={{windowSize}}, displaySize={{displaySize}}, location={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menu đã ẩn, ấn phím 'Alt' để hiện menu (hoặc ấn 'Escape' nếu bạn đang bật In-app Menu)",
"message": "Ẩn Menu đã được bật",
"title": "Ẩn Menu đã được bật"
},
"need-to-restart": {
"buttons": {
"later": "Để sau",
"restart-now": "Khởi động lại ngay"
},
"detail": "Tiện ích mở rộng \"{{pluginName}}\" yêu cầu khởi động lại ứng dụng để áp dụng",
"message": "\"{{pluginName}}\" cần khởi động lại",
"title": "Yêu cầu khởi động lại"
},
"unresponsive": {
"buttons": {
"quit": "Thoát",
"relaunch": "Khởi chạy lại",
"wait": "Đợi"
},
"detail": "Chúng tôi xin lỗi về sự bất tiện này! hãy chọn việc cần làm:",
"message": "Ứng dụng không phản hồi",
"title": "Cửa sổ không phản hồi"
},
"update-available": {
"buttons": {
"disable": "Tắt cập nhật",
"download": "Tải xuống",
"ok": "Đồng ý"
},
"detail": "Đã có phiên bản mới hơn, bạn có thể tải xuống tại {{downloadLink}}",
"message": "Đã có phiên bản mới",
"title": "Cập nhật có sẵn"
}
},
"menu": {
"about": "Giới thiệu",
"navigation": {
"label": "Điều hướng",
"submenu": {
"copy-current-url": "Copy URL hiện tại",
"go-back": "Quay lại",
"go-forward": "Tiến về trước",
"quit": "Thoát",
"restart": "Khởi động lại ứng dụng"
}
},
"options": {
"label": "Tùy chọn",
"submenu": {
"advanced-options": {
"label": "Tùy chọn nâng cao",
"submenu": {
"auto-reset-app-cache": "Làm mới bộ nhớ đệm khi khởi động ứng dụng",
"disable-hardware-acceleration": "Vô hiệu hóa tăng tốc phần cứng",
"edit-config-json": "Chỉnh sửa config.json",
"override-user-agent": "Ghi đè User-Agent",
"restart-on-config-changes": "Khởi động lại khi thay đổi cấu hình",
"set-proxy": {
"label": "Cài đặt proxy",
"prompt": {
"label": "Nhập địa chỉ Proxy: (để trống nếu muốn tắt)",
"placeholder": "Ví dụ: SOCKS5://127.0.0.1:9999",
"title": "Cài proxy"
}
},
"toggle-dev-tools": "Bật/tắt DevTools"
}
},
"always-on-top": "Luôn ở trên cùng",
"auto-update": "Tự động cập nhật",
"hide-menu": {
"dialog": {
"message": "Menu sẽ bị ẩn khi ứng dụng được chạy vào lần tới, dùng phím [Alt] để hiện nó (hoặc phím [`] nếu sử dụng in-app-menu)",
"title": "Ẩn Menu đã được bật"
},
"label": "Ẩn Menu"
},
"language": {
"dialog": {
"message": "Ngôn ngữ sẽ được thay đổi sau khi ứng dụng khởi động lại",
"title": "Ngôn ngữ đã thay đổi"
},
"label": "Ngôn ngữ",
"submenu": {
"to-help-translate": "Bạn muốn giúp dịch? Bấm vào đây"
}
},
"resume-on-start": "Tiếp tục bài hát cuối cùng khi ứng dụng khởi động",
"single-instance-lock": "Khóa một trường hợp",
"start-at-login": "Bắt đầu lúc đăng nhập",
"starting-page": {
"label": "Trang bắt đầu",
"unset": "Bỏ thiết đặt"
},
"tray": {
"label": "Khay",
"submenu": {
"disabled": "Vô hiệu hóa",
"enabled-and-hide-app": "Đã bật và ẩn ứng dụng",
"enabled-and-show-app": "Đã bật và hiển thị ứng dụng",
"play-pause-on-click": "Phát/Tạm dừng khi nhấp chuột"
}
},
"visual-tweaks": {
"label": "Tinh chỉnh hình ảnh",
"submenu": {
"like-buttons": {
"default": "Mặc định",
"force-show": "Tập trung hiển thị",
"hide": "Ẩn",
"label": "Nút thích"
},
"remove-upgrade-button": "Xóa nút nâng cấp",
"theme": {
"label": "Chủ đề",
"submenu": {
"import-css-file": "Nhập tệp CSS tùy chỉnh",
"no-theme": "Không có chủ đề"
}
}
}
}
}
},
"plugins": {
"enabled": "Đã bật",
"label": "Trình bổ sung",
"new": "MỚI"
},
"view": {
"label": "Xem",
"submenu": {
"force-reload": "Buộc tải lại",
"reload": "Tải lại",
"reset-zoom": "Kích thước thực",
"toggle-fullscreen": "Bật chế độ toàn màn hình",
"zoom-in": "Phóng to",
"zoom-out": "Thu nhỏ"
}
}
},
"tray": {
"next": "Tiếp theo",
"play-pause": "Phát/Tạm Dừng",
"previous": "Trước",
"quit": "Thoát",
"restart": "Khởi động lại ứng dụng",
"show": "Hiện cửa sổ",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"adblocker": {
"description": "Chặn toàn bộ quảng cáo và trình theo dõi",
"menu": {
"blocker": "Trình chặn"
},
"name": "Chặn quảng cáo"
},
"album-actions": {
"description": "Thêm nút hủy không thích, không thích, thích và không thích để áp dụng cho tất cả danh sách phát hoặc album",
"name": "Tác vụ với album"
},
"album-color-theme": {
"description": "Áp dụng chủ đề động và hiệu ứng hình ảnh dựa trên bảng màu của album",
"menu": {
"color-mix-ratio": {
"label": "Tỉ lệ trộn màu",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Màu nền album"
},
"ambient-mode": {
"description": "Áp dụng hiệu ứng ánh sáng bằng cách truyền các màu nhẹ từ video vào nền màn hình của bạn",
"menu": {
"blur-amount": {
"label": "Lượng mờ",
"submenu": {
"pixels": "{{blurAmount}} điểm ảnh"
}
},
"buffer": {
"label": "Bộ đệm",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Độ mờ",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Chất lượng",
"submenu": {
"pixels": "{{quality}} điểm ảnh"
}
},
"size": {
"label": "Kích thước",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Độ mượt chuyển cảnh",
"submenu": {
"during": "Trong {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Dùng chế độ toàn màn hình"
}
},
"name": "Chế độ Môi trường xung quanh"
},
"audio-compressor": {
"description": "Áp dụng tính năng nén cho âm thanh (giảm âm lượng của phần to nhất của tín hiệu và tăng âm lượng của phần nhỏ nhất)",
"name": "Bộ nén âm thanh"
},
"blur-nav-bar": {
"description": "Làm mờ và trong suốt thanh điều hướng",
"name": "Thanh điều hướng mờ"
},
"bypass-age-restrictions": {
"description": "Bỏ qua xác minh độ tuổi của YouTube",
"name": "Bỏ qua hạn chế độ tuổi"
},
"captions-selector": {
"description": "Bộ lựa chọn phụ đề cho các bài hát trên Youtube Music",
"menu": {
"autoload": "Tự động chọn phụ đề vừa sử dụng",
"disable-captions": "Không có phụ đề đặt làm mặc định"
},
"name": "Bộ lựa chọn phụ đề",
"prompt": {
"selector": {
"label": "Ngôn ngữ phụ đề hiện tại: {{language}}",
"none": "Không có",
"title": "Chọn ngôn ngữ phụ đề"
}
},
"templates": {
"title": "Mở lựa chọn phụ đề"
}
},
"compact-sidebar": {
"description": "Luôn đặt thanh bên cạnh ở chế độ thu gọn",
"name": "Thanh bên thu gọn"
},
"crossfade": {
"description": "Chuyển tiếp giữa các bài hát",
"menu": {
"advanced": "Nâng cao"
},
"name": "Xen kẽ [thử nghiệm]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Xuất hiện mờ dần trong khoảng thời gian (ms)",
"fade-out-duration": "Khoảng thời gian hoát ra mờ dần (ms)",
"fade-scaling": {
"label": "Làm mờ theo tỉ lệ",
"linear": "Trực tuyến",
"logarithmic": "Logarit"
},
"seconds-before-end": "Xen kẽ N giây trước khi kết thúc"
},
"title": "Tùy chọn xen kẽ"
}
}
},
"disable-autoplay": {
"description": "Bắt đầu bài hát khi ở chế độ \"tạm dừng\"",
"menu": {
"apply-once": "Áp dụng khi khởi động"
},
"name": "Tắt tự động phát"
},
"discord": {
"backend": {
"already-connected": "Đã cố gắng kết nối với kết nối khả dụng",
"connected": "Đã kết nối với Discord",
"disconnected": "Đã ngắt kết nối với Discord"
},
"description": "Cho bạn bè của bạn thấy những gì bạn nghe với Rich Presence",
"menu": {
"auto-reconnect": "Tự động kết nối lại",
"clear-activity": "Xoá hoạt động",
"clear-activity-after-timeout": "Xóa hoạt động sau khi hết thời gian chờ",
"connected": "Đã kết nối",
"disconnected": "Đã ngắt kết nối",
"hide-duration-left": "Ẩn thời lượng còn lại",
"hide-github-button": "Ẩn nút liên kết GitHub",
"play-on-youtube-music": "Phát trong Youtube Music",
"set-inactivity-timeout": "Đặt thời gian chờ không hoạt động"
},
"name": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "Nhập thời gian chờ không hoạt động tính bằng giây:",
"title": "Đặt thời gian chờ không hoạt động"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Đồng ý"
},
"message": "Argh! Xin lỗi, tải xuống thất bại…",
"title": "Lỗi khi tải xuống!"
},
"start-download-playlist": {
"buttons": {
"ok": "Đồng ý"
},
"detail": "({{playlistSize}} bài hát)",
"message": "Đang tải danh sách phát {{playlistTitle}}",
"title": "Đã bắt đầu tải xuống"
}
},
"feedback": {
"conversion-progress": "Chuyển đổi: {{percent}}%",
"converting": "Đang chuyển đổi…",
"done": "Đã xong: {{filePath}}",
"download-info": "Đang tải {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Đang tải: {{percent}}%",
"downloading": "Đang tải…",
"downloading-counter": "Đang tải {{current}}/{{total}}…",
"downloading-playlist": "Đang tải danh sách phát \"{{playlistTitle}}\" - {{playlistSize}} bài hát ({{playlistId}})",
"error-while-downloading": "Lỗi tải xuống \"{{author}} - {{title}}\": {{error}}",
"folder-already-exists": "Thư mục {{playlistFolder}} đã tồn tại",
"getting-playlist-info": "Đang lấy thông tin danh sách phát…",
"loading": "Đang tải…",
"playlist-has-only-one-song": "Danh sách phát chỉ có một mục, tải trực tiếp",
"playlist-id-not-found": "Không tìm thấy ID danh sách phát",
"playlist-is-empty": "Danh sách phát trống",
"playlist-is-mix-or-private": "Lỗi lấy thông tin danh sách phát: đảm bảo danh sách phát không ở chế độ riêng tư hoặc là danh sách phát \"Dành cho bạn\"\n\n{{error}}",
"preparing-file": "Đang chuẩn bị thư mục…",
"saving": "Đang lưu…",
"trying-to-get-playlist-id": "Đang lấy ID danh sách phát: {{playlistId}}",
"video-id-not-found": "Không tìm thấy video",
"writing-id3": "Đang ghi thẻ ID3…"
}
},
"description": "Tải xuống MP3 / âm thanh nguồn trực tiếp từ giao diện",
"menu": {
"choose-download-folder": "Chọn thư mục tải xuống",
"download-playlist": "Tải danh sách phát",
"presets": "Cài đặt sẵn",
"skip-existing": "Bỏ qua các tập tin hiện có"
},
"name": "Trình tải xuống",
"renderer": {
"can-not-update-progress": "Không thể cập nhật tiến độ"
},
"templates": {
"button": "Tải xuống"
}
},
"exponential-volume": {
"description": "Làm cho thanh trượt âm lượng theo cấp số nhân để dễ dàng chọn âm lượng thấp hơn.",
"name": "Âm lượng theo cấp số nhân"
},
"in-app-menu": {
"description": "Mang lại cho thanh menu một giao diện lạ mắt, tối màu hoặc màu album",
"menu": {
"hide-dom-window-controls": "Ẩn cửa sổ điều khiển DOM"
},
"name": "Menu trong ứng dụng"
},
"lumiastream": {
"description": "Thêm hỗ trợ Lumia Stream",
"name": "Lumia Stream [Thử nghiệm]"
},
"lyrics-genius": {
"description": "Thêm hỗ trợ lời bài hát cho hầu hết các bài hát",
"menu": {
"romanized-lyrics": "Lời bài hát La Mã"
},
"name": "Lời bài hát từ Genius",
"renderer": {
"fetched-lyrics": "Lời bài hát được tìm nạp cho Genius"
}
},
"music-together": {
"description": "Chia sẻ danh sách phát với người khác. Khi máy chủ phát một bài hát, những người khác cũng sẽ nghe bài hát đó",
"dialog": {
"enter-host": "Nhập ID máy chủ"
},
"internal": {
"save": "Lưu",
"track-source": "Nguồn âm thanh",
"unknown-user": "Người dùng không rõ"
},
"menu": {
"click-to-copy-id": "Sao chép ID máy chủ",
"close": "Đóng Music Together",
"connected-users": "Người dùng đã kết nối",
"disconnect": "Ngắt kết nối Music Together",
"empty-user": "Không có người dùng đã kết nối",
"host": "Máy chủ Music Together",
"join": "Tham gia Music Together",
"permission": {
"all": "Cho phép người tham gia kiểm soát danh sách phát và trình phát",
"host-only": "Chỉ người tạo máy chủ có quyền điều khiển danh sách phát và trình phát",
"playlist": "Cho phép người tham gia điều khiển danh sách phát"
},
"set-permission": "Thay đổi quyền điều khiển",
"status": {
"disconnected": "Đã ngắt kết nối",
"guest": "Đã kết nối với tư cách Người tham gia",
"host": "Đã kết nối với tư cách Máy chủ"
}
},
"name": "Music Together [Thử nghiệm]",
"toast": {
"add-song-failed": "Thêm bài hát thất bại",
"closed": "Đã đóng Music Together",
"disconnected": "Đã ngắt kết nối Music Together",
"host-failed": "Không thể tổ chức Music Together",
"id-copied": "Đã sao chép ID máy chủ vào bộ nhớ tạm",
"id-copy-failed": "Sao chepd ID máy chủ vào bộ nhớ tạm không thành công",
"join-failed": "Không thể tham gia Music Together",
"joined": "Đã tham gia Music Together",
"permission-changed": "Quyền của Music Together đã thay đổi thành \"{{permission}}\"",
"remove-song-failed": "Không thể xoá bài hát",
"user-connected": "{{name}} đã tham gia Music Together",
"user-disconnected": "{{name}} đã rời khỏi Music Together"
}
},
"navigation": {
"description": "Mũi tên điều hướng Tiếp theo/Quay lại được tích hợp trực tiếp trong giao diện, giống như trong trình duyệt yêu thích của bạn",
"name": "Điều hướng"
},
"no-google-login": {
"description": "Xóa các nút và liên kết đăng nhập Google khỏi giao diện",
"name": "Không đăng nhập Google"
},
"notifications": {
"description": "Hiển thị thông báo khi bài hát bắt đầu phát (thông báo tương tác có sẵn trên Windows)",
"menu": {
"interactive": "Thông báo tương tác",
"interactive-settings": {
"label": "Cài đặt tương tác",
"submenu": {
"hide-button-text": "Ẩn tên nút",
"refresh-on-play-pause": "Làm mới khi phát/tạm dừng",
"tray-controls": "Mở/Đóng khi nhấp vào khay"
}
},
"priority": "Ưu tiên thông báo",
"toast-style": "Kiểu thông báo bật lên",
"unpause-notification": "Hiển thị thông báo khi bỏ tạm dừng"
},
"name": "Thông báo"
},
"picture-in-picture": {
"description": "Cho phép chuyển ứng dụng sang chế độ ảnh trong ảnh",
"menu": {
"always-on-top": "Luôn ở trên cùng",
"hotkey": {
"label": "Phím nóng",
"prompt": {
"keybind-options": {
"hotkey": "Phím nóng"
},
"label": "Chọn phím nóng để chuyển đổi ảnh trong ảnh",
"title": "Phím nóng ảnh trong ảnh"
}
},
"save-window-position": "Lưu vị trí cửa sổ",
"save-window-size": "Lưu kích thước cửa sổ",
"use-native-pip": "Sử dụng PiP gốc của trình duyệt"
},
"name": "Ảnh trong ảnh",
"templates": {
"button": "Ảnh trong ảnh"
}
},
"playback-speed": {
"description": "Nghe nhanh, nghe chậm! Thêm thanh trượt kiểm soát tốc độ bài hát",
"name": "Tốc độ phát lại",
"templates": {
"button": "Tốc độ"
}
},
"precise-volume": {
"description": "Kiểm soát âm lượng chính xác bằng con lăn chuột/phím nóng, với HUD tùy chỉnh và các bước âm lượng có thể tùy chỉnh",
"menu": {
"arrows-shortcuts": "Điều khiển phím mũi tên cục bộ",
"custom-volume-steps": "Đặt các bước âm lượng tùy chỉnh",
"global-shortcuts": "Phím nóng chung"
},
"name": "Âm lượng chính xác",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Giảm âm lượng",
"increase": "Tăng âm lượng"
},
"label": "Chọn tổ hợp phím âm lượng chung:",
"title": "Liên kết phím âm lượng chung"
},
"volume-steps": {
"label": "Chọn các bước tăng/giảm âm lượng",
"title": "Bước âm lượng"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Chất lượng hiện tại: {{quality}}",
"message": "Chọn chất lượng video:",
"title": "Chọn chất lượng video:"
}
}
},
"description": "Cho phép thay đổi chất lượng video bằng một nút trên lớp phủ video",
"name": "Thay đổi chất lượng video"
},
"scrobbler": {
"description": "Thêm hỗ trợ scrobbling (v.v. Last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Không thể xác minh với \nẨn thông báo cho đến lần bật ứng dụng tiếp theo.",
"title": "Xác minh thất bại"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Cài đặt API Last.fm"
},
"listenbrainz": {
"token": "Nhập mã người dùng ListenBrainz"
},
"scrobble-other-media": "Scrobber nội dung khác"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Khóa API Last.fm",
"api-secret": "API Last.fm bảo mật"
},
"listenbrainz": {
"token": {
"label": "Nhập mã người dùng ListenBrainz của bạn:",
"title": "Mã ListenBrainz"
}
}
}
},
"shortcuts": {
"description": "Cho phép thiết lập các phím nóng chung để phát lại (phát/tạm dừng/tiếp theo/trước) và tắt OSD media bằng cách ghi đè các phím media, bật Ctrl/CMD + F để tìm kiếm, bật hỗ trợ Linux MPRIS cho các phím media và các phím nóng tùy chỉnh cho người dùng nâng cao",
"menu": {
"override-media-keys": "Ghi đè khóa phương tiện",
"set-keybinds": "Đặt điều khiển bài hát chung"
},
"name": "Phím tắt (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Tiếp theo",
"play-pause": "Phát / Tạm dừng",
"previous": "Trước đó"
},
"label": "Chọn tổ hợp phím chung để kiểm soát bài hát:",
"title": "Tổ hợp phím chung"
}
}
},
"skip-disliked-songs": {
"description": "Bỏ qua những bài hát không thích",
"name": "Bỏ qua những bài hát không thích"
},
"skip-silences": {
"description": "Tự động bỏ qua các đoạn im lặng trong bài hát",
"name": "Bỏ qua đoạn im lặng"
},
"sponsorblock": {
"description": "Tự động bỏ qua các phần không phải âm nhạc như phần giới thiệu/kết thúc hoặc các phần của video nhạc mà bài hát không được phát",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "Kiểm soát phát lại từ thanh tác vụ Windows của bạn",
"name": "Kiểm soát phương tiện trên thanh tác vụ"
},
"touchbar": {
"description": "Thêm tiện ích TouchBar cho người dùng macOS",
"name": "TouchBar"
},
"tuna-obs": {
"description": "Tích hợp với plugin Tuna của OBS",
"name": "Tuna OBS"
},
"video-toggle": {
"description": "Thêm nút để chuyển giữa chế độ Video/Bài hát. Cũng có thể tùy ý xóa toàn bộ tab video",
"menu": {
"align": {
"label": "Căn chỉnh",
"submenu": {
"left": "Trái",
"middle": "Giữa",
"right": "Phải"
}
},
"force-hide": "Buộc loại bỏ tab video",
"mode": {
"label": "Chế độ",
"submenu": {
"custom": "Chuyển đổi tùy chỉnh",
"disabled": "Vô hiệu hoá",
"native": "Chuyển đổi gốc"
}
}
},
"name": "Chuyển đổi video",
"templates": {
"button": "Bài hát"
}
},
"visualizer": {
"description": "Thêm trình hiển thị cho trình phát",
"menu": {
"visualizer-type": "Loại trình hiển thị"
},
"name": "Trình hiển thị"
}
}
}

View File

@ -1,7 +1,690 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "执行插件 {{pluginName}}::{{contextName}} 失败",
"executed-at-ms": "插件 {{pluginName}}::{{contextName}} 已在 {{ms}} 毫秒内执行",
"initialize-failed": "初始化插件 “{{pluginName}}” 失败",
"load-all": "正在加载所有插件",
"load-failed": "加载插件 “{{pluginName}}” 失败",
"loaded": "插件 “{{pluginName}}” 已载入",
"unload-failed": "卸载插件 “{{pluginName}}” 失败",
"unloaded": "插件 “{{pluginName}}” 已卸载"
}
}
},
"language": {
"code": "zh-CN",
"local-name": "簡體中文",
"local-name": "简体中文",
"name": "Simplified Chinese"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "加载完毕。开发人员工具已启动"
},
"i18n": {
"loaded": "i18n 已载入"
},
"second-instance": {
"receive-command": "已从协议接收到以下指令:“{{command}}”"
},
"theme": {
"css-file-not-found": "CSS 文件 “{{cssFile}}” 不存在,将被忽略"
},
"unresponsive": {
"details": "无响应错误!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "正在清理应用缓存"
},
"window": {
"tried-to-render-offscreen": "窗口试图于屏幕外绘制, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "菜单已隐藏,按下 Alt 键来显示(若使用应用内菜单则按 Esc 键)",
"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": "复制当前 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": "覆盖 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 键以显示(若使用应用内菜单则按 ` 键)",
"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": {
"label": "主题",
"submenu": {
"import-css-file": "导入自定义 CSS 文件",
"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": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"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}} 秒"
}
},
"use-fullscreen": {
"label": "使用全屏"
}
},
"name": "沉浸模式"
},
"audio-compressor": {
"description": "对音频应用压缩(压低响亮部分,提升柔和部分)",
"name": "音频压缩器"
},
"blur-nav-bar": {
"description": "让导航栏透明及模糊",
"name": "模糊导航栏"
},
"bypass-age-restrictions": {
"description": "绕过 YouTube 年龄验证",
"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": "交叉淡化 [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "淡入持续时间(毫秒)",
"fade-out-duration": "淡出持续时间(毫秒)",
"fade-scaling": {
"label": "淡化尺度",
"linear": "线性",
"logarithmic": "对数"
},
"seconds-before-end": "歌曲结束前持续交叉淡化时长"
},
"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": "Discord Rich Presence 状态显示",
"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": "未找到播放列表 ID",
"playlist-is-empty": "播放列表是空的",
"playlist-is-mix-or-private": "获取播放列表信息时出错:请确认目标不是私有或“为你推荐”列表\n\n{{error}}",
"preparing-file": "正在准备文件…",
"saving": "正在保存…",
"trying-to-get-playlist-id": "正尝试获取播放列表 ID {{playlistId}}",
"video-id-not-found": "视频未找到",
"writing-id3": "正在写入 ID3 标签…"
}
},
"description": "在界面内直接下载 MP3 / 源音频",
"menu": {
"choose-download-folder": "选择下载文件夹",
"download-playlist": "下载播放列表",
"presets": "预设",
"skip-existing": "跳过已存在的文件"
},
"name": "下载器",
"renderer": {
"can-not-update-progress": "无法更新进度"
},
"templates": {
"button": "下载"
}
},
"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": "输入发起人 ID"
},
"internal": {
"save": "保存",
"track-source": "追踪来源",
"unknown-user": "未知用户"
},
"menu": {
"click-to-copy-id": "复制发起者 ID",
"close": "关闭 Music Together",
"connected-users": "已连接用户",
"disconnect": "断开 Music Together 连接",
"empty-user": "没有已连接的用户",
"host": "Music Together 发起者",
"join": "加入 Music Together",
"permission": {
"all": "允许来宾控制播放列表与播放器",
"host-only": "仅发起人可以控制播放列表与播放器",
"playlist": "允许来宾控制播放列表"
},
"set-permission": "更改控制权限",
"status": {
"disconnected": "已断开连接",
"guest": "已作为来宾连接",
"host": "已作为发起人连接"
}
},
"name": "Music Together [测试]",
"toast": {
"add-song-failed": "添加歌曲失败",
"closed": "Music Together 已关闭",
"disconnected": "Music Together 已断开连接",
"host-failed": "发起 Music Together 失败",
"id-copied": "已将发起者 ID 复制到剪切板",
"id-copy-failed": "复制发起者 ID 到剪贴板时失败",
"join-failed": "加入 Music Together 失败",
"joined": "已加入 Music Together",
"permission-changed": "Music Together 权限已改为 \"{{permission}}\"",
"remove-song-failed": "移除歌曲失败",
"user-connected": "{{name}} 加入了 Music Together",
"user-disconnected": "{{name}} 离开了 Music Together"
}
},
"navigation": {
"description": "如同浏览器般,在应用界面内直接显示前进/后退导航按钮",
"name": "导航"
},
"no-google-login": {
"description": "从界面内移除 Google 登录按钮和链接",
"name": "无 Google 登录"
},
"notifications": {
"description": "歌曲开始时显示通知(交互式通知仅适用于 Windows",
"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": "添加歌曲追踪支持(如 Last.fm 和 Listenbrainz",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "与 Last.fm 认证时失败\n弹出窗口将在下次重启前隐藏。",
"title": "认证失败"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API 设置"
},
"listenbrainz": {
"token": "输入 ListenBrainz 用户令牌"
},
"scrobble-other-media": "记录其他媒体文件"
},
"name": "歌曲记录器",
"prompt": {
"lastfm": {
"api-key": "Last.fm API 密钥Key",
"api-secret": "Last.fm API 密文Secret"
},
"listenbrainz": {
"token": {
"label": "输入您的v 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": "自动跳过非音乐部分,如 MV 的介绍/结语以及歌曲未开始的部分",
"name": "SponsorBlock"
},
"taskbar-mediacontrol": {
"description": "从 Windows 任务栏控制音乐回放",
"name": "任务栏媒体控件"
},
"touchbar": {
"description": "为 macOS 用户启用 TouchBar 支持",
"name": "TouchBar"
},
"tuna-obs": {
"description": "与 OBS 的 Tuna 插件集成",
"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

@ -2,14 +2,14 @@
"common": {
"console": {
"plugins": {
"execute-failed": "外掛 {{pluginName}} 無法執行::{{contextName}}",
"execute-failed": "外掛 {{pluginName}} 無法執行::{{contextName}}",
"executed-at-ms": "外掛 {{pluginName}}::{{contextName}} 用了 {{ms}} 毫秒來執行",
"initialize-failed": "初始化外掛「{{pluginName}}」失敗",
"load-all": "正在載入所有外掛",
"load-failed": "載入外掛「{{pluginName}}」失敗",
"loaded": "外掛「{{pluginName}}」已載入",
"unload-failed": "移除外掛「{{pluginName}}」失敗",
"unloaded": "外掛「{{pluginName}}」已移除"
"unloaded": "外掛「{{pluginName}}」已移除"
}
}
},
@ -44,18 +44,18 @@
},
"dialog": {
"hide-menu-enabled": {
"detail": "選單已隱藏,使用 Alt 鍵來重新顯示(或是使用 Esc 鍵)",
"message": "隱藏選單已經啟用",
"title": "隱藏選單已啟用"
"detail": "選單已隱藏,使用 Alt 鍵來重新顯示(或是使用 Esc 鍵)",
"message": "隱藏選單已經啟用",
"title": "隱藏選單已啟用"
},
"need-to-restart": {
"buttons": {
"later": "稍後",
"restart-now": "立即重啟"
},
"detail": "外掛「{{pluginName}}」需要程式重新啟動之後才會生效",
"message": "{{pluginName}}」需要重新啟動",
"title": "需要重新啟動"
"detail": "\"{{pluginName}}\" 外掛需要重啟應用之後才會生效",
"message": "\"{{pluginName}}\" 需要重啟應用",
"title": "需要重啟應用"
},
"unresponsive": {
"buttons": {
@ -87,7 +87,7 @@
"go-back": "回到上一頁",
"go-forward": "回到下一頁",
"quit": "退出",
"restart": "重啟程式"
"restart": "重啟應用"
}
},
"options": {
@ -100,12 +100,12 @@
"disable-hardware-acceleration": "關閉硬體加速",
"edit-config-json": "編輯 config.json",
"override-user-agent": "覆寫使用者代理",
"restart-on-config-changes": "設定檔變更時重啟程式",
"restart-on-config-changes": "設定檔更動時自動重啟應用程式",
"set-proxy": {
"label": "設定代理伺服器",
"prompt": {
"label": "輸入代理伺服器位置:(留空以停用本設定)",
"placeholder": "範例:socks5://127.0.0.1:9999",
"placeholder": "範例:SOCKS5://127.0.0.1:9999",
"title": "設定代理伺服器"
}
},
@ -116,10 +116,10 @@
"auto-update": "自動更新",
"hide-menu": {
"dialog": {
"message": "選單會在程式下次啟動時隱藏,使用 Alt 鍵來重新顯示(或是使用 ` 鍵)",
"title": "隱藏選單已啟用"
"message": "選單會在程式下次啟動時隱藏,使用 Alt 鍵來重新顯示(或是使用 ` 鍵)",
"title": "隱藏選單已啟用"
},
"label": "隱藏選單"
"label": "隱藏選單"
},
"language": {
"dialog": {
@ -131,12 +131,12 @@
"to-help-translate": "想要協助翻譯?按一下這裡"
}
},
"resume-on-start": "繼續上次關閉應用程式前的音樂",
"single-instance-lock": "禁止多開應用程式",
"resume-on-start": "應用啟動時繼續上次播放的歌曲",
"single-instance-lock": "單視窗鎖定",
"start-at-login": "開機時啟動",
"starting-page": {
"label": "啟動頁面",
"unset": "未設定"
"unset": "不指定"
},
"tray": {
"label": "系統閘圖式",
@ -148,7 +148,7 @@
}
},
"visual-tweaks": {
"label": "視覺設定",
"label": "介面設定",
"submenu": {
"like-buttons": {
"default": "預設",
@ -170,7 +170,8 @@
},
"plugins": {
"enabled": "啟用",
"label": "外掛功能"
"label": "外掛功能",
"new": "新的"
},
"view": {
"label": "視窗",
@ -190,7 +191,11 @@
"previous": "上一首",
"quit": "關閉",
"restart": "重啟程式",
"show": "顯示視窗"
"show": "顯示視窗",
"tooltip": {
"default": "Youtube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
@ -199,14 +204,26 @@
"menu": {
"blocker": "阻擋方式"
},
"name": "廣告阻擋"
"name": "廣告攔截器"
},
"album-actions": {
"description": "新增支援對整個播放清單或專輯\"喜歡/不喜歡\"\"取消喜歡/取消不喜歡\"的按鈕",
"name": "進階專輯操作"
},
"album-color-theme": {
"description": "依歌曲專輯色調動態改變主題顏色",
"name": "動態專輯主題色調"
"description": "依歌曲色調自動更改應用程式主題",
"menu": {
"color-mix-ratio": {
"label": "顏色混合程度",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "隨歌曲色調變更主題"
},
"ambient-mode": {
"description": "將影片內容的淺色畫面投放至螢幕背景, 讓觀眾在觀賞影片時更有臨場感",
"description": "影片周圍背景根據影片內容改變顏色, 讓觀眾在觀賞影片時更有臨場感",
"menu": {
"blur-amount": {
"label": "模糊等級",
@ -329,13 +346,13 @@
"hide-duration-left": "隱藏音樂剩餘時間狀態",
"hide-github-button": "隱藏Github頁面按鈕",
"play-on-youtube-music": "顯示Play on YouTube Music按鈕",
"set-inactivity-timeout": "設置歌曲暫停後幾秒清除狀態"
"set-inactivity-timeout": "設定閒置狀態時長"
},
"name": "Discord狀態",
"prompt": {
"set-inactivity-timeout": {
"label": "設多少秒後清除狀態:",
"title": "設置歌曲暫停後幾秒清除狀態"
"label": "設多少秒後清除狀態:",
"title": "設定閒置狀態時長"
}
}
},
@ -354,7 +371,7 @@
"ok": "完成"
},
"detail": "({{playlistSize}} 首歌曲)",
"message": "正在下載 {{playlistTitle}} 播放清單",
"message": "正在下載播放清單 {{playlistTitle}}",
"title": "開始下載"
}
},
@ -366,30 +383,30 @@
"download-progress": "下載進度: {{percent}}%",
"downloading": "下載中…",
"downloading-counter": "正在下載第 {{current}}/{{total}}…",
"downloading-playlist": "正在下載 \"{{playlistTitle}}\" 播放清單 - 共 {{playlistSize}} 首歌 ({{playlistId}})",
"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": "沒有找到播放清單ID",
"playlist-is-empty": "播放清單為空",
"playlist-has-only-one-song": "播放清單內只有一首歌曲, 直接下載",
"playlist-id-not-found": "沒有找到播放清單 ID",
"playlist-is-empty": "播放清單是空的",
"playlist-is-mix-or-private": "獲取播放清單資訊時發生錯誤: 請確認非私人播放清單或是\"為你推薦的合輯\"\n\n{{error}}",
"preparing-file": "正在準備檔案…",
"saving": "儲存中…",
"trying-to-get-playlist-id": "正在嘗試獲取播放清單ID: {{playlistId}}",
"video-id-not-found": "未找到影片",
"writing-id3": "正在寫入ID3標籤…"
"trying-to-get-playlist-id": "正在嘗試獲取播放清單 ID: {{playlistId}}",
"video-id-not-found": "未找到影片",
"writing-id3": "正在寫入 ID3 標籤…"
}
},
"description": "在應用程式內下載MP3原始音樂檔",
"description": "在應用程式內下載 MP3原始音樂檔",
"menu": {
"choose-download-folder": "選擇下載位置",
"download-playlist": "下載播放清單",
"presets": "預設格式",
"skip-existing": "跳過已存在的檔案"
},
"name": "下載",
"name": "歌曲下載",
"renderer": {
"can-not-update-progress": "無法更新進度"
},
@ -398,22 +415,18 @@
}
},
"exponential-volume": {
"description": "使音量滑桿指數增加,以便更容易選擇較低的音量。",
"name": "指數音量調整"
"description": "使音量滑桿指數,以便更容易選擇較低的音量。",
"name": "指數音量調整"
},
"in-app-menu": {
"description": "優化選單欄外觀, 選單欄顏色將會隨主題變色或預設黑色",
"description": "使選單列變更為黑色或隨主題變色",
"menu": {
"hide-dom-window-controls": "隱藏DOM視窗控制"
},
"name": "程式內選單"
},
"last-fm": {
"description": "新增對Last.fm的scrobbling支援",
"name": "Last.fm"
"name": "程式內選單"
},
"lumiastream": {
"description": "新增對Lumia Stream的支援",
"description": "新增對 Lumia Stream 的支援",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
@ -426,13 +439,59 @@
"fetched-lyrics": "為Genius獲取字幕"
}
},
"music-together": {
"description": "與他人共享播放清單。當發起人播放歌曲時,其他成員也會同步收聽",
"dialog": {
"enter-host": "輸入發起人 ID"
},
"internal": {
"save": "儲存",
"track-source": "追蹤來源",
"unknown-user": "未知使用者"
},
"menu": {
"click-to-copy-id": "複製發起人 ID",
"close": "同步關閉音樂",
"connected-users": "已連接的使用者",
"disconnect": "斷開連接共享音樂",
"empty-user": "無已連接的使用者",
"host": "發起共享音樂",
"join": "加入共享音樂",
"permission": {
"all": "允許加入的使用者控制播放清單及播放控制",
"host-only": "不允許加入的使用者控制播放清單及播放控制",
"playlist": "只允許加入的使用者控制播放清單"
},
"set-permission": "切換共享音樂播放權限",
"status": {
"disconnected": "已斷開連接",
"guest": "以使用者身份加入",
"host": "以發起人身份加入"
}
},
"name": "共享音樂 [Beta]",
"toast": {
"add-song-failed": "歌曲加入失敗",
"closed": "關閉共享音樂",
"disconnected": "共享音樂已斷開連接",
"host-failed": "發起共享音樂失敗",
"id-copied": "已複製發起人 ID",
"id-copy-failed": "複製發起人 ID 失敗",
"join-failed": "加入共享音樂失敗",
"joined": "加入共享音樂",
"permission-changed": "共享音樂播放權限已切換至 \"{{permission}}\"",
"remove-song-failed": "歌曲移除失敗",
"user-connected": "{{name}} 已加入共享音樂",
"user-disconnected": "{{name}} 離開了共享音樂"
}
},
"navigation": {
"description": "將上一頁/下一頁按鈕新增至應用程式上方, 就像你最熟悉的瀏覽器",
"name": "導覽列"
},
"no-google-login": {
"description": "移除Google登入按鈕及連結",
"name": "用Google登入"
"name": "用Google登入"
},
"notifications": {
"description": "在歌曲播放時發送一個系統通知 (可互動通知僅限Windows)",
@ -453,7 +512,7 @@
"name": "歌曲播放通知"
},
"picture-in-picture": {
"description": "允許應用程式切換至畫中畫模式",
"description": "允許應用程式切換至子母畫面模式",
"menu": {
"always-on-top": "永遠顯示在最上層",
"hotkey": {
@ -462,17 +521,17 @@
"keybind-options": {
"hotkey": "快捷鍵"
},
"label": "選擇一個快捷鍵來切換畫中畫模式",
"title": "畫中畫模式快捷鍵"
"label": "選擇一個快捷鍵來切換子母畫面模式",
"title": "子母畫面模式快捷鍵"
}
},
"save-window-position": "記住視窗位置",
"save-window-size": "記住視窗大小",
"use-native-pip": "使用瀏覽器原生畫中畫模式"
"use-native-pip": "使用瀏覽器原生子母畫面模式"
},
"name": "畫中畫模式",
"name": "子母畫面",
"templates": {
"button": "畫中畫模式"
"button": "子母畫面"
}
},
"playback-speed": {
@ -483,13 +542,13 @@
}
},
"precise-volume": {
"description": "讓你可使用滑鼠滾輪/快捷鍵控制音量",
"description": "讓你可使用滑鼠滾輪/快捷鍵控制音量,並顯示目前音量大小",
"menu": {
"arrows-shortcuts": "本地方向鍵控制",
"custom-volume-steps": "自訂音量層級",
"arrows-shortcuts": "方向鍵音量控制",
"custom-volume-steps": "自訂音量調整時層級",
"global-shortcuts": "全域快捷鍵"
},
"name": "精確音量控制",
"name": "進階音量控制",
"prompt": {
"global-shortcuts": {
"keybind-options": {
@ -500,8 +559,8 @@
"title": "全域音量控制快捷鍵"
},
"volume-steps": {
"label": "設定音量一次增加/降低的層級",
"title": "音量層級設定"
"label": "設定音量一次增加/降低的層級",
"title": "自訂音量調整時層級"
}
}
},
@ -515,8 +574,41 @@
}
}
},
"description": "允許在影片畫面內調整影片畫質",
"name": "影片畫質更改器"
"description": "允許在影片內進行畫質更改",
"name": "允許變更影片畫質"
},
"scrobbler": {
"description": "額外新增 scrobbling 支援 (例如last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm認證失敗\n將隱藏彈窗直到重啟。",
"title": "認證失敗"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API 設定"
},
"listenbrainz": {
"token": "輸入 ListenBrainz 使用者憑證"
},
"scrobble-other-media": "紀錄其他媒體文件"
},
"name": "Scrobbler",
"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媒體快捷鍵 + 更多自訂快捷鍵給進階使用者",
@ -537,9 +629,13 @@
}
}
},
"skip-disliked-songs": {
"description": "自動跳過不喜歡的歌曲",
"name": "自動跳過不喜歡的歌曲"
},
"skip-silences": {
"description": "自動跳過音樂無聲片段",
"name": "跳過無聲"
"name": "自動跳過無聲片段"
},
"sponsorblock": {
"description": "自動跳過贊助片段",
@ -550,11 +646,11 @@
"name": "工作列媒體控制"
},
"touchbar": {
"description": "為macOS使用者新增支援觸控列",
"name": "觸控列"
"description": "為macOS使用者新增觸控列支援",
"name": "觸控列 (Touchbar) 支援"
},
"tuna-obs": {
"description": "與OBS外掛Tuna連接",
"description": "與 OBSTuna 外掛連接",
"name": "Tuna OBS"
},
"video-toggle": {
@ -578,7 +674,7 @@
}
}
},
"name": "影片切換",
"name": "歌曲/影片切換",
"templates": {
"button": "歌曲"
}

View File

@ -53,8 +53,17 @@ import {
import { LoggerPrefix } from '@/utils';
import { loadI18n, setLanguage, t } from '@/i18n';
import ErrorHtmlAsset from '@assets/error.html?asset';
import type { PluginConfig } from '@/types/plugins';
if (!is.macOS()) {
delete allPlugins['touchbar'];
}
if (!is.windows()) {
delete allPlugins['taskbar-mediacontrol'];
}
// Catch errors and log them
unhandled({
logger: console.error,
@ -73,11 +82,15 @@ if (!gotTheLock) {
app.exit();
}
// Ozone platform hint: Required for Wayland support
app.commandLine.appendSwitch('ozone-platform-hint', 'auto');
// SharedArrayBuffer: Required for downloader (@ffmpeg/core-mt)
// OverlayScrollbar: Required for overlay scrollbars
// UseOzonePlatform: Required for Wayland support
// WaylandWindowDecorations: Required for Wayland decorations
app.commandLine.appendSwitch(
'enable-features',
'OverlayScrollbar,SharedArrayBuffer',
'OverlayScrollbar,SharedArrayBuffer,UseOzonePlatform,WaylandWindowDecorations',
);
if (config.get('options.disableHardwareAcceleration')) {
if (is.dev()) {
@ -114,18 +127,18 @@ function onClosed() {
mainWindow = null;
}
ipcMain.handle('get-main-plugin-names', () => Object.keys(mainPlugins));
ipcMain.handle('ytmd:get-main-plugin-names', () => Object.keys(mainPlugins));
const initHook = (win: BrowserWindow) => {
ipcMain.handle(
'get-config',
'ytmd:get-config',
(_, id: string) =>
deepmerge(
allPlugins[id].config ?? { enabled: false },
config.get(`plugins.${id}`) ?? {},
) as PluginConfig,
);
ipcMain.handle('set-config', (_, name: string, obj: object) =>
ipcMain.handle('ytmd:set-config', (_, name: string, obj: object) =>
config.setPartial(`plugins.${name}`, obj, allPlugins[name].config),
);
@ -258,7 +271,7 @@ async function createMainWindow() {
const windowPosition: Electron.Point = config.get('window-position');
const useInlineMenu = config.plugins.isEnabled('in-app-menu');
const defaultTitleBarOverlayOptions: Electron.TitleBarOverlayOptions = {
const defaultTitleBarOverlayOptions: Electron.TitleBarOverlay = {
color: '#00000000',
symbolColor: '#ffffff',
height: 32,
@ -299,7 +312,7 @@ async function createMainWindow() {
const { x: windowX, y: windowY } = windowPosition;
const winSize = win.getSize();
const display = screen.getDisplayNearestPoint(windowPosition);
const scaleFactor = display.scaleFactor;
const scaleFactor = is.windows() ? display.scaleFactor: 1;
const scaledWidth = Math.floor(windowSize.width / scaleFactor);
const scaledHeight = Math.floor(windowSize.height / scaleFactor);
@ -402,53 +415,26 @@ async function createMainWindow() {
removeContentSecurityPolicy();
win.webContents.on('dom-ready', async () => {
win.webContents.on('dom-ready', () => {
if (useInlineMenu && is.windows()) {
win.setTitleBarOverlay({
...defaultTitleBarOverlayOptions,
height: Math.floor(
defaultTitleBarOverlayOptions.height! *
win.webContents.getZoomFactor(),
win.webContents.getZoomFactor(),
),
});
}
});
win.webContents.on('will-redirect', (event) => {
const url = new URL(event.url);
// Inject index.html file as string using insertAdjacentHTML
// In dev mode, get string from process.env.VITE_DEV_SERVER_URL, else use fs.readFileSync
if (is.dev() && process.env.ELECTRON_RENDERER_URL) {
// HACK: to make vite work with electron renderer (supports hot reload)
await win.webContents.executeJavaScript(`
console.log('Loading vite from dev server');
const viteScript = document.createElement('script');
viteScript.type = 'module';
viteScript.src = '${process.env.ELECTRON_RENDERER_URL}/@vite/client';
const rendererScript = document.createElement('script');
rendererScript.type = 'module';
rendererScript.src = '${process.env.ELECTRON_RENDERER_URL}/renderer.ts';
document.body.appendChild(viteScript);
document.body.appendChild(rendererScript);
0
`);
} else {
const rendererPath = path.join(__dirname, '..', 'renderer');
const indexHTML = parse(
fs.readFileSync(path.join(rendererPath, 'index.html'), 'utf-8'),
);
const scriptSrc = indexHTML.querySelector('script')!;
const scriptPath = path.join(
rendererPath,
scriptSrc.getAttribute('src')!,
);
const scriptString = fs.readFileSync(scriptPath, 'utf-8');
await win.webContents.executeJavaScriptInIsolatedWorld(
0,
[
{
code: scriptString + ';0',
url: url.pathToFileURL(scriptPath).toString(),
},
],
true,
// Workarounds for regions where YTM is restricted
if (url.hostname.endsWith('youtube.com') && url.pathname === '/premium') {
event.preventDefault();
win.webContents.loadURL(
'https://accounts.google.com/ServiceLogin?ltmpl=music&service=youtube&continue=https%3A%2F%2Fwww.youtube.com%2Fsignin%3Faction_handle_signin%3Dtrue%26next%3Dhttps%253A%252F%252Fmusic.youtube.com%252F'
);
}
});
@ -525,7 +511,7 @@ app.once('browser-window-created', (_event, win) => {
if (errorCode !== -3) {
// -3 is a false positive
win.webContents.send('log', log);
win.webContents.loadFile(path.join(__dirname, 'error.html'));
win.webContents.loadFile(ErrorHtmlAsset);
}
},
);
@ -606,7 +592,7 @@ app.whenReady().then(async () => {
);
try {
// Check if shortcut is registered and valid
const shortcutDetails = shell.readShortcutLink(shortcutPath); // Throw error if doesn't exist yet
const shortcutDetails = shell.readShortcutLink(shortcutPath); // Throw error if it doesn't exist yet
if (
shortcutDetails.target !== appLocation ||
shortcutDetails.appUserModelId !== appID
@ -629,6 +615,48 @@ app.whenReady().then(async () => {
}
}
ipcMain.on('get-renderer-script', (event) => {
// Inject index.html file as string using insertAdjacentHTML
// In dev mode, get string from process.env.VITE_DEV_SERVER_URL, else use fs.readFileSync
if (is.dev() && process.env.ELECTRON_RENDERER_URL) {
// HACK: to make vite work with electron renderer (supports hot reload)
event.returnValue = [null, `
console.log('${LoggerPrefix}', 'Loading vite from dev server');
(async () => {
await new Promise((resolve) => {
if (document.readyState === 'loading') {
console.log('${LoggerPrefix}', 'Waiting for DOM to load');
document.addEventListener('DOMContentLoaded', () => resolve(), { once: true });
} else {
resolve();
}
});
const viteScript = document.createElement('script');
viteScript.type = 'module';
viteScript.src = '${process.env.ELECTRON_RENDERER_URL}/@vite/client';
const rendererScript = document.createElement('script');
rendererScript.type = 'module';
rendererScript.src = '${process.env.ELECTRON_RENDERER_URL}/renderer.ts';
document.body.appendChild(viteScript);
document.body.appendChild(rendererScript);
})();
0
`];
} else {
const rendererPath = path.join(__dirname, '..', 'renderer');
const indexHTML = parse(
fs.readFileSync(path.join(rendererPath, 'index.html'), 'utf-8'),
);
const scriptSrc = indexHTML.querySelector('script')!;
const scriptPath = path.join(
rendererPath,
scriptSrc.getAttribute('src')!,
);
const scriptString = fs.readFileSync(scriptPath, 'utf-8');
event.returnValue = [url.pathToFileURL(scriptPath).toString(), scriptString + ';0'];
}
});
mainWindow = await createMainWindow();
await setApplicationMenu(mainWindow);
await refreshMenu(mainWindow);
@ -649,7 +677,9 @@ app.whenReady().then(async () => {
);
}
handleProtocol(command);
const splited = decodeURIComponent(command).split(' ');
handleProtocol(splited.shift()!, splited);
return;
}
@ -684,13 +714,15 @@ app.whenReady().then(async () => {
const dialogOptions: Electron.MessageBoxOptions = {
type: 'info',
buttons: [
t('main.dialog.update-available.buttons.download'),
t('main.dialog.update-available.buttons.ok'),
t('main.dialog.update-available.buttons.download'),
t('main.dialog.update-available.buttons.disable'),
],
title: t('main.dialog.update-available.title'),
message: t('main.dialog.update-available.message'),
detail: t('main.dialog.update-available.detail', { downloadLink }),
defaultId: 1,
cancelId: 0,
};
let dialogPromise: Promise<Electron.MessageBoxReturnValue>;
@ -714,7 +746,7 @@ app.whenReady().then(async () => {
break;
}
default: {
case 0: {
break;
}
}

View File

@ -18,9 +18,9 @@ const loadedPluginMap: Record<
export const createContext = <Config extends PluginConfig>(
id: string,
): RendererContext<Config> => ({
getConfig: async () => window.ipcRenderer.invoke('get-config', id),
getConfig: async () => window.ipcRenderer.invoke('ytmd:get-config', id),
setConfig: async (newConfig) => {
await window.ipcRenderer.invoke('set-config', id, newConfig);
await window.ipcRenderer.invoke('ytmd:set-config', id, newConfig);
},
ipc: {
send: (event: string, ...args: unknown[]) => {

View File

@ -9,6 +9,7 @@ import {
shell,
} from 'electron';
import prompt from 'custom-electron-prompt';
import { satisfies } from 'semver';
import { allPlugins } from 'virtual:plugins';
@ -23,6 +24,8 @@ import promptOptions from './providers/prompt-options';
import { getAllMenuTemplate, loadAllMenuPlugins } from './loader/menu';
import { setLanguage, t } from '@/i18n';
import packageJson from '../package.json';
export type MenuTemplate = Electron.MenuItemConstructorOptions[];
// True only if in-app-menu was loaded on launch
@ -31,10 +34,14 @@ const inAppMenuActive = config.plugins.isEnabled('in-app-menu');
const pluginEnabledMenu = (
plugin: string,
label = '',
description: string | undefined = undefined,
isNew = false,
hasSubmenu = false,
refreshMenu: (() => void) | undefined = undefined,
): Electron.MenuItemConstructorOptions => ({
label: label || plugin,
sublabel: isNew ? t('main.menu.plugins.new') : undefined,
toolTip: description,
type: 'checkbox',
checked: config.plugins.isEnabled(plugin),
click(item: Electron.MenuItem) {
@ -66,12 +73,15 @@ export const mainMenuTemplate = async (
const menuResult = Object.entries(getAllMenuTemplate()).map(
([id, template]) => {
const pluginLabel = allPlugins[id]?.name?.() ?? id;
const plugin = allPlugins[id];
const pluginLabel = plugin?.name?.() ?? id;
const pluginDescription = plugin?.description?.() ?? undefined;
const isNew = plugin?.addedVersion ? satisfies(packageJson.version, plugin.addedVersion) : false;
if (!config.plugins.isEnabled(id)) {
return [
id,
pluginEnabledMenu(id, pluginLabel, true, innerRefreshMenu),
pluginEnabledMenu(id, pluginLabel, pluginDescription, isNew, true, innerRefreshMenu),
] as const;
}
@ -79,10 +89,14 @@ export const mainMenuTemplate = async (
id,
{
label: pluginLabel,
sublabel: isNew ? t('main.menu.plugins.new') : undefined,
toolTip: pluginDescription,
submenu: [
pluginEnabledMenu(
id,
t('main.menu.plugins.enabled'),
undefined,
false,
true,
innerRefreshMenu,
),
@ -106,9 +120,12 @@ export const mainMenuTemplate = async (
const predefinedTemplate = menuResult.find((it) => it[0] === id);
if (predefinedTemplate) return predefinedTemplate[1];
const pluginLabel = allPlugins[id]?.name?.() ?? id;
const plugin = allPlugins[id];
const pluginLabel = plugin?.name?.() ?? id;
const pluginDescription = plugin?.description?.() ?? undefined;
const isNew = plugin?.addedVersion ? satisfies(packageJson.version, plugin.addedVersion) : false;
return pluginEnabledMenu(id, pluginLabel, true, innerRefreshMenu);
return pluginEnabledMenu(id, pluginLabel, pluginDescription, isNew, true, innerRefreshMenu);
});
const availableLanguages = Object.keys(languageResources);

View File

@ -109,7 +109,7 @@ export default createPlugin({
},
},
preload: {
script: 'window.JSON = window._proxyJson; window._proxyJson = undefined; window.Response = window._proxyResponse; window._proxyResponse = undefined; 0',
script: 'window.JSON.parse = window._proxyJsonParse; window._proxyJsonParse = undefined; window.Response.prototype.json = window._proxyResponseJson; window._proxyResponseJson = undefined; 0',
async start({ getConfig }) {
const config = await getConfig();

View File

@ -32,37 +32,17 @@ export const inject = (contextBridge) => {
return o;
};
contextBridge.exposeInMainWorld('_proxyJson', {
parse: new Proxy(JSON.parse, {
apply() {
return pruner(Reflect.apply(...arguments));
},
}),
stringify: JSON.stringify,
[Symbol.toStringTag]: JSON[Symbol.toStringTag],
});
contextBridge.exposeInMainWorld('_proxyJsonParse', new Proxy(JSON.parse, {
apply() {
return pruner(Reflect.apply(...arguments));
},
}));
const withPrototype = (obj) => {
const protos = Object.getPrototypeOf(obj);
for (const [key, value] of Object.entries(protos)) {
if (Object.prototype.hasOwnProperty.call(obj, key)) continue;
if (typeof value === 'function') {
obj[key] = function (...args) {
return value.call(obj, ...args);
}
} else {
obj[key] = value;
}
}
return obj;
};
Response.prototype.json = new Proxy(Response.prototype.json, {
contextBridge.exposeInMainWorld('_proxyResponseJson', new Proxy(Response.prototype.json, {
apply() {
return Reflect.apply(...arguments).then((o) => pruner(o));
},
});
contextBridge.exposeInMainWorld('_proxyResponse', withPrototype(Response));
}));
}
(function () {

View File

@ -0,0 +1,193 @@
import { t } from '@/i18n';
import { createPlugin } from '@/utils';
import { ElementFromHtml } from '@/plugins/utils/renderer';
import undislikeHTML from './templates/undislike.html?raw';
import dislikeHTML from './templates/dislike.html?raw';
import likeHTML from './templates/like.html?raw';
import unlikeHTML from './templates/unlike.html?raw';
export default createPlugin<
unknown,
unknown,
{
observer?: MutationObserver;
loadObserver?: MutationObserver;
changeObserver?: MutationObserver;
waiting: boolean;
onPageChange(): void;
waitForElem(selector: string): Promise<HTMLElement>;
loadFullList: (event: MouseEvent) => void;
applyToList(id: string, loader: HTMLElement): void;
start(): void;
stop(): void;
}
>({
name: () => t('plugins.album-actions.name'),
description: () => t('plugins.album-actions.description'),
restartNeeded: false,
addedVersion: '3.2.X',
config: {
enabled: false,
},
renderer: {
waiting: false,
start() {
// Waits for pagechange
this.onPageChange();
this.observer = new MutationObserver(() => {
this.onPageChange();
});
this.observer.observe(document.querySelector('#browse-page')!, {
attributes: false,
childList: true,
subtree: true,
});
},
async onPageChange() {
if (this.waiting) {
return;
} else {
this.waiting = true;
}
const continuations = await this.waitForElem('#continuations');
this.waiting = false;
//Gets the for buttons
const buttons: Array<HTMLElement> = [
ElementFromHtml(undislikeHTML),
ElementFromHtml(dislikeHTML),
ElementFromHtml(likeHTML),
ElementFromHtml(unlikeHTML),
];
//Finds the playlist
const playlist =
document.querySelector('ytmusic-shelf-renderer') ??
document.querySelector('ytmusic-playlist-shelf-renderer')!;
// Adds an observer for every button, so it gets updated when one is clicked
this.changeObserver?.disconnect();
this.changeObserver = new MutationObserver(() => {
this.stop();
this.start();
});
const allButtons = playlist.querySelectorAll(
'yt-button-shape.ytmusic-like-button-renderer',
);
for (const btn of allButtons) {
this.changeObserver.observe(btn, {
attributes: true,
childList: false,
subtree: false,
});
}
//Determine if button is needed and colors the percentage
const listsLength = playlist.querySelectorAll(
'#button-shape-dislike > button',
).length;
if (continuations.children.length == 0 && listsLength > 0) {
const counts = [
playlist?.querySelectorAll(
'#button-shape-dislike[aria-pressed=true] > button',
).length,
playlist?.querySelectorAll(
'#button-shape-dislike[aria-pressed=false] > button',
).length,
playlist?.querySelectorAll(
'#button-shape-like[aria-pressed=false] > button',
).length,
playlist?.querySelectorAll(
'#button-shape-like[aria-pressed=true] > button',
).length,
];
let i = 0;
for (const count of counts) {
if (count == 0) {
buttons.splice(i, 1);
i--;
} else {
(buttons[i].children[0].children[0] as HTMLElement).style.setProperty(
'-webkit-mask-size',
`100% ${100 - ((count / listsLength) * 100)}%`,
);
}
i++;
}
}
const menu = document.querySelector('.detail-page-menu');
if (menu && !document.querySelector('.like-menu')) {
for (const button of buttons) {
menu.appendChild(button);
button.addEventListener('click', this.loadFullList);
}
}
},
loadFullList(event: MouseEvent) {
if (event.currentTarget instanceof Element) {
event.stopPropagation();
const id = event.currentTarget.id;
const loader = document.getElementById('continuations')!;
this.loadObserver = new MutationObserver(() => {
this.applyToList(id, loader);
});
this.applyToList(id, loader);
this.loadObserver.observe(loader, {
attributes: true,
childList: true,
subtree: true,
});
loader?.style.setProperty('top', '0');
loader?.style.setProperty('left', '50%');
loader?.style.setProperty('position', 'absolute');
}
},
applyToList(id: string, loader: HTMLElement) {
if (loader.children.length != 0) return;
this.loadObserver?.disconnect();
let playlistButtons: NodeListOf<HTMLElement> | undefined;
const playlist = document.querySelector('ytmusic-shelf-renderer')
? document.querySelector('ytmusic-shelf-renderer')
: document.querySelector('ytmusic-playlist-shelf-renderer');
switch (id) {
case 'allundislike':
playlistButtons = playlist?.querySelectorAll(
'#button-shape-dislike[aria-pressed=true] > button',
);
break;
case 'alldislike':
playlistButtons = playlist?.querySelectorAll(
'#button-shape-dislike[aria-pressed=false] > button',
);
break;
case 'alllike':
playlistButtons = playlist?.querySelectorAll(
'#button-shape-like[aria-pressed=false] > button',
);
break;
case 'allunlike':
playlistButtons = playlist?.querySelectorAll(
'#button-shape-like[aria-pressed=true] > button',
);
break;
default:
}
playlistButtons?.forEach((elem) => elem.click());
},
stop() {
this.observer?.disconnect();
this.changeObserver?.disconnect();
for (const button of document.querySelectorAll('.like-menu')) {
button.remove();
}
},
waitForElem(selector: string) {
return new Promise((resolve) => {
const interval = setInterval(() => {
const elem = document.querySelector<HTMLElement>(selector);
if (!elem) return;
clearInterval(interval);
resolve(elem);
});
});
},
},
});

View File

@ -0,0 +1,74 @@
<button
id="alldislike"
data-type="dislike"
data-filled="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Dislike all"
>
<div
class="yt-spec-button-shape-next__icon"
style="color: var(--ytmusic-setting-item-toggle-active)"
aria-hidden="true"
>
<div
class="yt-spec-button-shape-next__icon"
style="
color: white;
-webkit-mask: linear-gradient(grey, grey);
-webkit-mask-size: 100% 50%;
-webkit-mask-repeat: no-repeat;
z-index: 1;
position: absolute;
"
aria-hidden="true"
>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="
pointer-events: none;
display: block;
width: 100%;
height: 100%;
"
>
<g class="style-scope yt-icon">
<path
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="pointer-events: none; display: block; width: 100%; height: 100%"
>
<g class="style-scope yt-icon">
<path
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<yt-touch-feedback-shape style="border-radius: inherit">
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
>
<div class="yt-spec-touch-feedback-shape__stroke"></div>
<div class="yt-spec-touch-feedback-shape__fill"></div>
</div>
</yt-touch-feedback-shape>
</button>

View File

@ -0,0 +1,74 @@
<button
id="alllike"
data-type="like"
data-filled="false"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Like all"
>
<div
class="yt-spec-button-shape-next__icon"
style="color: var(--ytmusic-setting-item-toggle-active)"
aria-hidden="true"
>
<div
class="yt-spec-button-shape-next__icon"
style="
color: white;
-webkit-mask: linear-gradient(grey, grey);
-webkit-mask-size: 100% 50%;
-webkit-mask-repeat: no-repeat;
z-index: 1;
position: absolute;
"
aria-hidden="true"
>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="
pointer-events: none;
display: block;
width: 100%;
height: 100%;
"
>
<g class="style-scope yt-icon">
<path
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="pointer-events: none; display: block; width: 100%; height: 100%"
>
<g class="style-scope yt-icon">
<path
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<yt-touch-feedback-shape style="border-radius: inherit">
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
>
<div class="yt-spec-touch-feedback-shape__stroke"></div>
<div class="yt-spec-touch-feedback-shape__fill"></div>
</div>
</yt-touch-feedback-shape>
</button>

View File

@ -0,0 +1,74 @@
<button
id="allundislike"
data-type="dislike"
data-filled="true"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Undislike all"
>
<div
class="yt-spec-button-shape-next__icon"
style="color: var(--ytmusic-setting-item-toggle-active)"
aria-hidden="true"
>
<div
class="yt-spec-button-shape-next__icon"
style="
color: white;
-webkit-mask: linear-gradient(grey, grey);
-webkit-mask-size: 100% 50%;
-webkit-mask-repeat: no-repeat;
z-index: 1;
position: absolute;
"
aria-hidden="true"
>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="
pointer-events: none;
display: block;
width: 100%;
height: 100%;
"
>
<g class="style-scope yt-icon">
<path
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="pointer-events: none; display: block; width: 100%; height: 100%"
>
<g class="style-scope yt-icon">
<path
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<yt-touch-feedback-shape style="border-radius: inherit">
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
>
<div class="yt-spec-touch-feedback-shape__stroke"></div>
<div class="yt-spec-touch-feedback-shape__fill"></div>
</div>
</yt-touch-feedback-shape>
</button>

View File

@ -0,0 +1,74 @@
<button
id="allunlike"
data-type="like"
data-filled="true"
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
aria-pressed="false"
aria-label="Unlike all"
>
<div
class="yt-spec-button-shape-next__icon"
style="color: var(--ytmusic-setting-item-toggle-active)"
aria-hidden="true"
>
<div
class="yt-spec-button-shape-next__icon"
style="
color: white;
-webkit-mask: linear-gradient(grey, grey);
-webkit-mask-size: 100% 50%;
-webkit-mask-repeat: no-repeat;
z-index: 1;
position: absolute;
"
aria-hidden="true"
>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="
pointer-events: none;
display: block;
width: 100%;
height: 100%;
"
>
<g class="style-scope yt-icon">
<path
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<div style="width: 24px; height: 24px">
<svg
viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet"
focusable="false"
class="style-scope yt-icon"
style="pointer-events: none; display: block; width: 100%; height: 100%"
>
<g class="style-scope yt-icon">
<path
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
class="style-scope yt-icon"
></path>
</g>
</svg>
</div>
</div>
<yt-touch-feedback-shape style="border-radius: inherit">
<div
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
aria-hidden="true"
>
<div class="yt-spec-touch-feedback-shape__stroke"></div>
<div class="yt-spec-touch-feedback-shape__fill"></div>
</div>
</yt-touch-feedback-shape>
</button>

View File

@ -1,94 +1,80 @@
import { FastAverageColor } from 'fast-average-color';
import Color from 'color';
import style from './style.css?inline';
import { createPlugin } from '@/utils';
import { t } from '@/i18n';
import type { VideoDataChanged } from '@/types/video-data-changed';
const COLOR_KEY = '--ytmusic-album-color';
const DARK_COLOR_KEY = '--ytmusic-album-color-dark';
const RATIO_KEY = '--ytmusic-album-color-ratio';
export default createPlugin({
export default createPlugin<
unknown,
unknown,
{
color?: Color;
darkColor?: Color;
playerPage: HTMLElement | null;
navBarBackground: HTMLElement | null;
ytmusicPlayerBar: HTMLElement | null;
playerBarBackground: HTMLElement | null;
sidebarBig: HTMLElement | null;
sidebarSmall: HTMLElement | null;
ytmusicAppLayout: HTMLElement | null;
getMixedColor(color: string, key: string, alpha?: number, ratioMultiply?: number): string;
updateColor(): void;
},
{
enabled: boolean;
ratio: number;
}
>({
name: () => t('plugins.album-color-theme.name'),
description: () => t('plugins.album-color-theme.description'),
restartNeeded: true,
restartNeeded: false,
config: {
enabled: false,
ratio: 0.5,
},
stylesheets: [style],
menu: async ({ getConfig, setConfig }) => {
const ratioList = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
const config = await getConfig();
return [
{
label: t('plugins.album-color-theme.menu.color-mix-ratio.label'),
submenu: ratioList.map((ratio) => ({
label: t(
'plugins.album-color-theme.menu.color-mix-ratio.submenu.percent',
{
ratio: ratio * 100,
},
),
type: 'radio',
checked: config.ratio === ratio,
click() {
setConfig({ ratio });
},
})),
},
];
},
renderer: {
hexToHSL: (H: string) => {
// Convert hex to RGB first
let r = 0;
let g = 0;
let b = 0;
if (H.length == 4) {
r = Number('0x' + H[1] + H[1]);
g = Number('0x' + H[2] + H[2]);
b = Number('0x' + H[3] + H[3]);
} else if (H.length == 7) {
r = Number('0x' + H[1] + H[2]);
g = Number('0x' + H[3] + H[4]);
b = Number('0x' + H[5] + H[6]);
}
// Then to HSL
r /= 255;
g /= 255;
b /= 255;
const cmin = Math.min(r, g, b);
const cmax = Math.max(r, g, b);
const delta = cmax - cmin;
let h: number;
let s: number;
let l: number;
playerPage: null,
navBarBackground: null,
ytmusicPlayerBar: null,
playerBarBackground: null,
sidebarBig: null,
sidebarSmall: null,
ytmusicAppLayout: null,
if (delta == 0) {
h = 0;
} else if (cmax == r) {
h = ((g - b) / delta) % 6;
} else if (cmax == g) {
h = ((b - r) / delta) + 2;
} else {
h = ((r - g) / delta) + 4;
}
h = Math.round(h * 60);
if (h < 0) {
h += 360;
}
l = (cmax + cmin) / 2;
s = delta == 0 ? 0 : delta / (1 - Math.abs((2 * l) - 1));
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
//return "hsl(" + h + "," + s + "%," + l + "%)";
return [h, s, l];
},
hue: 0,
saturation: 0,
lightness: 0,
changeElementColor: (
element: HTMLElement | null,
hue: number,
saturation: number,
lightness: number,
) => {
if (element) {
element.style.backgroundColor = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}
},
playerPage: null as HTMLElement | null,
navBarBackground: null as HTMLElement | null,
ytmusicPlayerBar: null as HTMLElement | null,
playerBarBackground: null as HTMLElement | null,
sidebarBig: null as HTMLElement | null,
sidebarSmall: null as HTMLElement | null,
ytmusicAppLayout: null as HTMLElement | null,
start() {
async start({ getConfig }) {
this.playerPage = document.querySelector<HTMLElement>('#player-page');
this.navBarBackground = document.querySelector<HTMLElement>(
'#nav-bar-background',
@ -104,112 +90,102 @@ export default createPlugin({
);
this.ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
const isPageOpen =
this.ytmusicAppLayout?.hasAttribute('player-page-open');
if (isPageOpen) {
this.changeElementColor(
this.sidebarSmall,
this.hue,
this.saturation,
this.lightness - 30,
);
} else {
if (this.sidebarSmall) {
this.sidebarSmall.style.backgroundColor = 'black';
}
}
}
}
});
if (this.playerPage) {
observer.observe(this.playerPage, { attributes: true });
}
const config = await getConfig();
document.documentElement.style.setProperty(RATIO_KEY, `${~~(config.ratio * 100)}%`);
},
onPlayerApiReady(playerApi) {
const fastAverageColor = new FastAverageColor();
document.addEventListener(
'videodatachange',
(event: CustomEvent<VideoDataChanged>) => {
if (event.detail.name === 'dataloaded') {
const playerResponse = playerApi.getPlayerResponse();
const thumbnail =
playerResponse?.videoDetails?.thumbnail?.thumbnails?.at(0);
if (thumbnail) {
fastAverageColor
.getColorAsync(thumbnail.url)
.then((albumColor) => {
if (albumColor) {
const [hue, saturation, lightness] = ([
this.hue,
this.saturation,
this.lightness,
] = this.hexToHSL(albumColor.hex));
this.changeElementColor(
this.playerPage,
hue,
saturation,
lightness - 30,
);
this.changeElementColor(
this.navBarBackground,
hue,
saturation,
lightness - 15,
);
this.changeElementColor(
this.ytmusicPlayerBar,
hue,
saturation,
lightness - 15,
);
this.changeElementColor(
this.playerBarBackground,
hue,
saturation,
lightness - 15,
);
this.changeElementColor(
this.sidebarBig,
hue,
saturation,
lightness - 15,
);
if (
this.ytmusicAppLayout?.hasAttribute('player-page-open')
) {
this.changeElementColor(
this.sidebarSmall,
hue,
saturation,
lightness - 30,
);
}
const ytRightClickList =
document.querySelector<HTMLElement>(
'tp-yt-paper-listbox',
);
this.changeElementColor(
ytRightClickList,
hue,
saturation,
lightness - 15,
);
} else {
if (this.playerPage) {
this.playerPage.style.backgroundColor = '#000000';
}
}
})
.catch((e) => console.error(e));
}
document.addEventListener('videodatachange', async (event) => {
if (event.detail.name !== 'dataloaded') return;
const playerResponse = playerApi.getPlayerResponse();
const thumbnail = playerResponse?.videoDetails?.thumbnail?.thumbnails?.at(0);
if (!thumbnail) return;
const albumColor = await fastAverageColor.getColorAsync(thumbnail.url)
.catch((err) => {
console.error(err);
return null;
});
if (albumColor) {
const target = Color(albumColor.hex);
this.darkColor = target.darken(0.3).rgb();
this.color = target.darken(0.15).rgb();
while (this.color.luminosity() > 0.5) {
this.color = this.color?.darken(0.05);
this.darkColor = this.darkColor?.darken(0.05);
}
},
);
document.documentElement.style.setProperty(COLOR_KEY, `${~~this.color.red()}, ${~~this.color.green()}, ${~~this.color.blue()}`);
document.documentElement.style.setProperty(DARK_COLOR_KEY, `${~~this.darkColor.red()}, ${~~this.darkColor.green()}, ${~~this.darkColor.blue()}`);
} else {
document.documentElement.style.setProperty(COLOR_KEY, '0, 0, 0');
document.documentElement.style.setProperty(DARK_COLOR_KEY, '0, 0, 0');
}
this.updateColor();
});
},
onConfigChange(config) {
document.documentElement.style.setProperty(RATIO_KEY, `${~~(config.ratio * 100)}%`);
},
getMixedColor(color: string, key: string, alpha = 1, ratioMultiply) {
const keyColor = `rgba(var(${key}), ${alpha})`;
let colorRatio = `var(${RATIO_KEY}, 50%)`;
let originalRatio = `calc(100% - var(${RATIO_KEY}, 50%))`;
if (ratioMultiply) {
colorRatio = `calc(var(${RATIO_KEY}, 50%) * ${ratioMultiply})`;
originalRatio = `calc(100% - calc(var(${RATIO_KEY}, 50%) * ${ratioMultiply}))`;
}
return `color-mix(in srgb, ${color} ${originalRatio}, ${keyColor} ${colorRatio})`;
},
updateColor() {
const variableMap = {
'--ytmusic-color-black1': '#212121',
'--ytmusic-color-black2': '#181818',
'--ytmusic-color-black3': '#030303',
'--ytmusic-color-black4': '#030303',
'--ytmusic-color-blackpure': '#000',
'--dark-theme-background-color': '#212121',
'--yt-spec-base-background': '#0f0f0f',
'--yt-spec-raised-background': '#212121',
'--yt-spec-menu-background': '#282828',
'--yt-spec-static-brand-black': '#212121',
'--yt-spec-static-overlay-background-solid': '#000',
'--yt-spec-static-overlay-background-heavy': 'rgba(0,0,0,0.8)',
'--yt-spec-static-overlay-background-medium': 'rgba(0,0,0,0.6)',
'--yt-spec-static-overlay-background-medium-light': 'rgba(0,0,0,0.3)',
'--yt-spec-static-overlay-background-light': 'rgba(0,0,0,0.1)',
'--yt-spec-general-background-a': '#181818',
'--yt-spec-general-background-b': '#0f0f0f',
'--yt-spec-general-background-c': '#030303',
'--yt-spec-snackbar-background': '#030303',
'--yt-spec-filled-button-text': '#030303',
'--yt-spec-black-1': '#282828',
'--yt-spec-black-2': '#1f1f1f',
'--yt-spec-black-3': '#161616',
'--yt-spec-black-4': '#0d0d0d',
'--yt-spec-black-pure': '#000',
'--yt-spec-black-pure-alpha-5': 'rgba(0,0,0,0.05)',
'--yt-spec-black-pure-alpha-10': 'rgba(0,0,0,0.1)',
'--yt-spec-black-pure-alpha-15': 'rgba(0,0,0,0.15)',
'--yt-spec-black-pure-alpha-30': 'rgba(0,0,0,0.3)',
'--yt-spec-black-pure-alpha-60': 'rgba(0,0,0,0.6)',
'--yt-spec-black-pure-alpha-80': 'rgba(0,0,0,0.8)',
'--yt-spec-black-1-alpha-98': 'rgba(40,40,40,0.98)',
'--yt-spec-black-1-alpha-95': 'rgba(40,40,40,0.95)',
};
Object.entries(variableMap).map(([variable, color]) => {
document.documentElement.style.setProperty(variable, this.getMixedColor(color, COLOR_KEY), 'important');
});
document.body.style.setProperty('background', this.getMixedColor('#030303', COLOR_KEY), 'important');
document.documentElement.style.setProperty('--ytmusic-background', this.getMixedColor('#030303', DARK_COLOR_KEY), 'important');
},
},
});

View File

@ -4,28 +4,24 @@ yt-page-navigation-progress {
}
#player-page {
transition:
transform 300ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
transition: transform 300ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
}
#nav-bar-background {
transition:
opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
transition: opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
}
#mini-guide-background {
transition:
opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
transition: opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
border-right: 0px !important;
}
#guide-wrapper {
transition:
opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
transition: opacity 200ms,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) !important;
}
#img,
@ -37,3 +33,57 @@ yt-page-navigation-progress {
#items {
border-radius: 10px !important;
}
/* fix blur navigation bar */
ytmusic-app-layout > [slot='player-page'] {
padding-top: 90px;
margin-top: calc(-90px + var(--menu-bar-height, 0px)) !important;
}
/* fix icon color */
.duration.ytmusic-player-queue-item, .byline.ytmusic-player-queue-item {
color: rgba(255, 255, 255, 0.5) !important;
--yt-endpoint-color: rgba(255, 255, 255, 0.5) !important;
--yt-endpoint-hover-color: rgba(255, 255, 255, 0.5) !important;
--yt-endpoint-visited-color: rgba(255, 255, 255, 0.5) !important;
}
.icon.ytmusic-menu-navigation-item-renderer {
color: rgba(255, 255, 255, 0.5) !important;
}
.menu.ytmusic-player-bar {
--iron-icon-fill-color: rgba(255, 255, 255, 0.5) !important;
}
ytmusic-player-bar {
color: rgba(255, 255, 255, 0.5) !important;
}
.time-info.ytmusic-player-bar {
color: rgba(255, 255, 255, 0.5) !important;
}
.volume-slider.ytmusic-player-bar, .expand-volume-slider.ytmusic-player-bar {
--paper-slider-container-color: rgba(255, 255, 255, 0.5) !important;
}
/* fix background image */
ytmusic-fullbleed-thumbnail-renderer img {
mask: linear-gradient(to bottom, #000 0%, #000 50%, transparent 100%);
}
.background-gradient.style-scope,
ytmusic-app-layout[is-bauhaus-sidenav-enabled] #mini-guide-background.ytmusic-app-layout {
background: var(--ytmusic-background) !important;
}
ytmusic-browse-response[has-background]:not([disable-gradient]) .background-gradient.ytmusic-browse-response {
background: unset !important;
}
#background.immersive-background.style-scope.ytmusic-browse-response {
opacity: 0.6;
}

View File

@ -1,18 +1,10 @@
import style from './style.css?inline';
import { createPlugin } from '@/utils';
import { t } from '@/i18n';
import { createPlugin } from '@/utils';
import { menu } from './menu';
import { AmbientModePluginConfig } from './types';
export type AmbientModePluginConfig = {
enabled: boolean;
quality: number;
buffer: number;
interpolationTime: number;
blur: number;
size: number;
opacity: number;
fullscreen: boolean;
};
const defaultConfig: AmbientModePluginConfig = {
enabled: false,
quality: 50,
@ -30,138 +22,78 @@ export default createPlugin({
restartNeeded: false,
config: defaultConfig,
stylesheets: [style],
menu: async ({ getConfig, setConfig }) => {
const interpolationTimeList = [0, 500, 1000, 1500, 2000, 3000, 4000, 5000];
const qualityList = [10, 25, 50, 100, 200, 500, 1000];
const sizeList = [100, 110, 125, 150, 175, 200, 300];
const bufferList = [1, 5, 10, 20, 30];
const blurAmountList = [0, 5, 10, 25, 50, 100, 150, 200, 500];
const opacityList = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
const config = await getConfig();
return [
{
label: t('plugins.ambient-mode.menu.smoothness-transition.label'),
submenu: interpolationTimeList.map((interpolationTime) => ({
label: t(
'plugins.ambient-mode.menu.smoothness-transition.submenu.during',
{
interpolationTime: interpolationTime / 1000,
},
),
type: 'radio',
checked: config.interpolationTime === interpolationTime,
click() {
setConfig({ interpolationTime });
},
})),
},
{
label: t('plugins.ambient-mode.menu.quality.label'),
submenu: qualityList.map((quality) => ({
label: t('plugins.ambient-mode.menu.quality.submenu.pixels', {
quality,
}),
type: 'radio',
checked: config.quality === quality,
click() {
setConfig({ quality });
},
})),
},
{
label: t('plugins.ambient-mode.menu.size.label'),
submenu: sizeList.map((size) => ({
label: t('plugins.ambient-mode.menu.size.submenu.percent', { size }),
type: 'radio',
checked: config.size === size,
click() {
setConfig({ size });
},
})),
},
{
label: t('plugins.ambient-mode.menu.buffer.label'),
submenu: bufferList.map((buffer) => ({
label: t('plugins.ambient-mode.menu.buffer.submenu.buffer', {
buffer,
}),
type: 'radio',
checked: config.buffer === buffer,
click() {
setConfig({ buffer });
},
})),
},
{
label: t('plugins.ambient-mode.menu.opacity.label'),
submenu: opacityList.map((opacity) => ({
label: t('plugins.ambient-mode.menu.opacity.submenu.percent', {
opacity: opacity * 100,
}),
type: 'radio',
checked: config.opacity === opacity,
click() {
setConfig({ opacity });
},
})),
},
{
label: t('plugins.ambient-mode.menu.blur-amount.label'),
submenu: blurAmountList.map((blur) => ({
label: t('plugins.ambient-mode.menu.blur-amount.submenu.pixels', {
blurAmount: blur,
}),
type: 'radio',
checked: config.blur === blur,
click() {
setConfig({ blur });
},
})),
},
{
label: t('plugins.ambient-mode.menu.use-fullscreen.label'),
type: 'checkbox',
checked: config.fullscreen,
click(item) {
setConfig({ fullscreen: item.checked });
},
},
];
},
menu: menu,
renderer: {
interpolationTime: defaultConfig.interpolationTime,
buffer: defaultConfig.buffer,
qualityRatio: defaultConfig.quality,
sizeRatio: defaultConfig.size / 100,
size: defaultConfig.size,
blur: defaultConfig.blur,
opacity: defaultConfig.opacity,
isFullscreen: defaultConfig.fullscreen,
unregister: null as (() => void) | null,
update: null as (() => void) | null,
observer: null as MutationObserver | null,
interval: null as NodeJS.Timeout | null,
lastMediaType: null as "video" | "image" | null,
lastVideoSource: null as string | null,
lastImageSource: null as string | null,
start() {
const injectBlurVideo = (): (() => void) | null => {
const songVideo = document.querySelector<HTMLDivElement>('#song-video');
const video = document.querySelector<HTMLVideoElement>(
'#song-video .html5-video-container > video',
);
const wrapper = document.querySelector('#song-video > .player-wrapper');
async start({ getConfig }) {
const config = await getConfig();
this.interpolationTime = config.interpolationTime;
this.buffer = config.buffer;
this.qualityRatio = config.quality;
this.size = config.size;
this.blur = config.blur;
this.opacity = config.opacity;
this.isFullscreen = config.fullscreen;
if (!songVideo) return null;
if (!video) return null;
if (!wrapper) return null;
const songImage = document.querySelector<HTMLImageElement>('#song-image');
const songVideo = document.querySelector<HTMLDivElement>('#song-video');
const image = songImage?.querySelector<HTMLImageElement>('yt-img-shadow > img');
const video = songVideo?.querySelector<HTMLVideoElement>('.html5-video-container > video');
const videoWrapper = document.querySelector('#song-video > .player-wrapper');
const injectBlurImage = () => {
if (!songImage || !image) return null;
this.lastImageSource = image.src;
const blurImage = document.createElement('img');
blurImage.classList.add('html5-blur-image');
blurImage.src = image.src;
this.update = () => {
if (this.isFullscreen) blurImage.classList.add('fullscreen');
else blurImage.classList.remove('fullscreen');
blurImage.style.setProperty('--width', `${this.size}%`);
blurImage.style.setProperty('--height', `${this.size}%`);
blurImage.style.setProperty('--blur', `${this.blur}px`);
blurImage.style.setProperty('--opacity', `${this.opacity}`);
};
this.update();
/* injecting */
songImage.prepend(blurImage);
/* cleanup */
return () => {
if (blurImage.isConnected) blurImage.remove();
};
};
const injectBlurVideo = () => {
if (!songVideo || !video || !videoWrapper) return null;
this.lastVideoSource = video.src;
const blurCanvas = document.createElement('canvas');
blurCanvas.classList.add('html5-blur-canvas');
const context = blurCanvas.getContext('2d', {
willReadFrequently: true,
});
const context = blurCanvas.getContext('2d', { willReadFrequently: true });
/* effect */
let lastEffectWorkId: number | null = null;
@ -172,21 +104,16 @@ export default createPlugin({
cancelAnimationFrame(lastEffectWorkId);
lastEffectWorkId = requestAnimationFrame(() => {
// console.log('context', context);
if (!context) return;
const width = this.qualityRatio;
let height = Math.max(
Math.floor((blurCanvas.height / blurCanvas.width) * width),
1,
);
let height = Math.max(Math.floor((blurCanvas.height / blurCanvas.width) * width), 1,);
if (!Number.isFinite(height)) height = width;
if (!height) return;
context.globalAlpha = 1;
if (lastImageData) {
const frameOffset =
(1 / this.buffer) * (1000 / this.interpolationTime);
const frameOffset = (1 / this.buffer) * (1000 / this.interpolationTime);
context.globalAlpha = 1 - (frameOffset * 2); // because of alpha value must be < 1
context.putImageData(lastImageData, 0, 0);
context.globalAlpha = frameOffset;
@ -199,7 +126,7 @@ export default createPlugin({
});
};
const applyVideoAttributes = () => {
this.update = () => {
const rect = video.getBoundingClientRect();
const newWidth = Math.floor(video.width || rect.width);
@ -208,45 +135,21 @@ export default createPlugin({
if (newWidth === 0 || newHeight === 0) return;
blurCanvas.width = this.qualityRatio;
blurCanvas.height = Math.floor(
(newHeight / newWidth) * this.qualityRatio,
);
blurCanvas.style.width = `${newWidth * this.sizeRatio}px`;
blurCanvas.style.height = `${newHeight * this.sizeRatio}px`;
blurCanvas.height = Math.floor((newHeight / newWidth) * this.qualityRatio);
if (this.isFullscreen) blurCanvas.classList.add('fullscreen');
else blurCanvas.classList.remove('fullscreen');
const leftOffset = (newWidth * (this.sizeRatio - 1)) / 2;
const topOffset = (newHeight * (this.sizeRatio - 1)) / 2;
blurCanvas.style.setProperty('--left', `${-1 * leftOffset}px`);
blurCanvas.style.setProperty('--top', `${-1 * topOffset}px`);
blurCanvas.style.setProperty('--width', `${this.size}%`);
blurCanvas.style.setProperty('--height', `${this.size}%`);
blurCanvas.style.setProperty('--blur', `${this.blur}px`);
blurCanvas.style.setProperty('--opacity', `${this.opacity}`);
};
this.update = applyVideoAttributes;
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes') {
applyVideoAttributes();
}
});
});
const resizeObserver = new ResizeObserver(() => {
applyVideoAttributes();
});
this.update();
/* hooking */
let canvasInterval: NodeJS.Timeout | null = null;
canvasInterval = setInterval(
onSync,
Math.max(1, Math.ceil(1000 / this.buffer)),
);
applyVideoAttributes();
observer.observe(songVideo, { attributes: true });
resizeObserver.observe(songVideo);
window.addEventListener('resize', applyVideoAttributes);
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / this.buffer)));
const onPause = () => {
if (canvasInterval) clearInterval(canvasInterval);
@ -254,16 +157,13 @@ export default createPlugin({
};
const onPlay = () => {
if (canvasInterval) clearInterval(canvasInterval);
canvasInterval = setInterval(
onSync,
Math.max(1, Math.ceil(1000 / this.buffer)),
);
canvasInterval = setInterval(onSync, Math.max(1, Math.ceil(1000 / this.buffer)));
};
songVideo.addEventListener('pause', onPause);
songVideo.addEventListener('play', onPlay);
/* injecting */
wrapper.prepend(blurCanvas);
videoWrapper.prepend(blurCanvas);
/* cleanup */
return () => {
@ -272,48 +172,63 @@ export default createPlugin({
songVideo.removeEventListener('pause', onPause);
songVideo.removeEventListener('play', onPlay);
observer.disconnect();
resizeObserver.disconnect();
window.removeEventListener('resize', applyVideoAttributes);
if (blurCanvas.isConnected) blurCanvas.remove();
};
};
const isVideoMode = () => {
const songVideo = document.querySelector<HTMLDivElement>('#song-video');
if (!songVideo) {
this.lastMediaType = "image";
return false;
}
const isVideo = getComputedStyle(songVideo).display !== 'none';
this.lastMediaType = isVideo ? "video" : "image";
return isVideo;
};
const playerPage = document.querySelector<HTMLElement>('#player-page');
const ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
const isPageOpen = ytmusicAppLayout?.hasAttribute('player-page-open');
if (isPageOpen) {
this.unregister?.();
this.unregister = injectBlurVideo() ?? null;
const injectBlurElement = (force?: boolean): boolean | void => {
const isPageOpen = ytmusicAppLayout?.hasAttribute('player-page-open');
if (isPageOpen) {
const isVideo = isVideoMode();
if (!force) {
if (this.lastMediaType === "video" && this.lastVideoSource === video?.src) return false;
if (this.lastMediaType === "image" && this.lastImageSource === image?.src) return false;
}
this.unregister?.();
this.unregister = (isVideo ? injectBlurVideo() : injectBlurImage()) ?? null;
} else {
this.unregister?.();
this.unregister = null;
}
}
/* needed for switching between different views (e.g. miniplayer) */
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'attributes') {
const isPageOpen =
ytmusicAppLayout?.hasAttribute('player-page-open');
if (isPageOpen) {
this.unregister?.();
this.unregister = injectBlurVideo() ?? null;
} else {
this.unregister?.();
this.unregister = null;
}
injectBlurElement(true);
break;
}
}
});
if (playerPage) {
observer.observe(playerPage, { attributes: true });
/* fallback ticker for when the observer isn't triggered */
this.interval = setInterval(injectBlurElement, 1000);
}
},
onConfigChange(newConfig) {
this.interpolationTime = newConfig.interpolationTime;
this.buffer = newConfig.buffer;
this.qualityRatio = newConfig.quality;
this.sizeRatio = newConfig.size / 100;
this.size = newConfig.size;
this.blur = newConfig.blur;
this.opacity = newConfig.opacity;
this.isFullscreen = newConfig.fullscreen;
@ -321,9 +236,9 @@ export default createPlugin({
this.update?.();
},
stop() {
this.observer?.disconnect();
this.update = null;
this.unregister?.();
if (this.interval) clearInterval(this.interval);
},
},
});

View File

@ -0,0 +1,110 @@
import { t } from "@/i18n";
import { MenuContext } from "@/types/contexts";
import { MenuItemConstructorOptions } from "electron";
import { AmbientModePluginConfig } from "./types";
export interface menuParameters {
getConfig: () => AmbientModePluginConfig | Promise<AmbientModePluginConfig>;
setConfig: (conf: Partial<Omit<AmbientModePluginConfig, "enabled">>) => void | Promise<void>;
}
export const menu: (ctx: MenuContext<AmbientModePluginConfig>) => MenuItemConstructorOptions[] | Promise<MenuItemConstructorOptions[]> = async ({ getConfig, setConfig }: menuParameters) => {
const interpolationTimeList = [0, 500, 1000, 1500, 2000, 3000, 4000, 5000];
const qualityList = [10, 25, 50, 100, 200, 500, 1000];
const sizeList = [100, 110, 125, 150, 175, 200, 300];
const bufferList = [1, 5, 10, 20, 30];
const blurAmountList = [0, 5, 10, 25, 50, 100, 150, 200, 500];
const opacityList = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
const config = await getConfig();
return [
{
label: t('plugins.ambient-mode.menu.smoothness-transition.label'),
submenu: interpolationTimeList.map((interpolationTime) => ({
label: t(
'plugins.ambient-mode.menu.smoothness-transition.submenu.during',
{
interpolationTime: interpolationTime / 1000,
},
),
type: 'radio',
checked: config.interpolationTime === interpolationTime,
click() {
setConfig({ interpolationTime });
},
})),
},
{
label: t('plugins.ambient-mode.menu.quality.label'),
submenu: qualityList.map((quality) => ({
label: t('plugins.ambient-mode.menu.quality.submenu.pixels', {
quality,
}),
type: 'radio',
checked: config.quality === quality,
click() {
setConfig({ quality });
},
})),
},
{
label: t('plugins.ambient-mode.menu.size.label'),
submenu: sizeList.map((size) => ({
label: t('plugins.ambient-mode.menu.size.submenu.percent', { size }),
type: 'radio',
checked: config.size === size,
click() {
setConfig({ size });
},
})),
},
{
label: t('plugins.ambient-mode.menu.buffer.label'),
submenu: bufferList.map((buffer) => ({
label: t('plugins.ambient-mode.menu.buffer.submenu.buffer', {
buffer,
}),
type: 'radio',
checked: config.buffer === buffer,
click() {
setConfig({ buffer });
},
})),
},
{
label: t('plugins.ambient-mode.menu.opacity.label'),
submenu: opacityList.map((opacity) => ({
label: t('plugins.ambient-mode.menu.opacity.submenu.percent', {
opacity: opacity * 100,
}),
type: 'radio',
checked: config.opacity === opacity,
click() {
setConfig({ opacity });
},
})),
},
{
label: t('plugins.ambient-mode.menu.blur-amount.label'),
submenu: blurAmountList.map((blur) => ({
label: t('plugins.ambient-mode.menu.blur-amount.submenu.pixels', {
blurAmount: blur,
}),
type: 'radio',
checked: config.blur === blur,
click() {
setConfig({ blur });
},
})),
},
{
label: t('plugins.ambient-mode.menu.use-fullscreen.label'),
type: 'checkbox',
checked: config.fullscreen,
click(item: Electron.MenuItem) {
setConfig({ fullscreen: item.checked });
},
},
];
}

View File

@ -1,26 +1,36 @@
#song-video canvas.html5-blur-canvas {
#song-video canvas.html5-blur-canvas,
#song-image .html5-blur-image {
filter: blur(var(--blur, 100px));
opacity: var(--opacity, 1);
width: var(--width, 100%);
height: var(--height, 100%);
pointer-events: none;
}
#song-video canvas.html5-blur-canvas:not(.fullscreen) {
#song-video canvas.html5-blur-canvas:not(.fullscreen),
#song-image .html5-blur-image {
position: absolute;
left: var(--left, 0px);
top: var(--top, 0px);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
#song-video canvas.html5-blur-canvas.fullscreen {
position: fixed;
left: 0;
top: 0;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
width: 100%;
height: 100%;
}
#song-video .html5-video-container > video {
top: 0 !important;
#song-video .html5-video-container {
height: 100%;
}
#player:not([video-mode]):not(.video-mode):not([player-ui-state='MINIPLAYER']) {
width: 100%;
margin: 0 auto !important;
overflow: visible;
}

View File

@ -0,0 +1,10 @@
export type AmbientModePluginConfig = {
enabled: boolean;
quality: number;
buffer: number;
interpolationTime: number;
blur: number;
size: number;
opacity: number;
fullscreen: boolean;
};

View File

@ -7,7 +7,7 @@ export default createPlugin({
renderer() {
document.addEventListener(
'audioCanPlay',
'ytmd:audio-can-play',
({ detail: { audioSource, audioContext } }) => {
const compressor = audioContext.createDynamicsCompressor();

View File

@ -1,11 +1,24 @@
import { createPlugin } from '@/utils';
import style from './style.css?inline';
import { t } from '@/i18n';
import style from './style.css?inline';
export default createPlugin({
name: () => t('plugins.blur-nav-bar.name'),
description: () => t('plugins.blur-nav-bar.description'),
restartNeeded: true,
stylesheets: [style],
renderer() {},
restartNeeded: false,
renderer: {
styleSheet: null as CSSStyleSheet | null,
async start() {
this.styleSheet = new CSSStyleSheet();
await this.styleSheet.replace(style);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, this.styleSheet];
},
async stop() {
await this.styleSheet?.replace('');
},
},
});

View File

@ -1,10 +1,18 @@
#nav-bar-background,
#header.ytmusic-item-section-renderer,
ytmusic-tabs {
#header.ytmusic-item-section-renderer {
background: rgba(0, 0, 0, 0.3) !important;
backdrop-filter: blur(8px) !important;
}
ytmusic-tabs {
top: calc(var(--ytmusic-nav-bar-height) + var(--menu-bar-height, 36px));
backdrop-filter: blur(8px) !important;
}
ytmusic-tabs.stuck {
background: rgba(0, 0, 0, 0.3) !important;
}
#nav-bar-divider {
display: none !important;
}

View File

@ -121,7 +121,7 @@ export default createRenderer<
?.unloadModule('captions');
document
.querySelector('video')
?.removeEventListener('srcChanged', this.videoChangeListener);
?.removeEventListener('ytmd:src-changed', this.videoChangeListener);
this.captionsSettingsButton.removeEventListener(
'click',
this.captionsButtonClickListener,
@ -139,7 +139,7 @@ export default createRenderer<
document
.querySelector('video')
?.addEventListener('srcChanged', this.videoChangeListener);
?.addEventListener('ytmd:src-changed', this.videoChangeListener);
this.captionsSettingsButton.addEventListener(
'click',
this.captionsButtonClickListener,

View File

@ -26,8 +26,8 @@ export default createPlugin<
unknown,
unknown,
{
config: CrossfadePluginConfig | null;
ipc: RendererContext<CrossfadePluginConfig>['ipc'] | null;
config?: CrossfadePluginConfig;
ipc?: RendererContext<CrossfadePluginConfig>['ipc'];
},
CrossfadePluginConfig
>({
@ -178,10 +178,8 @@ export default createPlugin<
},
renderer: {
config: null,
ipc: null,
start({ ipc }) {
async start({ ipc, getConfig }) {
this.config = await getConfig();
this.ipc = ipc;
},
onConfigChange(newConfig) {
@ -271,7 +269,7 @@ export default createPlugin<
const transitionBeforeEnd = () => {
if (
video.currentTime >=
video.duration - this.config!.secondsBeforeEnd &&
video.duration - (this.config?.secondsBeforeEnd ?? 0) &&
isReadyToCrossfade()
) {
video.removeEventListener('timeupdate', transitionBeforeEnd);

View File

@ -2,14 +2,12 @@ import { app, dialog, ipcMain } from 'electron';
import { Client as DiscordClient } from '@xhayper/discord-rpc';
import { dev } from 'electron-is';
import { SetActivity } from '@xhayper/discord-rpc/dist/structures/ClientUser';
import registerCallback, { type SongInfo } from '@/providers/song-info';
import { createBackend, LoggerPrefix } from '@/utils';
import { t } from '@/i18n';
import type { GatewayActivityButton } from 'discord-api-types/v10';
import type { SetActivity } from '@xhayper/discord-rpc/dist/structures/ClientUser';
import type { DiscordPluginConfig } from './index';
// Application ID registered by @th-ch/youtube-music dev team
@ -163,24 +161,30 @@ export const backend = createBackend<
);
}
// see https://github.com/th-ch/youtube-music/issues/1664
let buttons: GatewayActivityButton[] | undefined = [];
if (config.playOnYouTubeMusic) {
buttons.push({
label: 'Play on YouTube Music',
url: songInfo.url ?? 'https://music.youtube.com',
});
}
if (!config.hideGitHubButton) {
buttons.push({
label: 'View App On GitHub',
url: 'https://github.com/th-ch/youtube-music',
});
}
if (buttons.length === 0) {
buttons = undefined;
}
const activityInfo: SetActivity = {
details: songInfo.title,
state: songInfo.artist,
largeImageKey: songInfo.imageSrc ?? '',
largeImageText: songInfo.album ?? '',
buttons: [
...(config.playOnYouTubeMusic
? [{ label: 'Play on YouTube Music', url: songInfo.url ?? '' }]
: []),
...(config.hideGitHubButton
? []
: [
{
label: 'View App On GitHub',
url: 'https://github.com/th-ch/youtube-music',
},
]),
],
buttons,
};
if (songInfo.isPaused) {
@ -244,7 +248,7 @@ export const backend = createBackend<
});
connect();
let lastSent = Date.now();
ipcMain.on('timeChanged', (_, t: number) => {
ipcMain.on('ytmd:time-changed', (_, t: number) => {
const currentTime = Date.now();
// if lastSent is more than 5 seconds ago, send the new time
if (currentTime - lastSent > 5000) {

View File

@ -84,7 +84,7 @@ export const onMenu = async ({
checked: config.hideDurationLeft,
click(item: Electron.MenuItem) {
setConfig({
hideGitHubButton: item.checked,
hideDurationLeft: item.checked,
});
},
},

View File

@ -1,5 +1,4 @@
import {
createWriteStream,
existsSync,
mkdirSync,
writeFileSync,
@ -30,9 +29,8 @@ import {
import { fetchFromGenius } from '@/plugins/lyrics-genius/main';
import { isEnabled } from '@/config/plugins';
import { cleanupName, getImage, SongInfo } from '@/providers/song-info';
import { cleanupName, getImage, MediaType, type SongInfo } from '@/providers/song-info';
import { getNetFetchAsFetch } from '@/plugins/utils/main';
import { cache } from '@/providers/decorators';
import { t } from '@/i18n';
@ -110,7 +108,7 @@ export const onMainLoad = async ({
fetch: getNetFetchAsFetch(),
});
ipc.handle('download-song', (url: string) => downloadSong(url));
ipc.on('video-src-changed', (data: GetPlayerResponse) => {
ipc.on('ytmd:video-src-changed', (data: GetPlayerResponse) => {
playingUrl = data.microformat.microformatDataRenderer.urlCanonical;
});
ipc.handle('download-playlist-request', async (url: string) =>
@ -297,7 +295,7 @@ async function downloadSongUnsafe(
mkdirSync(dir);
}
const fileBuffer = await iterableStreamToTargetFile(
let fileBuffer = await iterableStreamToProcessedUint8Array(
iterableStream,
targetFileExtension,
metadata,
@ -307,19 +305,16 @@ async function downloadSongUnsafe(
increasePlaylistProgress,
);
if (fileBuffer && targetFileExtension === 'mp3') {
fileBuffer = await writeID3(
Buffer.from(fileBuffer),
metadata,
sendFeedback,
);
}
if (fileBuffer) {
if (targetFileExtension !== 'mp3') {
createWriteStream(filePath).write(fileBuffer);
} else {
const buffer = await writeID3(
Buffer.from(fileBuffer),
metadata,
sendFeedback,
);
if (buffer) {
writeFileSync(filePath, buffer);
}
}
writeFileSync(filePath, fileBuffer);
}
sendFeedback(null, -1);
@ -330,15 +325,12 @@ async function downloadSongUnsafe(
);
}
async function iterableStreamToTargetFile(
async function downloadChunks(
stream: AsyncGenerator<Uint8Array, void>,
extension: string,
metadata: CustomSongInfo,
presetFfmpegArgs: string[],
contentLength: number,
sendFeedback: (str: string, value?: number) => void,
increasePlaylistProgress: (value: number) => void = () => {},
): Promise<Uint8Array | null> {
) {
const chunks = [];
let downloaded = 0;
for await (const chunk of stream) {
@ -356,65 +348,80 @@ async function iterableStreamToTargetFile(
// This is a very rough estimate, trying to make the progress bar look nice
increasePlaylistProgress(ratio * 0.15);
}
sendFeedback(t('plugins.downloader.backend.feedback.loading'), 2); // Indefinite progress bar after download
const buffer = Buffer.concat(chunks);
const safeVideoName = randomBytes(32).toString('hex');
const releaseFFmpegMutex = await ffmpegMutex.acquire();
try {
if (!ffmpeg.isLoaded()) {
await ffmpeg.load();
}
sendFeedback(t('plugins.downloader.backend.feedback.preparing-file'));
ffmpeg.FS('writeFile', safeVideoName, buffer);
sendFeedback(t('plugins.downloader.backend.feedback.converting'));
ffmpeg.setProgress(({ ratio }) => {
sendFeedback(
t('plugins.downloader.backend.feedback.conversion-progress', {
percent: Math.floor(ratio * 100),
}),
ratio,
);
increasePlaylistProgress(0.15 + (ratio * 0.85));
});
const safeVideoNameWithExtension = `${safeVideoName}.${extension}`;
try {
await ffmpeg.run(
'-i',
safeVideoName,
...presetFfmpegArgs,
...getFFmpegMetadataArgs(metadata),
safeVideoNameWithExtension,
);
} finally {
ffmpeg.FS('unlink', safeVideoName);
}
sendFeedback(t('plugins.downloader.backend.feedback.saving'));
try {
return ffmpeg.FS('readFile', safeVideoNameWithExtension);
} finally {
ffmpeg.FS('unlink', safeVideoNameWithExtension);
}
} catch (error: unknown) {
sendError(error as Error, safeVideoName);
} finally {
releaseFFmpegMutex();
}
return null;
return chunks;
}
const getCoverBuffer = cache(async (url: string) => {
async function iterableStreamToProcessedUint8Array(
stream: AsyncGenerator<Uint8Array, void>,
extension: string,
metadata: CustomSongInfo,
presetFfmpegArgs: string[],
contentLength: number,
sendFeedback: (str: string, value?: number) => void,
increasePlaylistProgress: (value: number) => void = () => {},
): Promise<Uint8Array | null> {
sendFeedback(t('plugins.downloader.backend.feedback.loading'), 2); // Indefinite progress bar after download
const safeVideoName = randomBytes(32).toString('hex');
return await ffmpegMutex.runExclusive(async () => {
try {
if (!ffmpeg.isLoaded()) {
await ffmpeg.load();
}
sendFeedback(t('plugins.downloader.backend.feedback.preparing-file'));
ffmpeg.FS(
'writeFile',
safeVideoName,
Buffer.concat(
await downloadChunks(stream, contentLength, sendFeedback, increasePlaylistProgress),
),
);
sendFeedback(t('plugins.downloader.backend.feedback.converting'));
ffmpeg.setProgress(({ ratio }) => {
sendFeedback(
t('plugins.downloader.backend.feedback.conversion-progress', {
percent: Math.floor(ratio * 100),
}),
ratio,
);
increasePlaylistProgress(0.15 + (ratio * 0.85));
});
const safeVideoNameWithExtension = `${safeVideoName}.${extension}`;
try {
await ffmpeg.run(
'-i',
safeVideoName,
...presetFfmpegArgs,
...getFFmpegMetadataArgs(metadata),
safeVideoNameWithExtension,
);
} finally {
ffmpeg.FS('unlink', safeVideoName);
}
sendFeedback(t('plugins.downloader.backend.feedback.saving'));
try {
return ffmpeg.FS('readFile', safeVideoNameWithExtension);
} finally {
ffmpeg.FS('unlink', safeVideoNameWithExtension);
}
} catch (error: unknown) {
sendError(error as Error, safeVideoName);
}
return null;
});
}
const getCoverBuffer = async (url: string) => {
const nativeImage = cropMaxWidth(await getImage(url));
return nativeImage && !nativeImage.isEmpty() ? nativeImage.toPNG() : null;
});
};
async function writeID3(
buffer: Buffer,
@ -686,6 +693,7 @@ const getMetadata = (info: TrackInfo): CustomSongInfo => ({
?.url,
views: info.basic_info.view_count!,
songDuration: info.basic_info.duration!,
mediaType: MediaType.Audio,
});
// This is used to bypass age restrictions

View File

@ -32,38 +32,63 @@ const menuObserver = new MutationObserver(() => {
return;
}
const menuUrl = document.querySelector<HTMLAnchorElement>(
'tp-yt-paper-listbox [tabindex="-1"] #navigation-endpoint',
// check for video (or music)
let menuUrl = document.querySelector<HTMLAnchorElement>(
'tp-yt-paper-listbox [tabindex="0"] #navigation-endpoint',
)?.href;
if (!menuUrl?.includes('watch?') && doneFirstLoad) {
if (!menuUrl?.includes('watch?')) {
menuUrl = undefined;
// check for podcast
for (const it of document.querySelectorAll('tp-yt-paper-listbox [tabindex="-1"] #navigation-endpoint')) {
if (it.getAttribute('href')?.includes('podcast/')) {
menuUrl = it.getAttribute('href')!;
break;
}
}
}
if (!menuUrl && doneFirstLoad) {
return;
}
menu.prepend(downloadButton);
progress = document.querySelector('#ytmcustom-download');
if (doneFirstLoad) {
return;
if (!doneFirstLoad) {
setTimeout(() => (doneFirstLoad ||= true), 500);
}
setTimeout(() => (doneFirstLoad ||= true), 500);
});
export const onRendererLoad = ({
ipc,
}: RendererContext<DownloaderPluginConfig>) => {
window.download = () => {
let videoUrl = getSongMenu()
const songMenu = getSongMenu();
let videoUrl = songMenu
// Selector of first button which is always "Start Radio"
?.querySelector(
'ytmusic-menu-navigation-item-renderer[tabindex="-1"] #navigation-endpoint',
'ytmusic-menu-navigation-item-renderer[tabindex="0"] #navigation-endpoint',
)
?.getAttribute('href');
if (!videoUrl && songMenu) {
for (const it of songMenu.querySelectorAll('ytmusic-menu-navigation-item-renderer[tabindex="-1"] #navigation-endpoint')) {
if (it.getAttribute('href')?.includes('podcast/')) {
videoUrl = it.getAttribute('href');
break;
}
}
}
if (videoUrl) {
if (videoUrl.startsWith('watch?')) {
videoUrl = defaultConfig.url + '/' + videoUrl;
}
if (videoUrl.startsWith('podcast/')) {
videoUrl = defaultConfig.url + '/watch?' + videoUrl.replace('podcast/', 'v=');
}
if (videoUrl.includes('?playlist=')) {
ipc.invoke('download-playlist-request', videoUrl);
return;
@ -77,7 +102,7 @@ export const onRendererLoad = ({
ipc.on('downloader-feedback', (feedback: string) => {
if (progress) {
progress.innerHTML = feedback || 'Download';
progress.innerHTML = feedback || t('plugins.downloader.templates.button');
} else {
console.warn(
LoggerPrefix,

View File

@ -1,3 +0,0 @@
<svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#ffffff" d="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 392 B

View File

@ -1,3 +0,0 @@
<svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#ffffff" d="M6 3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3Zm0 2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H6Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 252 B

View File

@ -1,3 +0,0 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M3 17h12a1 1 0 0 1 .117 1.993L15 19H3a1 1 0 0 1-.117-1.993L3 17h12H3Zm0-6h18a1 1 0 0 1 .117 1.993L21 13H3a1 1 0 0 1-.117-1.993L3 11h18H3Zm0-6h15a1 1 0 0 1 .117 1.993L18 7H3a1 1 0 0 1-.117-1.993L3 5h15H3Z" fill="#ffffff"/>
</svg>

Before

Width:  |  Height:  |  Size: 338 B

View File

@ -1,3 +0,0 @@
<svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#ffffff" d="M3.755 12.5h16.492a.75.75 0 0 0 0-1.5H3.755a.75.75 0 0 0 0 1.5Z" />
</svg>

Before

Width:  |  Height:  |  Size: 174 B

View File

@ -1,3 +0,0 @@
<svg fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="#ffffff" d="M7.518 5H6.009a3.25 3.25 0 0 1 3.24-3h8.001A4.75 4.75 0 0 1 22 6.75v8a3.25 3.25 0 0 1-3 3.24v-1.508a1.75 1.75 0 0 0 1.5-1.732v-8a3.25 3.25 0 0 0-3.25-3.25h-8A1.75 1.75 0 0 0 7.518 5ZM5.25 6A3.25 3.25 0 0 0 2 9.25v9.5A3.25 3.25 0 0 0 5.25 22h9.5A3.25 3.25 0 0 0 18 18.75v-9.5A3.25 3.25 0 0 0 14.75 6h-9.5ZM3.5 9.25c0-.966.784-1.75 1.75-1.75h9.5c.967 0 1.75.784 1.75 1.75v9.5a1.75 1.75 0 0 1-1.75 1.75h-9.5a1.75 1.75 0 0 1-1.75-1.75v-9.5Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 546 B

View File

@ -0,0 +1,27 @@
export interface InAppMenuConfig {
enabled: boolean;
hideDOMWindowControls: boolean;
}
export const defaultInAppMenuConfig: InAppMenuConfig = {
enabled:
(
(
typeof window !== 'undefined' &&
!window.navigator?.userAgent?.toLowerCase().includes('mac')
) ||
(
typeof global !== 'undefined' &&
global.process?.platform !== 'darwin'
)
) && (
(
typeof window !== 'undefined' &&
!window.navigator?.userAgent?.toLowerCase().includes('linux')
) ||
(
typeof global !== 'undefined' &&
global.process?.platform !== 'linux'
)
),
hideDOMWindowControls: false,
};

View File

@ -2,24 +2,15 @@ import titlebarStyle from './titlebar.css?inline';
import { createPlugin } from '@/utils';
import { onMainLoad } from './main';
import { onMenu } from './menu';
import { onPlayerApiReady, onRendererLoad } from './renderer';
import { onConfigChange, onPlayerApiReady, onRendererLoad } from './renderer';
import { t } from '@/i18n';
import { defaultInAppMenuConfig } from './constants';
export interface InAppMenuConfig {
enabled: boolean;
hideDOMWindowControls: boolean;
}
export default createPlugin({
name: () => t('plugins.in-app-menu.name'),
description: () => t('plugins.in-app-menu.description'),
restartNeeded: true,
config: {
enabled:
(typeof window !== 'undefined' &&
!window.navigator?.userAgent?.includes('mac')) ||
(typeof global !== 'undefined' && global.process?.platform !== 'darwin'),
hideDOMWindowControls: false,
} as InAppMenuConfig,
config: defaultInAppMenuConfig,
stylesheets: [titlebarStyle],
menu: onMenu,
@ -27,5 +18,6 @@ export default createPlugin({
renderer: {
start: onRendererLoad,
onPlayerApiReady,
onConfigChange,
},
});

View File

@ -3,7 +3,7 @@ import { register } from 'electron-localshortcut';
import { BrowserWindow, Menu, MenuItem, ipcMain, nativeImage } from 'electron';
import type { BackendContext } from '@/types/contexts';
import type { InAppMenuConfig } from './index';
import type { InAppMenuConfig } from './constants';
export const onMainLoad = ({
window: win,
@ -47,7 +47,7 @@ export const onMainLoad = ({
return target;
};
ipcMain.handle('menu-event', (event, commandId: number) => {
ipcMain.handle('ytmd:menu-event', (event, commandId: number) => {
const target = getMenuItemById(commandId);
if (target)
target.click(

View File

@ -2,7 +2,7 @@ import is from 'electron-is';
import { t } from '@/i18n';
import type { InAppMenuConfig } from './index';
import type { InAppMenuConfig } from './constants';
import type { MenuContext } from '@/types/contexts';
import type { MenuTemplate } from '@/menu';

View File

@ -1,14 +0,0 @@
const Icons = {
submenu:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><polyline points="9 6 15 12 9 18" /></svg>',
checkbox:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10" /></svg>',
radio: {
checked:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" style="padding: 2px"><path fill="currentColor" d="M10,5 C7.2,5 5,7.2 5,10 C5,12.8 7.2,15 10,15 C12.8,15 15,12.8 15,10 C15,7.2 12.8,5 10,5 L10,5 Z M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z" /></svg>',
unchecked:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" style="padding: 2px"><path fill="currentColor" d="M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z" /></svg>',
},
};
export default Icons;

View File

@ -1,155 +0,0 @@
import Icons from './icons';
import { ElementFromHtml } from '../../utils/renderer';
import type { MenuItem } from 'electron';
interface PanelOptions {
placement?: 'bottom' | 'right';
order?: number;
}
export const createPanel = (
parent: HTMLElement,
anchor: HTMLElement,
items: MenuItem[],
options: PanelOptions = { placement: 'bottom', order: 0 },
) => {
const childPanels: HTMLElement[] = [];
const panel = document.createElement('menu-panel');
panel.style.zIndex = `${options.order}`;
const updateIconState = async (iconWrapper: HTMLElement, item: MenuItem) => {
if (item.type === 'checkbox') {
if (item.checked) iconWrapper.innerHTML = Icons.checkbox;
else iconWrapper.innerHTML = '';
} else if (item.type === 'radio') {
if (item.checked) iconWrapper.innerHTML = Icons.radio.checked;
else iconWrapper.innerHTML = Icons.radio.unchecked;
} else {
const iconURL =
typeof item.icon === 'string'
? ((await window.ipcRenderer.invoke(
'image-path-to-data-url',
)) as string)
: item.icon?.toDataURL();
if (iconURL) iconWrapper.style.background = `url(${iconURL})`;
}
};
const radioGroups: [MenuItem, HTMLElement][] = [];
items.map((item) => {
if (!item.visible) return;
if (item.type === 'separator')
return panel.appendChild(document.createElement('menu-separator'));
const menu = document.createElement('menu-item');
const iconWrapper = document.createElement('menu-icon');
updateIconState(iconWrapper, item);
menu.appendChild(iconWrapper);
menu.append(item.label);
menu.addEventListener('click', async () => {
await window.ipcRenderer.invoke('menu-event', item.commandId);
const menuItem = (await window.ipcRenderer.invoke(
'get-menu-by-id',
item.commandId,
)) as MenuItem | null;
if (menuItem) {
updateIconState(iconWrapper, menuItem);
if (menuItem.type === 'radio') {
await Promise.all(
radioGroups.map(async ([item, iconWrapper]) => {
if (item.commandId === menuItem.commandId) return;
const newItem = (await window.ipcRenderer.invoke(
'get-menu-by-id',
item.commandId,
)) as MenuItem | null;
if (newItem) updateIconState(iconWrapper, newItem);
}),
);
}
}
});
if (item.type === 'radio') {
radioGroups.push([item, iconWrapper]);
}
if (item.type === 'submenu') {
const subMenuIcon = document.createElement('menu-icon');
subMenuIcon.appendChild(ElementFromHtml(Icons.submenu));
menu.appendChild(subMenuIcon);
const [child, , children] = createPanel(
parent,
menu,
item.submenu?.items ?? [],
{
placement: 'right',
order: (options?.order ?? 0) + 1,
},
);
childPanels.push(child);
children.push(...children);
}
return panel.appendChild(menu);
});
/* methods */
const isOpened = () => panel.getAttribute('open') === 'true';
const close = () => panel.setAttribute('open', 'false');
const open = () => {
const rect = anchor.getBoundingClientRect();
if (options.placement === 'bottom') {
panel.style.setProperty('--x', `${rect.x}px`);
panel.style.setProperty('--y', `${rect.y + rect.height}px`);
} else {
panel.style.setProperty('--x', `${rect.x + rect.width}px`);
panel.style.setProperty('--y', `${rect.y}px`);
}
panel.setAttribute('open', 'true');
// Children are placed below their parent item, which can cause
// long lists to squeeze their children at the bottom of the screen
// (This needs to be done *after* setAttribute)
panel.classList.remove('position-by-bottom');
if (
options.placement === 'right' &&
panel.scrollHeight > panel.clientHeight
) {
panel.style.setProperty('--y', `${rect.y + rect.height}px`);
panel.classList.add('position-by-bottom');
}
};
anchor.addEventListener('click', () => {
if (isOpened()) close();
else open();
});
document.body.addEventListener('click', (event) => {
const path = event.composedPath();
const isInside = path.some(
(it) =>
it === panel ||
it === anchor ||
childPanels.includes(it as HTMLElement),
);
if (!isInside) close();
});
parent.appendChild(panel);
return [panel, { isOpened, close, open }, childPanels] as const;
};

View File

@ -1,219 +0,0 @@
import { createPanel } from './menu/panel';
import logoRaw from './assets/menu.svg?inline';
import closeRaw from './assets/close.svg?inline';
import minimizeRaw from './assets/minimize.svg?inline';
import maximizeRaw from './assets/maximize.svg?inline';
import unmaximizeRaw from './assets/unmaximize.svg?inline';
import type { Menu } from 'electron';
import type { RendererContext } from '@/types/contexts';
import type { InAppMenuConfig } from '@/plugins/in-app-menu/index';
const isMacOS = navigator.userAgent.includes('Macintosh');
const isNotWindowsOrMacOS =
!navigator.userAgent.includes('Windows') && !isMacOS;
export const onRendererLoad = async ({
getConfig,
ipc: { invoke, on },
}: RendererContext<InAppMenuConfig>) => {
const config = await getConfig();
const hideDOMWindowControls = config.hideDOMWindowControls;
let hideMenu = window.mainConfig.get('options.hideMenu');
const titleBar = document.createElement('title-bar');
const navBar = document.querySelector<HTMLDivElement>('#nav-bar-background');
let maximizeButton: HTMLButtonElement;
let panelClosers: (() => void)[] = [];
if (isMacOS) titleBar.style.setProperty('--offset-left', '70px');
const logo = document.createElement('img');
const close = document.createElement('img');
const minimize = document.createElement('img');
const maximize = document.createElement('img');
const unmaximize = document.createElement('img');
if (window.ELECTRON_RENDERER_URL) {
logo.src = window.ELECTRON_RENDERER_URL + '/' + logoRaw;
close.src = window.ELECTRON_RENDERER_URL + '/' + closeRaw;
minimize.src = window.ELECTRON_RENDERER_URL + '/' + minimizeRaw;
maximize.src = window.ELECTRON_RENDERER_URL + '/' + maximizeRaw;
unmaximize.src = window.ELECTRON_RENDERER_URL + '/' + unmaximizeRaw;
} else {
logo.src = logoRaw;
close.src = closeRaw;
minimize.src = minimizeRaw;
maximize.src = maximizeRaw;
unmaximize.src = unmaximizeRaw;
}
logo.classList.add('title-bar-icon');
const logoClick = () => {
hideMenu = !hideMenu;
let visibilityStyle: string;
if (hideMenu) {
visibilityStyle = 'hidden';
} else {
visibilityStyle = 'visible';
}
const menus = document.querySelectorAll<HTMLElement>('menu-button');
menus.forEach((menu) => {
menu.style.visibility = visibilityStyle;
});
};
logo.onclick = logoClick;
on('toggle-in-app-menu', logoClick);
if (!isMacOS) titleBar.appendChild(logo);
document.body.appendChild(titleBar);
titleBar.appendChild(logo);
const addWindowControls = async () => {
// Create window control buttons
const minimizeButton = document.createElement('button');
minimizeButton.classList.add('window-control');
minimizeButton.appendChild(minimize);
minimizeButton.onclick = () => invoke('window-minimize');
maximizeButton = document.createElement('button');
if (await invoke('window-is-maximized')) {
maximizeButton.classList.add('window-control');
maximizeButton.appendChild(unmaximize);
} else {
maximizeButton.classList.add('window-control');
maximizeButton.appendChild(maximize);
}
maximizeButton.onclick = async () => {
if (await invoke('window-is-maximized')) {
// change icon to maximize
maximizeButton.removeChild(maximizeButton.firstChild!);
maximizeButton.appendChild(maximize);
// call unmaximize
await invoke('window-unmaximize');
} else {
// change icon to unmaximize
maximizeButton.removeChild(maximizeButton.firstChild!);
maximizeButton.appendChild(unmaximize);
// call maximize
await invoke('window-maximize');
}
};
const closeButton = document.createElement('button');
closeButton.classList.add('window-control');
closeButton.appendChild(close);
closeButton.onclick = () => invoke('window-close');
// Create a container div for the window control buttons
const windowControlsContainer = document.createElement('div');
windowControlsContainer.classList.add('window-controls-container');
windowControlsContainer.appendChild(minimizeButton);
windowControlsContainer.appendChild(maximizeButton);
windowControlsContainer.appendChild(closeButton);
// Add window control buttons to the title bar
titleBar.appendChild(windowControlsContainer);
};
if (isNotWindowsOrMacOS && !hideDOMWindowControls) await addWindowControls();
if (navBar) {
const observer = new MutationObserver((mutations) => {
mutations.forEach(() => {
titleBar.style.setProperty(
'--titlebar-background-color',
navBar.style.backgroundColor,
);
document
.querySelector('html')!
.style.setProperty(
'--titlebar-background-color',
navBar.style.backgroundColor,
);
});
});
observer.observe(navBar, { attributes: true, attributeFilter: ['style'] });
}
const updateMenu = async () => {
const children = [...titleBar.children];
children.forEach((child) => {
if (child !== logo) child.remove();
});
panelClosers = [];
const menu = (await invoke('get-menu')) as Menu | null;
if (!menu) return;
menu.items.forEach((menuItem) => {
const menu = document.createElement('menu-button');
const [, { close: closer }] = createPanel(
titleBar,
menu,
menuItem.submenu?.items ?? [],
);
panelClosers.push(closer);
menu.append(menuItem.label);
titleBar.appendChild(menu);
if (hideMenu) {
menu.style.visibility = 'hidden';
}
});
if (isNotWindowsOrMacOS && !hideDOMWindowControls)
await addWindowControls();
};
await updateMenu();
document.title = 'Youtube Music';
on('close-all-in-app-menu-panel', () => {
panelClosers.forEach((closer) => closer());
});
on('refresh-in-app-menu', () => updateMenu());
on('window-maximize', () => {
if (
isNotWindowsOrMacOS &&
!hideDOMWindowControls &&
maximizeButton.firstChild
) {
maximizeButton.removeChild(maximizeButton.firstChild);
maximizeButton.appendChild(unmaximize);
}
});
on('window-unmaximize', () => {
if (
isNotWindowsOrMacOS &&
!hideDOMWindowControls &&
maximizeButton.firstChild
) {
maximizeButton.removeChild(maximizeButton.firstChild);
maximizeButton.appendChild(unmaximize);
}
});
if (window.mainConfig.plugins.isEnabled('picture-in-picture')) {
on('pip-toggle', () => {
updateMenu();
});
}
};
export const onPlayerApiReady = () => {
const htmlHeadStyle = document.querySelector('head > div > style');
if (htmlHeadStyle) {
// HACK: This is a hack to remove the scrollbar width
htmlHeadStyle.innerHTML = htmlHeadStyle.innerHTML.replace(
'html::-webkit-scrollbar {width: var(--ytmusic-scrollbar-width);',
'html::-webkit-scrollbar {',
);
}
};

View File

@ -0,0 +1,57 @@
import { createSignal } from 'solid-js';
import { render } from 'solid-js/web';
import { TitleBar } from './renderer/TitleBar';
import { defaultInAppMenuConfig, InAppMenuConfig } from './constants';
import type { RendererContext } from '@/types/contexts';
const scrollStyle = `
html::-webkit-scrollbar {
background-color: red;
}
`;
const isMacOS = navigator.userAgent.includes('Macintosh');
const isNotWindowsOrMacOS =
!navigator.userAgent.includes('Windows') && !isMacOS;
const [config, setConfig] = createSignal<InAppMenuConfig>(defaultInAppMenuConfig);
export const onRendererLoad = async ({
getConfig,
ipc,
}: RendererContext<InAppMenuConfig>) => {
setConfig(await getConfig());
document.title = 'YouTube Music';
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(scrollStyle);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
render(() => (
<TitleBar
ipc={ipc}
isMacOS={isMacOS}
enableController={isNotWindowsOrMacOS && !config().hideDOMWindowControls}
initialCollapsed={window.mainConfig.get('options.hideMenu')}
/>
), document.body);
};
export const onPlayerApiReady = () => {
// NOT WORKING AFTER YTM UPDATE (last checked 2024-02-04)
//
// const htmlHeadStyle = document.querySelector('head > div > style');
// if (htmlHeadStyle) {
// // HACK: This is a hack to remove the scrollbar width
// htmlHeadStyle.innerHTML = htmlHeadStyle.innerHTML.replace(
// 'html::-webkit-scrollbar {width: var(--ytmusic-scrollbar-width);',
// 'html::-webkit-scrollbar { width: 0;',
// );
// }
};
export const onConfigChange = (newConfig: InAppMenuConfig) => {
setConfig(newConfig);
};

View File

@ -0,0 +1,44 @@
import { JSX } from 'solid-js';
import { css } from 'solid-styled-components';
import { cache } from '@/providers/decorators';
const iconButton = cache(() => css`
-webkit-app-region: none;
background: transparent;
width: 24px;
height: 24px;
padding: 2px;
border-radius: 2px;
display: flex;
justify-content: center;
align-items: center;
color: white;
outline: none;
border: none;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
background: rgba(255, 255, 255, 0.1);
}
&:active {
scale: 0.9;
}
`);
type CollapseIconButtonProps = JSX.HTMLAttributes<HTMLButtonElement>;
export const IconButton = (props: CollapseIconButtonProps) => {
return (
<button {...props} class={iconButton()}>
{props.children}
</button>
);
};

View File

@ -0,0 +1,44 @@
import { JSX, splitProps } from 'solid-js';
import { css } from 'solid-styled-components';
import { cache } from '@/providers/decorators';
const menuStyle = cache(() => css`
-webkit-app-region: none;
display: flex;
justify-content: center;
align-items: center;
align-self: stretch;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
&:active {
scale: 0.9;
}
&[data-selected="true"] {
background-color: rgba(255, 255, 255, 0.2);
}
`);
export type MenuButtonProps = JSX.HTMLAttributes<HTMLLIElement> & {
text?: string;
selected?: boolean;
};
export const MenuButton = (props: MenuButtonProps) => {
const [local, leftProps] = splitProps(props, ['text']);
return (
<li {...leftProps} class={menuStyle()} data-selected={props.selected}>
{local.text}
</li>
);
};

View File

@ -0,0 +1,151 @@
import { createSignal, JSX, Show, splitProps } from 'solid-js';
import { mergeProps, Portal } from 'solid-js/web';
import { css } from 'solid-styled-components';
import { Transition } from 'solid-transition-group';
import { autoUpdate, flip, offset, OffsetOptions, size } from '@floating-ui/dom';
import { useFloating } from 'solid-floating-ui';
import { cache } from '@/providers/decorators';
const panelStyle = cache(() => css`
position: fixed;
top: var(--offset-y, 0);
left: var(--offset-x, 0);
max-width: var(--max-width, 100%);
max-height: var(--max-height, 100%);
z-index: 10000;
width: fit-content;
height: fit-content;
padding: 4px;
box-sizing: border-box;
border-radius: 8px;
overflow: auto;
background-color: color-mix(
in srgb,
var(--titlebar-background-color, #030303) 50%,
rgba(0, 0, 0, 0.1)
);
backdrop-filter: blur(8px);
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05),
0 2px 8px rgba(0, 0, 0, 0.2);
transform-origin: var(--origin-x, 50%) var(--origin-y, 50%);
`);
const animationStyle = cache(() => ({
enter: css`
opacity: 0;
transform: scale(0.9);
`,
enterActive: css`
transition: opacity 0.225s cubic-bezier(0.33, 1, 0.68, 1), transform 0.225s cubic-bezier(0.33, 1, 0.68, 1);
`,
exitTo: css`
opacity: 0;
transform: scale(0.9);
`,
exitActive: css`
transition: opacity 0.225s cubic-bezier(0.32, 0, 0.67, 0), transform 0.225s cubic-bezier(0.32, 0, 0.67, 0);
`,
}));
export type Placement =
'top'
| 'bottom'
| 'left'
| 'right'
| 'top-start'
| 'top-end'
| 'bottom-start'
| 'bottom-end'
| 'right-start'
| 'right-end'
| 'left-start'
| 'left-end';
export type PanelProps = JSX.HTMLAttributes<HTMLUListElement> & {
open?: boolean;
anchor?: HTMLElement | null;
children: JSX.Element;
placement?: Placement;
offset?: OffsetOptions;
};
export const Panel = (props: PanelProps) => {
const [elements, local, leftProps] = splitProps(
mergeProps({ placement: 'bottom' }, props),
['anchor', 'children'],
['open', 'placement', 'offset'],
);
const [panel, setPanel] = createSignal<HTMLElement | null>(null);
const position = useFloating(() => elements.anchor, panel, {
whileElementsMounted: autoUpdate,
placement: local.placement as Placement,
strategy: 'fixed',
middleware: [
offset(local.offset),
size({
padding: 8,
apply({ elements, availableWidth, availableHeight }) {
elements.floating.style.setProperty('--max-width', `${Math.max(200, availableWidth)}px`);
elements.floating.style.setProperty('--max-height', `${Math.max(200, availableHeight)}px`);
}
}),
flip({ fallbackStrategy: 'initialPlacement' }),
],
});
const originX = () => {
if (position.placement.includes('left')) return '100%';
if (position.placement.includes('right')) return '0';
if (position.placement.includes('top') || position.placement.includes('bottom')) {
if (position.placement.includes('start')) return '0';
if (position.placement.includes('end')) return '100%';
}
return '50%';
};
const originY = () => {
if (position.placement.includes('top')) return '100%';
if (position.placement.includes('bottom')) return '0';
if (position.placement.includes('left') || position.placement.includes('right')) {
if (position.placement.includes('start')) return '0';
if (position.placement.includes('end')) return '100%';
}
return '50%';
};
return (
<Portal>
<Transition
appear
enterClass={animationStyle().enter}
enterActiveClass={animationStyle().enterActive}
exitToClass={animationStyle().exitTo}
exitActiveClass={animationStyle().exitActive}
>
<Show when={local.open}>
<ul
{...leftProps}
data-ytmd-sub-panel={true}
ref={setPanel}
class={panelStyle()}
style={{
'--offset-x': `${position.x}px`,
'--offset-y': `${position.y}px`,
'--origin-x': originX(),
'--origin-y': originY(),
}}
>
{elements.children}
</ul>
</Show>
</Transition>
</Portal>
);
};

View File

@ -0,0 +1,335 @@
import { createSignal, Match, Show, Switch } from 'solid-js';
import { JSX } from 'solid-js/jsx-runtime';
import { css } from 'solid-styled-components';
import { Portal } from 'solid-js/web';
import { Transition } from 'solid-transition-group';
import { useFloating } from 'solid-floating-ui';
import { autoUpdate, offset, size } from '@floating-ui/dom';
import { Panel } from './Panel';
import { cache } from '@/providers/decorators';
const itemStyle = cache(() => css`
position: relative;
-webkit-app-region: none;
min-height: 32px;
height: 32px;
display: grid;
grid-template-columns: 32px 1fr auto minmax(32px, auto);
justify-content: flex-start;
align-items: center;
border-radius: 4px;
cursor: pointer;
box-sizing: border-box;
user-select: none;
-webkit-user-drag: none;
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
&:active {
background-color: rgba(255, 255, 255, 0.2);
}
&[data-selected="true"] {
background-color: rgba(255, 255, 255, 0.2);
}
& * {
box-sizing: border-box;
}
`);
const itemIconStyle = cache(() => css`
height: 32px;
padding: 4px;
color: white;
`);
const itemLabelStyle = cache(() => css`
font-size: 12px;
color: white;
`);
const itemChipStyle = cache(() => css`
display: flex;
justify-content: center;
align-items: center;
min-width: 16px;
height: 16px;
padding: 0 4px;
margin-left: 8px;
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.2);
color: #f1f1f1;
font-size: 10px;
font-weight: 500;
line-height: 1;
`);
const toolTipStyle = cache(() => css`
min-width: 32px;
width: 100%;
height: 100%;
padding: 4px;
max-width: calc(var(--max-width, 100%) - 8px);
max-height: calc(var(--max-height, 100%) - 8px);
border-radius: 4px;
background-color: rgba(25, 25, 25, 0.8);
color: #f1f1f1;
font-size: 10px;
`);
const popupStyle = cache(() => css`
position: fixed;
top: var(--offset-y, 0);
left: var(--offset-x, 0);
max-width: var(--max-width, 100%);
max-height: var(--max-height, 100%);
z-index: 100000000;
pointer-events: none;
`);
const animationStyle = cache(() => ({
enter: css`
opacity: 0;
transform: scale(0.9);
`,
enterActive: css`
transition: opacity 0.225s cubic-bezier(0.33, 1, 0.68, 1), transform 0.225s cubic-bezier(0.33, 1, 0.68, 1);
`,
exitTo: css`
opacity: 0;
transform: scale(0.9);
`,
exitActive: css`
transition: opacity 0.225s cubic-bezier(0.32, 0, 0.67, 0), transform 0.225s cubic-bezier(0.32, 0, 0.67, 0);
`,
}));
const getParents = (element: Element | null): (HTMLElement | null)[] => {
const parents: (HTMLElement | null)[] = [];
let now = element;
while (now) {
parents.push(now as HTMLElement | null);
now = now.parentElement;
}
return parents;
};
type BasePanelItemProps = {
name: string;
label?: string;
chip?: string;
toolTip?: string;
commandId?: number;
};
type NormalPanelItemProps = BasePanelItemProps & {
type: 'normal';
onClick?: () => void;
};
type SubmenuItemProps = BasePanelItemProps & {
type: 'submenu';
level: number[];
children: JSX.Element;
};
type RadioPanelItemProps = BasePanelItemProps & {
type: 'radio';
checked: boolean;
onChange?: (checked: boolean) => void;
};
type CheckboxPanelItemProps = BasePanelItemProps & {
type: 'checkbox';
checked: boolean;
onChange?: (checked: boolean) => void;
};
export type PanelItemProps = NormalPanelItemProps | SubmenuItemProps | RadioPanelItemProps | CheckboxPanelItemProps;
export const PanelItem = (props: PanelItemProps) => {
const [open, setOpen] = createSignal(false);
const [toolTipOpen, setToolTipOpen] = createSignal(false);
const [toolTip, setToolTip] = createSignal<HTMLElement | null>(null);
const [anchor, setAnchor] = createSignal<HTMLElement | null>(null);
const [child, setChild] = createSignal<HTMLElement | null>(null);
const position = useFloating(anchor, toolTip, {
whileElementsMounted: autoUpdate,
placement: 'bottom-start',
strategy: 'fixed',
middleware: [
offset({ mainAxis: 8 }),
size({
apply({ rects, elements }) {
elements.floating.style.setProperty('--max-width', `${rects.reference.width}px`);
}
}),
],
});
const handleHover = (event: MouseEvent) => {
setToolTipOpen(true);
event.target?.addEventListener('mouseleave', () => {
setToolTipOpen(false);
}, { once: true });
if (props.type === 'submenu') {
const timer = setTimeout(() => {
setOpen(true);
let mouseX = event.clientX;
let mouseY = event.clientY;
const onMouseMove = (event: MouseEvent) => {
mouseX = event.clientX;
mouseY = event.clientY;
};
document.addEventListener('mousemove', onMouseMove);
event.target?.addEventListener('mouseleave', () => {
setTimeout(() => {
document.removeEventListener('mousemove', onMouseMove);
const parents = getParents(document.elementFromPoint(mouseX, mouseY));
if (!parents.includes(child())) {
setOpen(false);
} else {
const onOtherHover = (event: MouseEvent) => {
const parents = getParents(event.target as HTMLElement);
const closestLevel = parents.find((it) => it?.dataset?.level)?.dataset.level ?? '';
const path = event.composedPath();
const isOtherItem = path.some((it) => it instanceof HTMLElement && it.classList.contains(itemStyle()));
const isChild = closestLevel.startsWith(props.level.join('/'));
if (isOtherItem && !isChild) {
setOpen(false);
document.removeEventListener('mousemove', onOtherHover);
}
};
document.addEventListener('mousemove', onOtherHover);
}
}, 225);
}, { once: true });
}, 225);
event.target?.addEventListener('mouseleave', () => {
clearTimeout(timer);
}, { once: true });
}
};
const handleClick = async () => {
await window.ipcRenderer.invoke('ytmd:menu-event', props.commandId);
if (props.type === 'radio') {
props.onChange?.(!props.checked);
} else if (props.type === 'checkbox') {
props.onChange?.(!props.checked);
} else if (props.type === 'normal') {
props.onClick?.();
}
};
return (
<li
ref={setAnchor}
class={itemStyle()}
onMouseEnter={handleHover}
onClick={handleClick}
data-selected={open()}
>
<Switch fallback={<div class={itemIconStyle()}/>}>
<Match when={props.type === 'checkbox' && props.checked}>
<svg class={itemIconStyle()} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M5 12l5 5l10 -10"/>
</svg>
</Match>
<Match when={props.type === 'radio' && props.checked}>
<svg class={itemIconStyle()} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
style={{ padding: '6px' }}>
<path fill="currentColor"
d="M10,5 C7.2,5 5,7.2 5,10 C5,12.8 7.2,15 10,15 C12.8,15 15,12.8 15,10 C15,7.2 12.8,5 10,5 L10,5 Z M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z"/>
</svg>
</Match>
<Match when={props.type === 'radio' && !props.checked}>
<svg class={itemIconStyle()} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
style={{ padding: '6px' }}>
<path fill="currentColor"
d="M10,0 C4.5,0 0,4.5 0,10 C0,15.5 4.5,20 10,20 C15.5,20 20,15.5 20,10 C20,4.5 15.5,0 10,0 L10,0 Z M10,18 C5.6,18 2,14.4 2,10 C2,5.6 5.6,2 10,2 C14.4,2 18,5.6 18,10 C18,14.4 14.4,18 10,18 L10,18 Z"/>
</svg>
</Match>
</Switch>
<span class={itemLabelStyle()}>
{props.name}
</span>
<Show when={props.chip} fallback={<div/>}>
<span class={itemChipStyle()}>
{props.chip}
</span>
</Show>
<Show when={props.type === 'submenu'}>
<svg class={itemIconStyle()} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<polyline points="9 6 15 12 9 18"/>
</svg>
<Panel
ref={setChild}
open={open()}
anchor={anchor()}
placement={'right-start'}
data-level={props.type === 'submenu' && props.level.join('/')}
offset={{ mainAxis: 8 }}
>
{props.type === 'submenu' && props.children}
</Panel>
</Show>
<Show when={props.toolTip}>
<Portal>
<div
ref={setToolTip}
class={popupStyle()}
style={{
'--offset-x': `${position.x}px`,
'--offset-y': `${position.y}px`,
}}
>
<Transition
appear
enterClass={animationStyle().enter}
enterActiveClass={animationStyle().enterActive}
exitToClass={animationStyle().exitTo}
exitActiveClass={animationStyle().exitActive}
>
<Show when={toolTipOpen()}>
<div class={toolTipStyle()}>
{props.toolTip}
</div>
</Show>
</Transition>
</div>
</Portal>
</Show>
</li>
);
};

View File

@ -0,0 +1,357 @@
import { Menu, MenuItem } from 'electron';
import { createEffect, createResource, createSignal, Index, Match, onMount, Show, Switch } from 'solid-js';
import { css } from 'solid-styled-components';
import { TransitionGroup } from 'solid-transition-group';
import { MenuButton } from './MenuButton';
import { Panel } from './Panel';
import { PanelItem } from './PanelItem';
import { IconButton } from './IconButton';
import { WindowController } from './WindowController';
import { cache } from '@/providers/decorators';
import type { RendererContext } from '@/types/contexts';
import type { InAppMenuConfig } from '../constants';
const titleStyle = cache(() => css`
-webkit-app-region: drag;
box-sizing: border-box;
position: fixed;
top: 0;
z-index: 10000000;
width: 100%;
height: var(--menu-bar-height, 32px);
display: flex;
flex-flow: row;
justify-content: flex-start;
align-items: center;
gap: 4px;
color: #f1f1f1;
font-size: 12px;
padding: 4px 4px 4px var(--offset-left, 4px);
background-color: var(--titlebar-background-color, #030303);
user-select: none;
transition: opacity 200ms ease 0s,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) 0s;
&[data-macos="true"] {
padding: 4px 4px 4px 74px;
}
`);
const separatorStyle = cache(() => css`
min-height: 1px;
height: 1px;
margin: 4px 0;
background-color: rgba(255, 255, 255, 0.2);
`);
const animationStyle = cache(() => ({
enter: css`
opacity: 0;
transform: translateX(-50%) scale(0.8);
`,
enterActive: css`
transition: opacity 0.1s cubic-bezier(0.33, 1, 0.68, 1), transform 0.1s cubic-bezier(0.33, 1, 0.68, 1);
`,
exitTo: css`
opacity: 0;
transform: translateX(-50%) scale(0.8);
`,
exitActive: css`
transition: opacity 0.1s cubic-bezier(0.32, 0, 0.67, 0), transform 0.1s cubic-bezier(0.32, 0, 0.67, 0);
`,
move: css`
transition: all 0.1s cubic-bezier(0.65, 0, 0.35, 1);
`,
fakeTarget: css`
position: absolute;
opacity: 0;
`,
fake: css`
transition: all 0.00000000001s;
`,
}));
export type PanelRendererProps = {
items: Electron.Menu['items'];
level?: number[];
onClick?: (commandId: number, radioGroup?: MenuItem[]) => void;
}
const PanelRenderer = (props: PanelRendererProps) => {
const radioGroup = () => props.items.filter((it) => it.type === 'radio');
return (
<Index each={props.items}>
{(subItem) => (
<Show when={subItem().visible}>
<Switch>
<Match when={subItem().type === 'normal'}>
<PanelItem
type={'normal'}
name={subItem().label}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
onClick={() => props.onClick?.(subItem().commandId)}
/>
</Match>
<Match when={subItem().type === 'submenu'}>
<PanelItem
type={'submenu'}
name={subItem().label}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
level={[...props.level ?? [], subItem().commandId]}
commandId={subItem().commandId}
>
<PanelRenderer
items={subItem().submenu?.items ?? []}
level={[...props.level ?? [], subItem().commandId]}
onClick={props.onClick}
/>
</PanelItem>
</Match>
<Match when={subItem().type === 'checkbox'}>
<PanelItem
type={'checkbox'}
name={subItem().label}
checked={subItem().checked}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
onChange={() => props.onClick?.(subItem().commandId)}
/>
</Match>
<Match when={subItem().type === 'radio'}>
<PanelItem
type={'radio'}
name={subItem().label}
checked={subItem().checked}
chip={subItem().sublabel}
toolTip={subItem().toolTip}
commandId={subItem().commandId}
onChange={() => props.onClick?.(subItem().commandId, radioGroup())}
/>
</Match>
<Match when={subItem().type === 'separator'}>
<hr class={separatorStyle()}/>
</Match>
</Switch>
</Show>
)}
</Index>
);
};
export type TitleBarProps = {
ipc: RendererContext<InAppMenuConfig>['ipc'];
isMacOS?: boolean;
enableController?: boolean;
initialCollapsed?: boolean;
};
export const TitleBar = (props: TitleBarProps) => {
const [collapsed, setCollapsed] = createSignal(props.initialCollapsed);
const [ignoreTransition, setIgnoreTransition] = createSignal(false);
const [openTarget, setOpenTarget] = createSignal<HTMLElement | null>(null);
const [menu, setMenu] = createSignal<Menu | null>(null);
const [data, { refetch }] = createResource(async () => await props.ipc.invoke('get-menu') as Promise<Menu | null>);
const [isMaximized, { refetch: refetchMaximize }] = createResource(async () => await props.ipc.invoke('window-is-maximized') as Promise<boolean>);
const handleToggleMaximize = async () => {
if (isMaximized()) {
await props.ipc.invoke('window-unmaximize');
} else {
await props.ipc.invoke('window-maximize');
}
await refetchMaximize();
};
const handleMinimize = async () => {
await props.ipc.invoke('window-minimize');
};
const handleClose = async () => {
await props.ipc.invoke('window-close');
};
const refreshMenuItem = async (originalMenu: Menu, commandId: number) => {
const menuItem = (await window.ipcRenderer.invoke(
'get-menu-by-id',
commandId,
)) as MenuItem | null;
const newMenu = structuredClone(originalMenu);
const stack = [...newMenu?.items ?? []];
let now: MenuItem | undefined = stack.pop();
while (now) {
const index = now?.submenu?.items?.findIndex((it) => it.commandId === commandId) ?? -1;
if (index >= 0) {
if (menuItem) now?.submenu?.items?.splice(index, 1, menuItem);
else now?.submenu?.items?.splice(index, 1);
}
if (now?.submenu) {
stack.push(...now.submenu.items);
}
now = stack.pop();
}
return newMenu;
};
const handleItemClick = async (commandId: number, radioGroup?: MenuItem[]) => {
const menuData = menu();
if (!menuData) return;
if (Array.isArray(radioGroup)) {
let newMenu = menuData;
for await (const item of radioGroup) {
newMenu = await refreshMenuItem(newMenu, item.commandId);
}
setMenu(newMenu);
return;
}
setMenu(await refreshMenuItem(menuData, commandId));
};
onMount(() => {
props.ipc.on('close-all-in-app-menu-panel', async () => {
setIgnoreTransition(true);
setMenu(null);
await refetch();
setMenu(data() ?? null);
setIgnoreTransition(false);
});
props.ipc.on('refresh-in-app-menu', async () => {
setIgnoreTransition(true);
await refetch();
setMenu(data() ?? null);
setIgnoreTransition(false);
});
props.ipc.on('toggle-in-app-menu', () => {
setCollapsed(!collapsed());
});
props.ipc.on('window-maximize', refetchMaximize);
props.ipc.on('window-unmaximize', refetchMaximize);
// close menu when the outside of the panel or sub-panel is clicked
document.body.addEventListener('click', (e) => {
if (
e.target instanceof HTMLElement &&
!(
e.target.closest('nav[data-ytmd-main-panel]') ||
e.target.closest('ul[data-ytmd-sub-panel]')
)
) {
setOpenTarget(null);
}
});
});
createEffect(() => {
if (!menu() && data()) {
setMenu(data() ?? null);
}
});
return (
<nav data-ytmd-main-panel={true} class={titleStyle()} data-macos={props.isMacOS}>
<IconButton
onClick={() => setCollapsed(!collapsed())}
style={{
'border-top-left-radius': '4px',
}}
>
<svg width={16} height={16} viewBox={'0 0 24 24'}>
<path
d="M3 17h12a1 1 0 0 1 .117 1.993L15 19H3a1 1 0 0 1-.117-1.993L3 17h12H3Zm0-6h18a1 1 0 0 1 .117 1.993L21 13H3a1 1 0 0 1-.117-1.993L3 11h18H3Zm0-6h15a1 1 0 0 1 .117 1.993L18 7H3a1 1 0 0 1-.117-1.993L3 5h15H3Z"
fill="currentColor"
/>
</svg>
</IconButton>
<TransitionGroup
enterClass={ignoreTransition() ? animationStyle().fakeTarget : animationStyle().enter}
enterActiveClass={ignoreTransition() ? animationStyle().fake : animationStyle().enterActive}
exitToClass={ignoreTransition() ? animationStyle().fakeTarget : animationStyle().exitTo}
exitActiveClass={ignoreTransition() ? animationStyle().fake : animationStyle().exitActive}
onBeforeEnter={(element) => {
if (ignoreTransition()) return;
const index = Number(element.getAttribute('data-index') ?? 0);
(element as HTMLElement).style.setProperty('transition-delay', `${(index * 0.025)}s`);
}}
onAfterEnter={(element) => {
(element as HTMLElement).style.removeProperty('transition-delay');
}}
onBeforeExit={(element) => {
if (ignoreTransition()) return;
const index = Number(element.getAttribute('data-index') ?? 0);
const length = Number(element.getAttribute('data-length') ?? 1);
(element as HTMLElement).style.setProperty('transition-delay', `${(length * 0.025) - (index * 0.025)}s`);
}}
>
<Show when={!collapsed()}>
<Index each={menu()?.items}>
{(item, index) => {
const [anchor, setAnchor] = createSignal<HTMLElement | null>(null);
const handleClick = () => {
if (openTarget() === anchor()) {
setOpenTarget(null);
} else {
setOpenTarget(anchor());
}
};
return (
<>
<MenuButton
ref={setAnchor}
text={item().label}
onClick={handleClick}
selected={openTarget() === anchor()}
data-index={index}
data-length={data()?.items.length}
/>
<Panel
open={openTarget() === anchor()}
anchor={anchor()}
placement={'bottom-start'}
offset={{ mainAxis: 8 }}
>
<PanelRenderer
items={item().submenu?.items ?? []}
onClick={handleItemClick}
/>
</Panel>
</>
);
}}
</Index>
</Show>
</TransitionGroup>
<Show when={props.enableController}>
<div style={{ flex: 1 }}/>
<WindowController
isMaximize={isMaximized()}
onToggleMaximize={handleToggleMaximize}
onMinimize={handleMinimize}
onClose={handleClose}
/>
</Show>
</nav>
);
};

View File

@ -0,0 +1,66 @@
import { css } from 'solid-styled-components';
import { Show } from 'solid-js';
import { IconButton } from './IconButton';
import { cache } from '@/providers/decorators';
const containerStyle = cache(() => css`
display: flex;
justify-content: flex-end;
align-items: center;
& > *:last-of-type {
border-top-right-radius: 4px;
&:hover {
background: rgba(255, 0, 0, 0.5);
}
}
`);
export type WindowControllerProps = {
isMaximize?: boolean;
onToggleMaximize?: () => void;
onMinimize?: () => void;
onClose?: () => void;
}
export const WindowController = (props: WindowControllerProps) => {
return (
<div class={containerStyle()}>
<IconButton onClick={props.onMinimize}>
<svg width={16} height={16} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M3.755 12.5h16.492a.75.75 0 0 0 0-1.5H3.755a.75.75 0 0 0 0 1.5Z"/>
</svg>
</IconButton>
<IconButton onClick={props.onToggleMaximize}>
<Show
when={props.isMaximize}
fallback={
<svg width={16} height={16} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
fill="currentColor"
d="M6 3h12a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3Zm0 2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H6Z"
/>
</svg>
}
>
<svg width={16} height={16} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
fill="currentColor"
d="M7.518 5H6.009a3.25 3.25 0 0 1 3.24-3h8.001A4.75 4.75 0 0 1 22 6.75v8a3.25 3.25 0 0 1-3 3.24v-1.508a1.75 1.75 0 0 0 1.5-1.732v-8a3.25 3.25 0 0 0-3.25-3.25h-8A1.75 1.75 0 0 0 7.518 5ZM5.25 6A3.25 3.25 0 0 0 2 9.25v9.5A3.25 3.25 0 0 0 5.25 22h9.5A3.25 3.25 0 0 0 18 18.75v-9.5A3.25 3.25 0 0 0 14.75 6h-9.5ZM3.5 9.25c0-.966.784-1.75 1.75-1.75h9.5c.967 0 1.75.784 1.75 1.75v9.5a1.75 1.75 0 0 1-1.75 1.75h-9.5a1.75 1.75 0 0 1-1.75-1.75v-9.5Z"
/>
</svg>
</Show>
</IconButton>
<IconButton onClick={props.onClose}>
<svg width={16} height={16} fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path
fill="currentColor"
d="m4.21 4.387.083-.094a1 1 0 0 1 1.32-.083l.094.083L12 10.585l6.293-6.292a1 1 0 1 1 1.414 1.414L13.415 12l6.292 6.293a1 1 0 0 1 .083 1.32l-.083.094a1 1 0 0 1-1.32.083l-.094-.083L12 13.415l-6.293 6.292a1 1 0 0 1-1.414-1.414L10.585 12 4.293 5.707a1 1 0 0 1-.083-1.32l.083-.094-.083.094Z"
/>
</svg>
</IconButton>
</div>
);
};

View File

@ -1,168 +1,8 @@
:root {
--titlebar-background-color: #030303;
--titlebar-background-color: var(--ytmusic-color-black3);
--menu-bar-height: 32px;
}
title-bar {
-webkit-app-region: drag;
box-sizing: border-box;
position: fixed;
top: 0;
z-index: 10000000;
width: 100%;
height: var(--menu-bar-height, 36px);
display: flex;
flex-flow: row;
justify-content: flex-start;
align-items: center;
gap: 4px;
color: #f1f1f1;
font-size: 12px;
padding: 4px 12px;
padding-left: var(--offset-left, 12px);
background-color: var(--titlebar-background-color, #030303);
user-select: none;
transition:
opacity 200ms ease 0s,
background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) 0s;
}
menu-button {
-webkit-app-region: none;
display: flex;
justify-content: center;
align-items: center;
align-self: stretch;
padding: 2px 8px;
border-radius: 4px;
cursor: pointer;
}
menu-button:hover {
background-color: rgba(255, 255, 255, 0.1);
}
menu-panel {
position: fixed;
top: var(--y, 0);
left: var(--x, 0);
max-height: calc(100vh - var(--menu-bar-height, 36px) - 16px - var(--y, 0));
display: flex;
flex-flow: column;
justify-content: flex-start;
align-items: stretch;
gap: 0;
overflow: auto;
padding: 4px;
border-radius: 8px;
pointer-events: none;
background-color: color-mix(
in srgb,
var(--titlebar-background-color, #030303) 50%,
rgba(0, 0, 0, 0.1)
);
backdrop-filter: blur(8px);
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.05),
0 2px 8px rgba(0, 0, 0, 0.2);
z-index: 0;
opacity: 0;
transform: scale(0.8);
transform-origin: top left;
transition:
opacity 200ms ease 0s,
transform 200ms ease 0s;
}
menu-panel[open='true'] {
pointer-events: all;
opacity: 1;
transform: scale(1);
}
menu-panel.position-by-bottom {
top: unset;
bottom: calc(100vh - var(--y, 100%));
max-height: calc(var(--y, 0) - var(--menu-bar-height, 36px) - 16px);
}
menu-item {
-webkit-app-region: none;
min-height: 32px;
height: 32px;
display: grid;
grid-template-columns: 32px 1fr minmax(32px, auto);
justify-content: flex-start;
align-items: center;
border-radius: 4px;
cursor: pointer;
}
menu-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
menu-item > menu-icon {
height: 32px;
padding: 4px;
box-sizing: border-box;
}
menu-separator {
min-height: 1px;
height: 1px;
margin: 4px 0;
background-color: rgba(255, 255, 255, 0.2);
}
/* classes */
.title-bar-icon {
height: calc(100% - 8px);
object-fit: cover;
margin-left: -4px;
}
/* Window control container */
.window-controls-container {
-webkit-app-region: no-drag;
display: flex;
justify-content: flex-end; /* Align to the right end of the title-bar */
align-items: center;
gap: 4px; /* Add spacing between the window control buttons */
position: absolute; /* Position it absolutely within title-bar */
right: 4px; /* Adjust the right position as needed */
}
/* Window control buttons */
.window-control {
width: 24px;
height: 24px;
background: none;
border: none;
cursor: pointer;
display: flex;
align-items: center;
color: #f1f1f1;
font-size: 14px;
padding: 0;
}
/* youtube-music style */
ytmusic-app-layout {
@ -185,6 +25,19 @@ ytmusic-app[is-bauhaus-sidenav-enabled] #mini-guide-spacer.ytmusic-app {
) !important;
}
@media (max-width: 935px) {
ytmusic-app[is-bauhaus-sidenav-enabled] #guide-spacer.ytmusic-app {
margin-top: calc(
var(--menu-bar-height, 36px)
) !important;
}
ytmusic-app[is-bauhaus-sidenav-enabled] #mini-guide-spacer.ytmusic-app {
margin-top: calc(
var(--ytmusic-nav-bar-height) + var(--menu-bar-height, 36px)
) !important;
}
}
ytmusic-app-layout > [slot='player-page'] {
margin-top: var(--menu-bar-height);
height: calc(
@ -198,3 +51,8 @@ ytmusic-guide-renderer {
100vh - var(--menu-bar-height) - var(--ytmusic-nav-bar-height)
) !important;
}
/* ytm-bugs: see https://github.com/th-ch/youtube-music/issues/1737 */
html {
scrollbar-color: unset;
}

View File

@ -1,80 +0,0 @@
import { createPlugin } from '@/utils';
import registerCallback from '@/providers/song-info';
import { addScrobble, getAndSetSessionKey, setNowPlaying } from './main';
import { t } from '@/i18n';
export interface LastFmPluginConfig {
enabled: boolean;
/**
* Token used for authentication
*/
token?: string;
/**
* Session key used for scrabbling
*/
session_key?: string;
/**
* Root of the Last.fm API
*
* @default 'http://ws.audioscrobbler.com/2.0/'
*/
api_root: string;
/**
* Last.fm api key registered by @semvis123
*
* @default '04d76faaac8726e60988e14c105d421a'
*/
api_key: string;
/**
* Last.fm api secret registered by @semvis123
*
* @default 'a5d2a36fdf64819290f6982481eaffa2'
*/
secret: string;
}
export default createPlugin({
name: () => t('plugins.last-fm.name'),
description: () => t('plugins.last-fm.description'),
restartNeeded: true,
config: {
enabled: false,
api_root: 'http://ws.audioscrobbler.com/2.0/',
api_key: '04d76faaac8726e60988e14c105d421a',
secret: 'a5d2a36fdf64819290f6982481eaffa2',
} as LastFmPluginConfig,
async backend({ getConfig, setConfig }) {
let config = await getConfig();
// This will store the timeout that will trigger addScrobble
let scrobbleTimer: number | undefined;
if (!config.api_root) {
config.enabled = true;
setConfig(config);
}
if (!config.session_key) {
// Not authenticated
config = await getAndSetSessionKey(config, setConfig);
}
registerCallback((songInfo) => {
// Set remove the old scrobble timer
clearTimeout(scrobbleTimer);
if (!songInfo.isPaused) {
setNowPlaying(songInfo, config, setConfig);
// Scrobble when the song is halfway through, or has passed the 4-minute mark
const scrobbleTime = Math.min(
Math.ceil(songInfo.songDuration / 2),
4 * 60,
);
if (scrobbleTime > (songInfo.elapsedSeconds ?? 0)) {
// Scrobble still needs to happen
const timeToWait =
(scrobbleTime - (songInfo.elapsedSeconds ?? 0)) * 1000;
scrobbleTimer = setTimeout(addScrobble, timeToWait, songInfo, config);
}
}
});
},
});

View File

@ -1,207 +0,0 @@
import crypto from 'node:crypto';
import { net, shell } from 'electron';
import type { LastFmPluginConfig } from './index';
import type { SongInfo } from '@/providers/song-info';
interface LastFmData {
method: string;
timestamp?: number;
}
interface LastFmSongData {
track?: string;
duration?: number;
artist?: string;
album?: string;
api_key: string;
sk?: string;
format: string;
method: string;
timestamp?: number;
api_sig?: string;
}
const createFormData = (parameters: LastFmSongData) => {
// Creates the body for in the post request
const formData = new URLSearchParams();
for (const key in parameters) {
formData.append(key, String(parameters[key as keyof LastFmSongData]));
}
return formData;
};
const createQueryString = (
parameters: Record<string, unknown>,
apiSignature: string,
) => {
// Creates a querystring
const queryData = [];
parameters.api_sig = apiSignature;
for (const key in parameters) {
queryData.push(
`${encodeURIComponent(key)}=${encodeURIComponent(
String(parameters[key]),
)}`,
);
}
return '?' + queryData.join('&');
};
const createApiSig = (parameters: LastFmSongData, secret: string) => {
// This function creates the api signature, see: https://www.last.fm/api/authspec
const keys = Object.keys(parameters);
keys.sort();
let sig = '';
for (const key of keys) {
if (key === 'format') {
continue;
}
sig += `${key}${parameters[key as keyof LastFmSongData]}`;
}
sig += secret;
sig = crypto.createHash('md5').update(sig, 'utf-8').digest('hex');
return sig;
};
const createToken = async ({
api_key: apiKey,
api_root: apiRoot,
secret,
}: LastFmPluginConfig) => {
// Creates and stores the auth token
const data = {
method: 'auth.gettoken',
api_key: apiKey,
format: 'json',
};
const apiSigature = createApiSig(data, secret);
const response = await net.fetch(
`${apiRoot}${createQueryString(data, apiSigature)}`,
);
const json = (await response.json()) as Record<string, string>;
return json?.token;
};
const authenticate = async (config: LastFmPluginConfig) => {
// Asks the user for authentication
await shell.openExternal(
`https://www.last.fm/api/auth/?api_key=${config.api_key}&token=${config.token}`,
);
};
type SetConfType = (
conf: Partial<Omit<LastFmPluginConfig, 'enabled'>>,
) => void | Promise<void>;
export const getAndSetSessionKey = async (
config: LastFmPluginConfig,
setConfig: SetConfType,
) => {
// Get and store the session key
const data = {
api_key: config.api_key,
format: 'json',
method: 'auth.getsession',
token: config.token,
};
const apiSignature = createApiSig(data, config.secret);
const response = await net.fetch(
`${config.api_root}${createQueryString(data, apiSignature)}`,
);
const json = (await response.json()) as {
error?: string;
session?: {
key: string;
};
};
if (json.error) {
config.token = await createToken(config);
await authenticate(config);
setConfig(config);
}
if (json.session) {
config.session_key = json.session.key;
}
setConfig(config);
return config;
};
const postSongDataToAPI = async (
songInfo: SongInfo,
config: LastFmPluginConfig,
data: LastFmData,
setConfig: SetConfType,
) => {
// This sends a post request to the api, and adds the common data
if (!config.session_key) {
await getAndSetSessionKey(config, setConfig);
}
const postData: LastFmSongData = {
track: songInfo.title,
duration: songInfo.songDuration,
artist: songInfo.artist,
...(songInfo.album ? { album: songInfo.album } : undefined), // Will be undefined if current song is a video
api_key: config.api_key,
sk: config.session_key,
format: 'json',
...data,
};
postData.api_sig = createApiSig(postData, config.secret);
const formData = createFormData(postData);
net
.fetch('https://ws.audioscrobbler.com/2.0/', {
method: 'POST',
body: formData,
})
.catch(
async (error: {
response?: {
data?: {
error: number;
};
};
}) => {
if (error?.response?.data?.error === 9) {
// Session key is invalid, so remove it from the config and reauthenticate
config.session_key = undefined;
config.token = await createToken(config);
await authenticate(config);
setConfig(config);
}
},
);
};
export const addScrobble = (
songInfo: SongInfo,
config: LastFmPluginConfig,
setConfig: SetConfType,
) => {
// This adds one scrobbled song to last.fm
const data = {
method: 'track.scrobble',
timestamp: Math.trunc((Date.now() - (songInfo.elapsedSeconds ?? 0)) / 1000),
};
postSongDataToAPI(songInfo, config, data, setConfig);
};
export const setNowPlaying = (
songInfo: SongInfo,
config: LastFmPluginConfig,
setConfig: SetConfType,
) => {
// This sets the now playing status in last.fm
const data = {
method: 'track.updateNowPlaying',
};
postSongDataToAPI(songInfo, config, data, setConfig);
};

View File

@ -38,7 +38,7 @@ export const fetchFromGenius = async (metadata: SongInfo) => {
const songArtist = `${cleanupName(metadata.artist)}`;
let lyrics: string | null;
/* Uses Regex to test the title and artist first for said characters if romanization is enabled. Otherwise normal
/* Uses Regex to test the title and artist first for said characters if romanization is enabled. Otherwise, normal
Genius Lyrics behavior is observed.
*/
let hasAsianChars = false;

View File

@ -32,7 +32,7 @@ export const onRendererLoad = ({
let unregister: (() => void) | null = null;
on('update-song-info', (extractedSongInfo: SongInfo) => {
on('ytmd:update-song-info', (extractedSongInfo: SongInfo) => {
unregister?.();
setTimeout(async () => {

View File

@ -0,0 +1,149 @@
import { DataConnection, Peer } from 'peerjs';
import type { Permission, Profile, VideoData } from './types';
export type ConnectionEventMap = {
ADD_SONGS: { videoList: VideoData[], index?: number };
REMOVE_SONG: { index: number };
MOVE_SONG: { fromIndex: number; toIndex: number };
IDENTIFY: { profile: Profile } | undefined;
SYNC_PROFILE: { profiles: Record<string, Profile> } | undefined;
SYNC_QUEUE: { videoList: VideoData[] } | undefined;
SYNC_PROGRESS: { progress?: number; state?: number; index?: number; } | undefined;
PERMISSION: Permission | undefined;
};
export type ConnectionEventUnion = {
[Event in keyof ConnectionEventMap]: {
type: Event;
payload: ConnectionEventMap[Event];
after?: ConnectionEventUnion[];
};
}[keyof ConnectionEventMap];
type PromiseUtil<T> = {
promise: Promise<T>;
resolve: (id: T) => void;
reject: (err: unknown) => void;
}
export type ConnectionListener = (event: ConnectionEventUnion, conn: DataConnection) => void;
export type ConnectionMode = 'host' | 'guest' | 'disconnected';
export class Connection {
private peer: Peer;
private _mode: ConnectionMode = 'disconnected';
private connections: Record<string, DataConnection> = {};
private waitOpen: PromiseUtil<string> = {} as PromiseUtil<string>;
private listeners: ConnectionListener[] = [];
private connectionListeners: ((connection?: DataConnection) => void)[] = [];
constructor() {
this.peer = new Peer({ debug: 0 });
this.waitOpen.promise = new Promise<string>((resolve, reject) => {
this.waitOpen.resolve = resolve;
this.waitOpen.reject = reject;
});
this.peer.on('open', (id) => {
this._mode = 'host';
this.waitOpen.resolve(id);
});
this.peer.on('connection', (conn) => {
this._mode = 'host';
this.registerConnection(conn);
});
this.peer.on('error', (err) => {
this._mode = 'disconnected';
this.waitOpen.reject(err);
this.connectionListeners.forEach((listener) => listener());
console.log(err);
});
}
/* public */
async waitForReady() {
return this.waitOpen.promise;
}
async connect(id: string) {
this._mode = 'guest';
const conn = this.peer.connect(id);
await this.registerConnection(conn);
return conn;
}
disconnect() {
if (this._mode === 'disconnected') throw new Error('Already disconnected');
this._mode = 'disconnected';
this.connections = {};
this.peer.destroy();
}
/* utils */
public get id() {
return this.peer.id;
}
public get mode() {
return this._mode;
}
public getConnections() {
return Object.values(this.connections);
}
public async broadcast<Event extends keyof ConnectionEventMap>(type: Event, payload: ConnectionEventMap[Event]) {
await Promise.all(
this.getConnections().map((conn) => conn.send({ type, payload }))
);
}
public on(listener: ConnectionListener) {
this.listeners.push(listener);
}
public onConnections(listener: (connections?: DataConnection) => void) {
this.connectionListeners.push(listener);
}
/* privates */
private async registerConnection(conn: DataConnection) {
return new Promise<DataConnection>((resolve, reject) => {
this.peer.once('error', (err) => {
this._mode = 'disconnected';
reject(err);
this.connectionListeners.forEach((listener) => listener());
});
conn.on('open', () => {
this.connections[conn.connectionId] = conn;
resolve(conn);
this.connectionListeners.forEach((listener) => listener(conn));
conn.on('data', (data) => {
if (!data || typeof data !== 'object' || !('type' in data) || !('payload' in data) || !data.type) {
console.warn('Music Together: Invalid data', data);
return;
}
for (const listener of this.listeners) {
listener(data as ConnectionEventUnion, conn);
}
});
});
const onClose = (err?: Error) => {
if (err) reject(err);
delete this.connections[conn.connectionId];
this.connectionListeners.forEach((listener) => listener(conn));
};
conn.on('error', onClose);
conn.on('close', onClose);
});
}
}

View File

@ -0,0 +1,138 @@
import { ElementFromHtml } from '@/plugins/utils/renderer';
import itemHTML from './templates/item.html?raw';
import popupHTML from './templates/popup.html?raw';
type Placement =
'top'
| 'bottom'
| 'right'
| 'left'
| 'center'
| 'middle'
| 'center-middle'
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right';
type PopupItem = (ItemRendererProps & { type: 'item'; })
| { type: 'divider'; }
| { type: 'custom'; element: HTMLElement; };
type PopupProps = {
data: PopupItem[];
anchorAt?: Placement;
popupAt?: Placement;
}
export const Popup = (props: PopupProps) => {
const popup = ElementFromHtml(popupHTML);
const container = popup.querySelector<HTMLElement>('.music-together-popup-container')!;
const items = props.data
.map((props) => {
if (props.type === 'item') return {
type: 'item' as const,
...ItemRenderer(props),
};
if (props.type === 'divider') return {
type: 'divider' as const,
element: ElementFromHtml('<div class="music-together-divider horizontal"></div>'),
};
if (props.type === 'custom') return {
type: 'custom' as const,
element: props.element,
};
return null;
})
.filter(Boolean);
container.append(...items.map(({ element }) => element));
popup.style.setProperty('opacity', '0');
popup.style.setProperty('pointer-events', 'none');
document.body.append(popup);
return {
element: popup,
container,
items,
show(x: number, y: number, anchor?: HTMLElement) {
let left = x;
let top = y;
if (anchor) {
if (props.anchorAt?.includes('right')) left += anchor.clientWidth;
if (props.anchorAt?.includes('bottom')) top += anchor.clientHeight;
if (props.anchorAt?.includes('center')) left += anchor.clientWidth / 2;
if (props.anchorAt?.includes('middle')) top += anchor.clientHeight / 2;
}
if (props.popupAt?.includes('right')) left -= popup.clientWidth;
if (props.popupAt?.includes('bottom')) top -= popup.clientHeight;
if (props.popupAt?.includes('center')) left -= popup.clientWidth / 2;
if (props.popupAt?.includes('middle')) top -= popup.clientHeight / 2;
popup.style.setProperty('left', `${left}px`);
popup.style.setProperty('top', `${top}px`);
popup.style.setProperty('opacity', '1');
popup.style.setProperty('pointer-events', 'unset');
setTimeout(() => {
const onClose = (event: MouseEvent) => {
const isPopupClick = event.composedPath().some((element) => element === popup);
if (!isPopupClick) {
this.dismiss();
document.removeEventListener('click', onClose);
}
};
document.addEventListener('click', onClose);
}, 16);
},
showAtAnchor(anchor: HTMLElement) {
const { x, y } = anchor.getBoundingClientRect();
this.show(x, y, anchor);
},
isShowing() {
return popup.style.getPropertyValue('opacity') === '1';
},
dismiss() {
popup.style.setProperty('opacity', '0');
popup.style.setProperty('pointer-events', 'none');
}
};
};
type ItemRendererProps = {
id?: string;
icon?: Element;
text: string;
onClick?: () => void;
};
export const ItemRenderer = (props: ItemRendererProps) => {
const element = ElementFromHtml(itemHTML);
const iconContainer = element.querySelector<HTMLElement>('div.icon')!;
const textContainer = element.querySelector<HTMLElement>('div.text')!;
if (props.icon) iconContainer.appendChild(props.icon);
textContainer.append(props.text);
if (props.onClick) {
element.addEventListener('click', () => {
props.onClick?.();
});
}
if (props.id) element.id = props.id;
return {
element,
setIcon(icon: Element) {
iconContainer.replaceChildren(icon);
},
setText(text: string) {
textContainer.replaceChildren(text);
},
id: props.id
};
};

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path d="M480-640 280-440l56 56 104-103v407h80v-407l104 103 56-56-200-200ZM146-260q-32-49-49-105T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 59-17 115t-49 105l-58-58q22-37 33-78t11-84q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 43 11 84t33 78l-58 58Z"/>
</svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path
d="M280-400q-33 0-56.5-23.5T200-480q0-33 23.5-56.5T280-560q33 0 56.5 23.5T360-480q0 33-23.5 56.5T280-400Zm0 160q-100 0-170-70T40-480q0-100 70-170t170-70q67 0 121.5 33t86.5 87h352l120 120-180 180-80-60-80 60-85-60h-47q-32 54-86.5 87T280-240Zm0-80q56 0 98.5-34t56.5-86h125l58 41 82-61 71 55 75-75-40-40H435q-14-52-56.5-86T280-640q-66 0-113 47t-47 113q0 66 47 113t113 47Z"/>
</svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path d="M560-160q-66 0-113-47t-47-113q0-66 47-113t113-47q23 0 42.5 5.5T640-458v-342h240v120H720v360q0 66-47 113t-113 47ZM80-320q0-99 38-186.5T221-659q65-65 152.5-103T560-800v80q-82 0-155 31.5t-127.5 86q-54.5 54.5-86 127T160-320H80Zm160 0q0-66 25.5-124.5t69-102Q378-590 436-615t124-25v80q-100 0-170 70t-70 170h-80Z"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path
d="M792-56 686-160H260q-92 0-156-64T40-380q0-77 47.5-137T210-594q3-8 6-15.5t6-16.5L56-792l56-56 736 736-56 56ZM260-240h346L284-562q-2 11-3 21t-1 21h-20q-58 0-99 41t-41 99q0 58 41 99t99 41Zm185-161Zm419 191-58-56q17-14 25.5-32.5T840-340q0-42-29-71t-71-29h-60v-80q0-83-58.5-141.5T480-720q-27 0-52 6.5T380-693l-58-58q35-24 74.5-36.5T480-800q117 0 198.5 81.5T760-520q69 8 114.5 59.5T920-340q0 39-15 72.5T864-210ZM593-479Z"/>
</svg>

After

Width:  |  Height:  |  Size: 529 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
<path d="M440-120v-240h80v80h320v80H520v80h-80Zm-320-80v-80h240v80H120Zm160-160v-80H120v-80h160v-80h80v240h-80Zm160-80v-80h400v80H440Zm160-160v-240h80v80h160v80H680v80h-80Zm-480-80v-80h400v80H120Z"/>
</svg>

After

Width:  |  Height:  |  Size: 298 B

Some files were not shown because too many files have changed in this diff Show More