Compare commits

..

112 Commits

Author SHA1 Message Date
c94b22b82c Bump version to 3.5.3 2024-09-17 21:32:22 +09:00
cab3cb49f0 chore(deps): update dependency electron to v32.1.0 2024-09-17 21:31:29 +09:00
e42084f008 fix(deps): update dependency @floating-ui/dom to v1.6.11 2024-09-17 21:30:11 +09:00
adca273ec3 chore(deps): update dependency typescript to v5.6.2 2024-09-17 21:28:03 +09:00
91dceb3c22 chore(deps): update playwright monorepo to v1.47.1 2024-09-17 21:27:47 +09:00
216e76f4a1 fix(music-together): fix ? operator 2024-09-17 21:09:30 +09:00
178bfa483f fix: openToast to toastService 2024-09-17 21:05:35 +09:00
10ecf5d2fe fix(src/index): fix typo 2024-09-17 20:40:23 +09:00
7099b81296 fix(src/index): ignore eslint error 2024-09-17 20:40:23 +09:00
1f15376b00 chore(deps): update dependency vite to v5.4.6 2024-09-17 20:39:32 +09:00
02b7a39753 chore(deps): update dependency eslint to v8.57.1 2024-09-17 20:38:38 +09:00
6edc84a8bd chore(deps): update dependency rollup to v4.21.3 2024-09-17 20:38:19 +09:00
11a0d39064 fix(song-info-front): fix nullable issue 2024-09-17 20:27:11 +09:00
d5a5ed35b6 fix: fix trustedHTML issue
- (Maybe) fix #2339, caused by YouTube's A/B testing
2024-09-17 20:05:22 +09:00
dbb9e95b32 fix(deps): update dependency i18next to v23.15.1 2024-09-17 18:27:27 +09:00
d4c8a4320d chore(deps): update typescript-eslint monorepo to v8.6.0 2024-09-17 18:27:05 +09:00
68d4f38e41 chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 94.7% (362 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-09-15 22:09:12 +00:00
2204784e89 chore(i18n): Translated using Weblate (Icelandic)
Currently translated at 92.9% (355 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/is/
2024-09-15 22:09:12 +00:00
c3b995b0a8 chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 6.0% (23 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2024-09-11 22:09:24 +02:00
ed0a344077 chore(i18n): Translated using Weblate (Polish)
Currently translated at 95.2% (364 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pl/
2024-09-09 22:09:15 +00:00
199d912823 Update changelog for v3.5.2 2024-09-07 12:27:30 +00:00
089eff3152 Revert "chore(deps): update dependency electron-builder to v25"
This reverts commit fe4c89c349.
2024-09-07 20:22:27 +09:00
306ee8dba5 Bump version to 3.5.2 2024-09-07 19:09:15 +09:00
a4992bafb2 fix(synced-lyric): fix timestamp
- Close #2323
- Close #2379
2024-09-07 19:06:52 +09:00
5b004eedff fix(song-info): fix regex 2024-09-07 18:40:24 +09:00
2a66076d31 fix(synced-lyric): optimize logic 2024-09-07 18:37:37 +09:00
f48e46d29c chore(deps): update dependency eslint-plugin-import to v2.30.0 2024-09-07 18:29:22 +09:00
20296f5463 chore(deps): update dependency rollup to v4.21.2 2024-09-07 18:29:16 +09:00
fe4c89c349 chore(deps): update dependency electron-builder to v25 2024-09-07 18:29:09 +09:00
3640527c8c fix(synced-lyrics): LRCLIB returns 0 results if album is undefined
- inspired by #2381
2024-09-07 18:28:13 +09:00
3326582a16 chore(deps): update dependency electron to v32 2024-09-07 18:21:41 +09:00
5dcb9fe9ba fix(deps): update dependency i18next to v23.14.0 2024-09-07 18:19:15 +09:00
336fa1e6fd fix(deps): update dependency youtubei.js to v10.4.0 2024-09-07 18:19:09 +09:00
3679a109d6 chore(deps): update dependency esbuild to v0.23.1 2024-09-07 18:15:01 +09:00
5290ed3de2 chore(deps): update playwright monorepo to v1.47.0 2024-09-07 18:14:40 +09:00
fe5195714f chore(deps): update typescript-eslint monorepo to v8.4.0 (#2401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:14:27 +09:00
8eb846262d chore(deps): update dependency @total-typescript/ts-reset to v0.6.1 (#2396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:09:00 +09:00
e9a1c2a91f chore(deps): update dependency electron to v31.5.0 (#2397)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:08:41 +09:00
2d1f78b383 chore(deps): update dependency eslint-import-resolver-typescript to v3.6.3 (#2376)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:06:07 +09:00
1899064fd3 chore(deps): update dependency discord-api-types to v0.37.100 (#2394)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:06:00 +09:00
e0280e5fe2 fix(deps): update dependency electron-updater to v6.3.4 (#2395)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 18:05:54 +09:00
d577e0fba6 chore(deps): update dependency @babel/runtime to v7.25.6 (#2388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 17:26:24 +09:00
37577c2f7f chore(deps): update dependency vite-plugin-inspect to v0.8.7 (#2389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-07 17:26:16 +09:00
c880f0a4eb chore(i18n): Translated using Weblate (Portuguese)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt/
2024-09-05 21:09:15 +02:00
4875955914 chore(deps): update dependency discord-api-types to v0.37.99 (#2374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-04 23:47:50 +09:00
5b28c780bd chore(deps): update dependency vite to v5.4.3 (#2377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-04 23:47:42 +09:00
4db2674b15 chore(i18n): Translated using Weblate (Greek)
Currently translated at 52.6% (201 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/el/
2024-09-02 23:09:12 +00:00
Sen
a454a0163f chore(i18n): Translated using Weblate (Dutch)
Currently translated at 74.0% (283 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/nl/
2024-08-31 21:09:31 +02:00
61eb28e780 fix: incorrect regex when splitting artistName (#2378)
Fixes the incorrect regex used to split a string in the form of `Name1 & Name2` or `Name1, Name2`.

Previously the regex was actually splitting on `Name1 &, Name2`...
2024-08-29 07:48:18 +09:00
e165e64952 chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 93.7% (358 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-08-28 13:09:22 +00:00
f380822e11 chore(deps): update dependency @babel/runtime to v7.25.4 (#2373)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-28 12:22:29 +09:00
6b1995145a synced-lyrics: make the lyrics search more reliable (#2343)
* fix: comparing multiple artists on a single track

* fix: get song info on startup

* chore: also split on commas

* chore: re-apply .toLowerCase() on the artist names

* chore: remove redundant code

* chore: attempt at improving the initial videodata

* oops

* eureka!

* stuff
2024-08-28 12:21:58 +09:00
9317e99f43 fix(deps): update dependency solid-js to v1.8.22 (#2354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-28 12:20:37 +09:00
66d05d8683 chore(deps): update typescript-eslint monorepo to v8.3.0 (#2350)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-28 12:20:26 +09:00
545a3a4bb6 fix(deps): update dependency electron-debug to v4.0.1 (#2349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-28 12:20:07 +09:00
04a6d16dbe chore(deps): update dependency electron to v31.4.0 (#2356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-28 12:19:53 +09:00
3c36477b1e fix: hide native-controls on linux when in-app-menu is used (#2366) 2024-08-28 12:19:30 +09:00
c5c191492e fix: detect the upgrade btn using the icon (#2364) 2024-08-23 07:13:55 +09:00
b12e2f607c chore(i18n): Translated using Weblate (Filipino)
Currently translated at 86.6% (331 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fil/
2024-08-20 03:09:10 +00:00
1d77ad6de4 fix: exclude build-id files from rpm (#2361) 2024-08-19 07:46:05 +09:00
25bd26d7f3 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-17 12:09:10 +02:00
d11d0abe73 chore(i18n): Translated using Weblate (Japanese)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ja/
2024-08-17 12:09:10 +02:00
8a643c465d chore(i18n): Translated using Weblate (Estonian)
Currently translated at 18.8% (72 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2024-08-15 22:09:31 +00:00
233673b8d8 chore(i18n): Translated using Weblate (Estonian)
Currently translated at 14.1% (54 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2024-08-13 21:09:13 +02:00
5a448fab31 chore(i18n): Translated using Weblate (Catalan)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ca/
2024-08-13 21:09:12 +02:00
42e8262cda fix(deps): update dependency i18next to v23.12.3 (#2352)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-13 11:57:27 +09:00
f64769b1d3 fix(deps): update dependency @floating-ui/dom to v1.6.10 (#2340)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 12:12:08 +09:00
e12998761b fix(deps): update dependency electron-updater to v6.3.3 (#2347)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-12 12:11:55 +09:00
2e20fa83b8 chore(i18n): Translated using Weblate (German)
Currently translated at 99.2% (379 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-11 10:09:24 +00:00
5149757af3 chore(i18n): Translated using Weblate (German)
Currently translated at 99.2% (379 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-11 10:09:24 +00:00
655741f108 chore(i18n): Translated using Weblate (German)
Currently translated at 96.3% (368 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-10 11:41:12 +02:00
4e58571ad0 chore(i18n): Translated using Weblate (German)
Currently translated at 96.3% (368 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-10 11:41:12 +02:00
1e4a615b47 chore(i18n): Translated using Weblate (German)
Currently translated at 94.7% (362 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-10 11:39:20 +02:00
dedcf0c9ff fix(deps): update dependency solid-js to v1.8.20 (#2345)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-10 10:58:28 +09:00
a84a7d236a chore(deps): update dependency vite to v5.4.0 (#2342)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-10 10:54:05 +09:00
e56b4b21f0 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-08-09 16:09:15 +02:00
361f9e42bd chore(i18n): Translated using Weblate (Malay)
Currently translated at 19.6% (75 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ms/
2024-08-09 16:09:13 +02:00
918736d2ca chore(i18n): Translated using Weblate (German)
Currently translated at 94.2% (360 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2024-08-09 16:09:12 +02:00
8f3d5b08ac chore(i18n): Translated using Weblate (Russian)
Currently translated at 97.3% (372 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-08-08 00:09:19 +02:00
4ca327d801 chore(deps): update typescript-eslint monorepo to v8.0.1 (#2335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-07 23:03:13 +09:00
8d0aa057ad fix(deps): update dependency @floating-ui/dom to v1.6.9 (#2337)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-07 23:02:23 +09:00
b7ffee089b chore(deps): update playwright monorepo to v1.46.0 (#2336)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-07 23:02:12 +09:00
d72b994f66 chore(README): Translation README to Russian and adding Synced Lyrics to main README (#2338)
* Translation of README.md to Russian and adding Synced Lyrics to default README.md

* Syntax fixes

* Sorting of Synced Lyrics Alphabetically
2024-08-07 23:01:49 +09:00
e6dafdb068 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-08-06 11:09:21 +02:00
14886dd4bd chore(i18n): Translated using Weblate (Catalan)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ca/
2024-08-06 11:09:17 +02:00
c9f2f88bac chore(i18n): Translated using Weblate (Russian)
Currently translated at 97.3% (372 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ru/
2024-08-06 11:09:17 +02:00
1eabbc0bbe chore(i18n): Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2024-08-05 09:09:19 +02:00
32a572b35a fix(downloader): fix playabilityStatus 2024-08-04 16:33:28 +09:00
59a5679cbb fix(cache): use cacheNoArgs for better performance 2024-08-04 16:31:07 +09:00
ac51f798c3 fix(synced-lyric): fix album_name 2024-08-04 15:49:30 +09:00
7599cc694a Revert "fix(MPRIS): Prevents player to start with invalid MPRIS interface (#1996)"
This reverts commit eaf9d310aa.

Fix #2225
2024-08-04 15:26:14 +09:00
53595654b1 chore(adblocker): add comment 2024-08-04 14:50:14 +09:00
7656c41dbc fix(adblocker/inplayer): fix Response.prototype.json
fix #2310
2024-08-04 14:36:10 +09:00
ff0c5b87c9 chore(i18n): Translated using Weblate (Estonian)
Currently translated at 2.8% (11 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2024-08-03 22:09:19 +00:00
506c95740a chore(i18n): Translated using Weblate (Vietnamese)
Currently translated at 99.4% (380 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/vi/
2024-08-03 22:09:18 +00:00
575a42e28a chore(i18n): Translated using Weblate (Indonesian)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/id/
2024-08-03 22:09:17 +00:00
dcdc6a825f chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-03 22:09:16 +00:00
0a41bb1cd6 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-03 22:09:16 +00:00
72a4736dc9 chore(i18n): Translated using Weblate (Greek)
Currently translated at 47.3% (181 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/el/
2024-08-03 22:09:15 +00:00
f2b1e6b6bf chore(deps): update dependency rollup to v4.20.0 (#2326)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-03 18:47:56 +09:00
bc0e28ad6d chore(i18n): Added translation using Weblate (Estonian) 2024-08-02 23:59:14 +02:00
8ebae91c02 chore(i18n): Translated using Weblate (Hungarian)
Currently translated at 93.7% (358 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hu/
2024-08-02 23:59:13 +02:00
954ad90733 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-02 23:59:13 +02:00
5af0643788 chore(i18n): Translated using Weblate (French)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fr/
2024-08-02 23:59:13 +02:00
be633ac1f2 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 99.7% (381 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-02 21:58:41 +02:00
0d047c1fd5 chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 99.7% (381 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-02 21:58:41 +02:00
e8b1aca629 chore(i18n): Translated using Weblate (Turkish)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/tr/
2024-08-02 21:58:41 +02:00
5b9bacf390 chore(i18n): Translated using Weblate (Filipino)
Currently translated at 85.3% (326 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/fil/
2024-08-02 14:09:23 +02:00
ccd16f4a5f chore(i18n): Translated using Weblate (Chinese (Traditional))
Currently translated at 93.4% (357 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2024-08-02 14:09:22 +02:00
02e519dab3 chore(i18n): Translated using Weblate (Spanish)
Currently translated at 100.0% (382 of 382 strings)

Translation: th-ch/youtube-music/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/es/
2024-08-02 14:09:21 +02:00
473ea78f12 synced-lyrics: fix album name? 2024-08-01 15:46:53 +03:00
e7f366b770 Update changelog for v3.5.1 2024-08-01 11:49:06 +00:00
49 changed files with 2934 additions and 989 deletions

View File

@ -21,7 +21,7 @@
</a>
</div>
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md)
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md), [🇷🇺](./docs/readme/README-ru.md)
**Electron wrapper around YouTube Music featuring:**
@ -141,6 +141,8 @@ Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸]
- [**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
- **Synced Lyrics**: Provides synced lyrics to songs, using providers like [LRClib](https://lrclib.net).
- **Taskbar Media Control**: Control playback from
your [Windows taskbar](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
@ -159,6 +161,7 @@ Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇮🇸]
- **Visualizer**: Different music visualizers
## Translation
You can help with translation on [Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/).

View File

@ -2,8 +2,66 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v3.5.2](https://github.com/th-ch/youtube-music/compare/v3.5.1...v3.5.2)
- chore(deps): update typescript-eslint monorepo to v8.4.0 [`#2401`](https://github.com/th-ch/youtube-music/pull/2401)
- chore(deps): update dependency @total-typescript/ts-reset to v0.6.1 [`#2396`](https://github.com/th-ch/youtube-music/pull/2396)
- chore(deps): update dependency electron to v31.5.0 [`#2397`](https://github.com/th-ch/youtube-music/pull/2397)
- chore(deps): update dependency eslint-import-resolver-typescript to v3.6.3 [`#2376`](https://github.com/th-ch/youtube-music/pull/2376)
- chore(deps): update dependency discord-api-types to v0.37.100 [`#2394`](https://github.com/th-ch/youtube-music/pull/2394)
- fix(deps): update dependency electron-updater to v6.3.4 [`#2395`](https://github.com/th-ch/youtube-music/pull/2395)
- chore(deps): update dependency @babel/runtime to v7.25.6 [`#2388`](https://github.com/th-ch/youtube-music/pull/2388)
- chore(deps): update dependency vite-plugin-inspect to v0.8.7 [`#2389`](https://github.com/th-ch/youtube-music/pull/2389)
- chore(deps): update dependency discord-api-types to v0.37.99 [`#2374`](https://github.com/th-ch/youtube-music/pull/2374)
- chore(deps): update dependency vite to v5.4.3 [`#2377`](https://github.com/th-ch/youtube-music/pull/2377)
- fix: incorrect regex when splitting artistName [`#2378`](https://github.com/th-ch/youtube-music/pull/2378)
- chore(deps): update dependency @babel/runtime to v7.25.4 [`#2373`](https://github.com/th-ch/youtube-music/pull/2373)
- synced-lyrics: make the lyrics search more reliable [`#2343`](https://github.com/th-ch/youtube-music/pull/2343)
- fix(deps): update dependency solid-js to v1.8.22 [`#2354`](https://github.com/th-ch/youtube-music/pull/2354)
- chore(deps): update typescript-eslint monorepo to v8.3.0 [`#2350`](https://github.com/th-ch/youtube-music/pull/2350)
- fix(deps): update dependency electron-debug to v4.0.1 [`#2349`](https://github.com/th-ch/youtube-music/pull/2349)
- chore(deps): update dependency electron to v31.4.0 [`#2356`](https://github.com/th-ch/youtube-music/pull/2356)
- fix: hide native-controls on linux when in-app-menu is used [`#2366`](https://github.com/th-ch/youtube-music/pull/2366)
- fix: detect the upgrade btn using the icon [`#2364`](https://github.com/th-ch/youtube-music/pull/2364)
- fix: exclude build-id files from rpm [`#2361`](https://github.com/th-ch/youtube-music/pull/2361)
- fix(deps): update dependency i18next to v23.12.3 [`#2352`](https://github.com/th-ch/youtube-music/pull/2352)
- fix(deps): update dependency @floating-ui/dom to v1.6.10 [`#2340`](https://github.com/th-ch/youtube-music/pull/2340)
- fix(deps): update dependency electron-updater to v6.3.3 [`#2347`](https://github.com/th-ch/youtube-music/pull/2347)
- fix(deps): update dependency solid-js to v1.8.20 [`#2345`](https://github.com/th-ch/youtube-music/pull/2345)
- chore(deps): update dependency vite to v5.4.0 [`#2342`](https://github.com/th-ch/youtube-music/pull/2342)
- chore(deps): update typescript-eslint monorepo to v8.0.1 [`#2335`](https://github.com/th-ch/youtube-music/pull/2335)
- fix(deps): update dependency @floating-ui/dom to v1.6.9 [`#2337`](https://github.com/th-ch/youtube-music/pull/2337)
- chore(deps): update playwright monorepo to v1.46.0 [`#2336`](https://github.com/th-ch/youtube-music/pull/2336)
- chore(README): Translation README to Russian and adding Synced Lyrics to main README [`#2338`](https://github.com/th-ch/youtube-music/pull/2338)
- chore(deps): update dependency rollup to v4.20.0 [`#2326`](https://github.com/th-ch/youtube-music/pull/2326)
- fix(synced-lyric): fix timestamp [`#2323`](https://github.com/th-ch/youtube-music/issues/2323) [`#2379`](https://github.com/th-ch/youtube-music/issues/2379)
- Revert "fix(MPRIS): Prevents player to start with invalid MPRIS interface (#1996)" [`#2225`](https://github.com/th-ch/youtube-music/issues/2225)
- fix(adblocker/inplayer): fix Response.prototype.json [`#2310`](https://github.com/th-ch/youtube-music/issues/2310)
- chore(deps): update dependency eslint-plugin-import to v2.30.0 [`f48e46d`](https://github.com/th-ch/youtube-music/commit/f48e46d29cf09c76c5172fd56d2d0f705616e4e3)
- Revert "chore(deps): update dependency electron-builder to v25" [`089eff3`](https://github.com/th-ch/youtube-music/commit/089eff3152903c8b55ad3e5571b944062a647e27)
- chore(deps): update dependency electron-builder to v25 [`fe4c89c`](https://github.com/th-ch/youtube-music/commit/fe4c89c349bb9f4f54d95c2018943095ccfdab0c)
#### [v3.5.1](https://github.com/th-ch/youtube-music/compare/v3.5.0...v3.5.1)
> 1 August 2024
- fix(deps): update dependency youtubei.js to v10.3.0 [`#2306`](https://github.com/th-ch/youtube-music/pull/2306)
- fix: Window gets stuck offscreen in some instances [`#2303`](https://github.com/th-ch/youtube-music/pull/2303)
- fix: Incorrect window size on multi-monitor scaled displays [`#2302`](https://github.com/th-ch/youtube-music/pull/2302)
- chore(deps): update dependency rollup to v4.19.2 [`#2304`](https://github.com/th-ch/youtube-music/pull/2304)
- chore(deps): update typescript-eslint monorepo to v8 (major) [`#2297`](https://github.com/th-ch/youtube-music/pull/2297)
- fix(ambient-mode): fix ambient-mode not working for videos after restart [`#2294`](https://github.com/th-ch/youtube-music/pull/2294)
- fix(deps): update dependency @xhayper/discord-rpc to v1.2.0 [`#2291`](https://github.com/th-ch/youtube-music/pull/2291)
- fix(synced-lyrics): fix lyric load [`#2295`](https://github.com/th-ch/youtube-music/issues/2295)
- fix(ambient-mode): fix ambient-mode not working for videos after restart (#2294) [`#1641`](https://github.com/th-ch/youtube-music/issues/1641)
- fix(synced-lyrics): fix i18n [`8750b54`](https://github.com/th-ch/youtube-music/commit/8750b54f766c735ff039c6be454427f17d4737e2)
- ts-fix: disambiguate ElectronStore typings [`8775735`](https://github.com/th-ch/youtube-music/commit/877573532c1b68af861a3fdc44d093f3097d36ab)
- chore(i18n): Translated using Weblate (Hungarian) [`3537dc1`](https://github.com/th-ch/youtube-music/commit/3537dc19eecce7f7deb2478942f70d3c7b72148d)
#### [v3.5.0](https://github.com/th-ch/youtube-music/compare/v3.4.1...v3.5.0)
> 31 July 2024
- plugin: Synced Lyrics [`#2207`](https://github.com/th-ch/youtube-music/pull/2207)
- chore(deps): update dependency electron to v31.3.1 [`#2290`](https://github.com/th-ch/youtube-music/pull/2290)
- chore(deps): update typescript-eslint monorepo to v7.18.0 [`#2292`](https://github.com/th-ch/youtube-music/pull/2292)

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

@ -0,0 +1,374 @@
<div align="center">
# YouTube Music
[![GitHub release](https://img.shields.io/github/release/th-ch/youtube-music.svg?style=for-the-badge&logo=youtube-music)](https://github.com/th-ch/youtube-music/releases/)
[![GitHub license](https://img.shields.io/github/license/th-ch/youtube-music.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
[![eslint code style](https://img.shields.io/badge/code_style-eslint-5ed9c7.svg?style=for-the-badge)](https://github.com/th-ch/youtube-music/blob/master/.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>
**Клиент для YouTube Music основанный на Electron с поддержкой:**
- Нативный вид приложения, нацелен на сохранение оригинального интерфейса
- Фреймворк для пользовательских плагинов: изменяйте YouTube Music под ваши нужды (внешний вид, контент, возможности), включайте/выключайте плагины в один клик
## Демо-изображение
| Экран плеера (цветовая тема альбома & режим Ambient) |
|:---------------------------------------------------------------------------------------------------------:|
|![Screenshot1](https://github.com/th-ch/youtube-music/assets/16558115/53efdf73-b8fa-4d7b-a235-b96b91ea77fc)|
## Содержание
- [Возможности](#features)
- [Доступные плагины](#available-plugins)
- [Перевод](#translation)
- [Скачать](#download)
- [Arch Linux](#arch-linux)
- [MacOS](#macos)
- [Windows](#windows)
- [Как установить без подключения к интернету? (в Windows)](#how-to-install-without-a-network-connection-in-windows)
- [Темы](#themes)
- [Для разработчиков](#dev)
- [Создайте свои собственные плагины](#build-your-own-plugins)
- [Создание плагина](#creating-a-plugin)
- [Примеры использования](#common-use-cases)
- [Сборка](#build)
- [Предварительный просмотр](#production-preview)
- [Тестирование](#tests)
- [Лицензия](#license)
- [Часто задаваемые вопросы](#faq)
## Возможности:
- **Авто-подтверждение при паузе** (Всегда включено): отключает всплывающие уведомление ["Продолжить просмотр?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png),
которое приостанавливает воспроизведение через определённое время
- И больше ...
## Доступные плагины:
- **Блокировщик рекламы**: Блокирует всю рекламу и трекеры
- **Действия с альбомом**: Добавляет кнопки "Убрать дизлайк", "Дизлайк", "Лайк", "Убрать лайк" и применяет их действия ко всем трекам в плейлисте или альбоме
- **Цветовая тема альбома**: Применяет динамическую тему и эффекты, основываясь на цветовой палитре альбома
- **Режим Ambient**: Применяет световой эффект, проецируя нежные цвета из видео на задний фон вашего экрана
- **Нормализация аудио**: Применяет нормализацию к аудио (уменьшает громкость громких частей трека и повышает громкость тихих частей трека)
- **Размытие панели навигации**: Делает панель навигации прозрачной и размытой
- **Обход возрастных ограничений**: Обходит проверку возраста YouTube
- **Выбор субтитров**: Включить субтитры
- **Компактная боковая панель**: Всегда показывать боковую панель компактно
- **Плавный переход**: Плавный переход между треками
- **Отключить автопроигрыш**: Каждый трек начинается в режиме паузы
- **[Discord](https://discord.com/) Rich Presence**: Показывает вашим друзьям, что вы слушаете с помощью [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)
- **Загрузчик**: Загрузка MP3 [напрямую из интерфейса](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
- **Расширенная громкость**: Делает слайдер громкости [расширенным](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) облегчая выбор громкости
- **Меню в приложении**: [Придаёт панели меню красивый тёмный вид](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png)
> (посмотрите [этот пост,](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) если у вас есть проблемы с доступом к меню после включения этого плагина и опции "Скрыть меню")
- **Скробблер**: Добавляет поддержку скробблинга [Last.fm](https://www.last.fm/) и [ListenBrainz](https://listenbrainz.org/)
- **Lumia Stream**: Добавляет поддержку [Lumia Stream](https://lumiastream.com/)
- **Тесты песен Genius**: Добавляет поддержку текстов для большинства песен
- **Music Together**: Делитесь плейлистом с другими. Когда ведущий воспроизводит трек, все остальные будут слушать этот же трек.
- **Навигация**: Кнопки Назад/Вперед интегрированы в интерфейс, как в вашем любимом браузере
- **Без входа в систему Google**: Убирает из интерфейса кнопки и ссылки для входа через Google
- **Уведомления**: Показывает уведомление, когда трек начинает играть ([интерактивные уведомления](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) доступны только для Windows)
- **Картинка в картинке**: Позволяет переключить приложение в режим "картинка в картинке"
- **Скорость воспроизведения**: Слушайте быстрее, слушайте медленнее! [Добавляет слайдер для контроля скорости трека](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png)
- **Точная громкость**: Точечно управляйте громкостью с помощью колеса мыши/горячих клавиш, с кастомным интерфейсом и настраиваемыми шагами громкости
- **Ярлыки (и MPRIS)**: Позволяет настроить глобальные горячие клавиши управления воспроизведением (плей/пауза/следующий/предыдущий) + отключает [отображение медиа на экране,](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png) переопределяя клавиши управления + включает Ctrl/CMD + F для поиска + включает поддержку linux mpris для клавиш управления медиа + [настраиваемые сочетания клавиш](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50) для [продвинутых пользователей](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)
- **Пропускать непонравившиеся треки**: Пропускает непонравившиеся треки
- **Пропуск тишины**: Автоматически пропускает тихие моменты в песнях
- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Автоматически пропускает немузыкальные части, такие как интро/аутро музыкальных видео, где трек не играет
- **Управление воспроизведением из панели задач**: Управляйте воспроизведением из [панели задач Windows](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
- **TouchBar**: Кастомная раскладка TouchBar для MacOS
- **Tuna OBS**: Интеграция с [OBS](https://obsproject.com/) плагином [Tuna](https://obsproject.com/forum/resources/tuna.843/)
- **Изменение качества видео**: Позволяет менять качество видео [кнопкой](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) на медиаплеере видео
- **Переключатель видео**: Добавляет
[кнопку](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) переключения режимов Трек/Видео. Также может удалять вкладку "Видео" полностью
- **Визуализатор**: Различные визуализаторы музыки
- **Synced Lyrics**:
Предоставляет синхронизированные слова для песен из таких источников, как [LRClib](https://lrclib.net).
## Перевод
Вы можете помочь с переводом на ваш язык на [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>
## Скачать
Вы можете посмотреть [latest release,](https://github.com/th-ch/youtube-music/releases/latest) чтобы быстро найти новую версию.
### Arch Linux
Установите пакет [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) из AUR. Инструкции по установке из AUR можете найти на этой [вики-странице](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
### macOS
Вы можете установить приложение с помощью Homebrew (сморите [cask definition](https://github.com/th-ch/homebrew-youtube-music)):
```bash
brew install th-ch/youtube-music/youtube-music
```
Если вы устанавливаете приложение вручную и получаете ошибку "is damaged and cant be opened.", запустите в терминале следующую команду:
```bash
xattr -cr /Applications/YouTube\ Music.app
```
### Windows
Вы можете использовать [пакетный менеджер Scoop](https://scoop.sh) для установки пакета `youtube-music` из [`extras` bucket](https://github.com/ScoopInstaller/Extras).
```bash
scoop bucket add extras
scoop install extras/youtube-music
```
Также для установки вы можете использовать [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), официальный пакетный менеджер командной строки Windows 11, для установки пакета `th-ch.YouTubeMusic`.
*К сведению: SmartScreen защитника Windows может блокировать установку, так как она от "неизвестного издателя". Это также применимо к методу ручной установки, когда вы пытаетесь запустить исполняемый файл(.exe) после загрузки здесь, на GitHub (тот же файл).*
```bash
winget install th-ch.YouTubeMusic
```
#### Установка без подключения к Интернету? (в Windows)
- Скачайте файл `*.nsis.7z` из _архетиктура вашего устройства_ на [release page](https://github.com/th-ch/youtube-music/releases/latest).
- `x64` для 64-bit Windows
- `ia32` для 32-bit Windows
- `arm64` для ARM64 Windows
- Скачайте установщик в release page. (`*-Setup.exe`)
- Поместите их в **одной директории**.
- Запустите установщик.
## Темы
Вы можете загрузить файл CSS для смены внешнего вида приложения (Настройки > Визуальные настройки > Тема).
Некоторые предустановленные темы доступны здесь: https://github.com/kerichdev/themes-for-ytmdesktop-player.
## Для разработчиков
```bash
git clone https://github.com/th-ch/youtube-music
cd youtube-music
pnpm install --frozen-lockfile
pnpm dev
```
## Создайте свои собственные плагины
Используя плагины вы можете:
- Манипулировать приложением - `BrowserWindow` из electron проброшен обработчику плагинов
- Изменять внешний вид, манипулируя HTML/CSS
### Создание плагина
Создайте директорию в `src/plugins/YOUR-PLUGIN-NAME`:
- `index.ts`: основной файл плагина
```typescript
import style from './style.css?inline'; // import style as inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic show restart dialog
config: {
enabled: false,
}, // your custom config
stylesheets: [style], // your custom style,
menu: async ({ getConfig, setConfig }) => {
// All *Config methods are wrapped Promise<T>
const config = await getConfig();
return [
{
label: 'menu',
submenu: [1, 2, 3].map((value) => ({
label: `value ${value}`,
type: 'radio',
checked: config.value === value,
click() {
setConfig({ value });
},
})),
},
];
},
backend: {
start({ window, ipc }) {
window.maximize();
// you can communicate with renderer plugin
ipc.handle('some-event', () => {
return 'hello';
});
},
// it fired when config changed
onConfigChange(newConfig) { /* ... */ },
// it fired when plugin disabled
stop(context) { /* ... */ },
},
renderer: {
async start(context) {
console.log(await context.ipc.invoke('some-event'));
},
// Only renderer available hook
onPlayerApiReady(api: YoutubePlayer, context: RendererContext) {
// set plugin config easily
context.setConfig({ myConfig: api.getVolume() });
},
onConfigChange(newConfig) { /* ... */ },
stop(_context) { /* ... */ },
},
preload: {
async start({ getConfig }) {
const config = await getConfig();
},
onConfigChange(newConfig) {},
stop(_context) {},
},
});
```
### Примеры использования
- Кастомный CSS: создайте файл `style.css` в той же директории, затем:
```typescript
// index.ts
import style from './style.css?inline'; // import style as inline
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic will show a restart dialog
config: {
enabled: false,
}, // your custom config
stylesheets: [style], // your custom style
renderer() {} // define renderer hook
});
```
- Если вы хотите изменить HTML:
```typescript
import { createPlugin } from '@/utils';
export default createPlugin({
name: 'Plugin Label',
restartNeeded: true, // if value is true, ytmusic will show the restart dialog
config: {
enabled: false,
}, // your custom config
renderer() {
// Remove the login button
document.querySelector(".sign-in-link.ytmusic-nav-bar").remove();
} // define renderer hook
});
```
- обмен между фронтом и бэком может быть выполнен с помощью модуля ipcMain из electron. Смотрите файл `index.ts` и
пример в плагине `sponsorblock`.
## Сборка
1. Склонируйте репозиторий
2. Следуйте [этой инструкции,](https://pnpm.io/installation) чтобы установить `pnpm`
3. Запустите `pnpm install --frozen-lockfile` для установки зависимостей
4. Запустите `pnpm build:OS`
- `pnpm dist:win` - Windows
- `pnpm dist:linux` - Linux (amd64)
- `pnpm dist:linux:deb-arm64` - Linux (arm64 for Debian)
- `pnpm dist:linux:rpm-arm64` - Linux (arm64 for Fedora)
- `pnpm dist:mac` - macOS (amd64)
- `pnpm dist:mac:arm64` - macOS (arm64)
Сборка приложения для macOS, Linux, и Windows,
используя [electron-builder](https://github.com/electron-userland/electron-builder).
## Предварительный просмотр
```bash
pnpm start
```
## Тестирование
```bash
pnpm test
```
Использует [Playwright](https://playwright.dev/) для тестирования приложения.
## Лицензия
MIT © [th-ch](https://github.com/th-ch/youtube-music)
## Часто задаваемые вопросы
### Почему меня приложения не отображается?
Если опция `Скрыть меню` включена - вы можете отобразить меню с помощью клавиши <kbd>alt</kbd> (или <kbd>\`</kbd> [обратный апостроф], если используете плагин "Меню в приложении")

View File

@ -1,7 +1,7 @@
{
"name": "youtube-music",
"productName": "YouTube Music",
"version": "3.5.1",
"version": "3.5.3",
"description": "YouTube Music Desktop App - including custom plugins",
"main": "./dist/main/index.js",
"license": "MIT",
@ -94,6 +94,10 @@
"rpm": {
"depends": [
"/usr/lib64/libuuid.so.1"
],
"fpm": [
"--rpm-rpmbuild-define",
"_build_id_links none"
]
},
"snap": {
@ -145,7 +149,7 @@
"xml2js": "0.6.2",
"node-fetch": "3.3.2",
"@electron/universal": "2.0.1",
"@babel/runtime": "7.25.0"
"@babel/runtime": "7.25.6"
},
"patchedDependencies": {
"vudio@2.1.1": "patches/vudio@2.1.1.patch",
@ -159,7 +163,7 @@
"@electron/remote": "2.1.2",
"@ffmpeg.wasm/core-mt": "0.12.0",
"@ffmpeg.wasm/main": "0.12.0",
"@floating-ui/dom": "1.6.8",
"@floating-ui/dom": "1.6.11",
"@foobar404/wave": "2.0.5",
"@jellybrick/electron-better-web-request": "1.0.4",
"@jellybrick/mpris-service": "2.1.4",
@ -173,18 +177,18 @@
"custom-electron-prompt": "1.5.8",
"dbus-next": "0.10.2",
"deepmerge-ts": "7.1.0",
"electron-debug": "4.0.0",
"electron-debug": "4.0.1",
"electron-is": "3.0.0",
"electron-localshortcut": "3.2.1",
"electron-store": "10.0.0",
"electron-unhandled": "4.0.1",
"electron-updater": "6.3.2",
"electron-updater": "6.3.4",
"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.12.2",
"i18next": "23.15.1",
"keyboardevent-from-electron-accelerator": "2.0.0",
"keyboardevents-areequal": "0.2.2",
"node-html-parser": "6.1.13",
@ -194,47 +198,48 @@
"serve": "14.2.3",
"simple-youtube-age-restriction-bypass": "github:organization/Simple-YouTube-Age-Restriction-Bypass#v2.5.9",
"solid-floating-ui": "0.3.1",
"solid-js": "1.8.19",
"solid-js": "1.8.22",
"solid-styled-components": "0.28.5",
"solid-transition-group": "0.2.3",
"ts-morph": "23.0.0",
"vudio": "2.1.1",
"x11": "2.3.0",
"youtubei.js": "10.3.0"
"youtubei.js": "10.4.0"
},
"devDependencies": {
"@playwright/test": "1.45.3",
"@total-typescript/ts-reset": "0.5.1",
"@playwright/test": "1.47.1",
"@total-typescript/ts-reset": "0.6.1",
"@types/color": "3.0.6",
"@types/electron-localshortcut": "3.1.3",
"@types/howler": "2.2.11",
"@types/html-to-text": "9.0.4",
"@types/semver": "7.5.8",
"@typescript-eslint/eslint-plugin": "8.0.0",
"@typescript-eslint/parser": "8.0.0",
"@types/trusted-types": "2.0.7",
"@typescript-eslint/eslint-plugin": "8.6.0",
"@typescript-eslint/parser": "8.6.0",
"bufferutil": "4.0.8",
"builtin-modules": "4.0.0",
"cross-env": "7.0.3",
"del-cli": "5.1.0",
"discord-api-types": "0.37.93",
"electron": "31.3.1",
"discord-api-types": "0.37.100",
"electron": "32.1.0",
"electron-builder": "24.13.3",
"electron-devtools-installer": "3.2.0",
"electron-vite": "2.3.0",
"esbuild": "0.23.0",
"eslint": "8.57.0",
"esbuild": "0.23.1",
"eslint": "8.57.1",
"eslint-import-resolver-exports": "1.0.0-beta.5",
"eslint-import-resolver-typescript": "3.6.1",
"eslint-plugin-import": "2.29.1",
"eslint-import-resolver-typescript": "3.6.3",
"eslint-plugin-import": "2.30.0",
"eslint-plugin-prettier": "5.2.1",
"glob": "11.0.0",
"node-gyp": "10.2.0",
"playwright": "1.45.3",
"rollup": "4.19.2",
"typescript": "5.5.4",
"playwright": "1.47.1",
"rollup": "4.21.3",
"typescript": "5.6.2",
"utf-8-validate": "6.0.4",
"vite": "5.3.5",
"vite-plugin-inspect": "0.8.5",
"vite": "5.4.6",
"vite-plugin-inspect": "0.8.7",
"vite-plugin-resolve": "2.5.2",
"vite-plugin-solid": "2.10.2",
"ws": "8.18.0"

1588
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
},
"language": {
"code": "ca",
"local-name": "català",
"local-name": "Català",
"name": "Catalan"
},
"main": {
@ -84,9 +84,9 @@
"label": "Navegació",
"submenu": {
"copy-current-url": "Copia l'URL actual",
"go-back": "Anar enrere",
"go-forward": "Anar endavant",
"quit": "Sortir",
"go-back": "Ves enrere",
"go-forward": "Ves endavant",
"quit": "Surt",
"restart": "Reinicia l'aplicació"
}
},
@ -102,11 +102,11 @@
"override-user-agent": "Sobreescriu l'agent d'usuari (User-Agent)",
"restart-on-config-changes": "Reinicia quan es canviï la configuració",
"set-proxy": {
"label": "Definir proxy",
"label": "Definir servidor intermediari (proxy)",
"prompt": {
"label": "Introduir l'adreça del proxy: (deixar en blanc per deshabilitar)",
"label": "Introduir l'adreça del servidor intermediari: (deixar en blanc per deshabilitar)",
"placeholder": "Exemple: SOCKS5://127.0.0.1:9999",
"title": "Definir proxy"
"title": "Definir servidor intermediari (proxy)"
}
},
"toggle-dev-tools": "Commuta les DevTools"
@ -144,11 +144,11 @@
"disabled": "Deshabilitat",
"enabled-and-hide-app": "Mostra la icona i amaga l'aplicació",
"enabled-and-show-app": "Mostra la icona i mostra l'aplicació",
"play-pause-on-click": "Reproduir/Pausar en clicar"
"play-pause-on-click": "Reprodueix / pausa en clicar"
}
},
"visual-tweaks": {
"label": "Configuració visual",
"label": "Opcions visuals",
"submenu": {
"like-buttons": {
"default": "Per defecte",
@ -182,9 +182,9 @@
"new": "NOU"
},
"view": {
"label": "Mostra",
"label": "Veure",
"submenu": {
"force-reload": "Força recàrrega",
"force-reload": "Força la recàrrega",
"reload": "Recarrega",
"reset-zoom": "Mida real",
"toggle-fullscreen": "Commuta la pantalla completa",
@ -220,7 +220,7 @@
},
"album-actions": {
"description": "Afegeix botons de «no m'agrada / retirar el no m'agrada» i «m'agrada / retirar el m'agrada» per aplicar-ho a totes les cançons en una llista de reproducció o àlbum",
"name": "Accions de l'àlbum"
"name": "Accions a l'àlbum"
},
"album-color-theme": {
"description": "Aplica un tema dinàmic i efectes visuals basats en la paleta de colors de l'àlbum",
@ -281,7 +281,7 @@
},
"audio-compressor": {
"description": "Aplica compressió a l'àudio (baixa el volum de les parts més sorolloses de la senyal d'àudio i puja el volum de les parts més fluixes)",
"name": "Compressor d'àudio"
"name": "Compress d'àudio"
},
"blur-nav-bar": {
"description": "Desenfoca i aplica transparència a la barra de navegació",
@ -518,7 +518,7 @@
},
"no-google-login": {
"description": "Elimina els botons d'inici de sessió de Google de la interfície",
"name": "Sense inici de sessió de Google"
"name": "Amaga l'inici de sessió de Google"
},
"notifications": {
"description": "Mostra una notificació quan una cançó es comença a reproduir (les notificacions interactives estan disponibles a Windows)",
@ -602,7 +602,7 @@
}
},
"description": "Permet canviar la qualitat del vídeo amb un botó que s'hi mostra a sobre",
"name": "Canvia la qualitat del vídeo"
"name": "Botó de qualitat del vídeo"
},
"scrobbler": {
"description": "Afegeix suport per scrobbling (Last.fm, ListenBrainz, etc.)",
@ -657,8 +657,8 @@
}
},
"skip-disliked-songs": {
"description": "Omet cançons amb «No m'agrada»",
"name": "Omet cançons amb «No m'agrad"
"description": "Salta les cançons amb «no m'agrada»",
"name": "Salta les cançons que no t'agraden"
},
"skip-silences": {
"description": "Omet automàticament les seccions amb silenci a les cançons",
@ -668,6 +668,59 @@
"description": "Omet automàticament els segments dels vídeos que no son música, com la intro o el final",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Proporciona lletres sincronitzades amb les cançons, a través de proveïdors com LRClib.",
"errors": {
"fetch": "⚠️ - Se ha produït un error en descarregar la lletra. Si us plau, intenta-ho més tard.",
"not-found": "⚠️ - No s'ha trobat la lletra per aquesta cançó."
},
"menu": {
"default-text-string": {
"label": "Caràcter per defecte entre lletres",
"tooltip": "Tria el caràcter per defecte que es mostrarà a l'espai entre les lletres"
},
"line-effect": {
"label": "Efecte de la línia",
"submenu": {
"focus": {
"label": "Focus",
"tooltip": "Mostra tan sols la línia actual en blanc"
},
"offset": {
"label": "Desplaçament",
"tooltip": "Desplaçament a la dreta de la línia actual"
},
"scale": {
"label": "Escala",
"tooltip": "Redimensiona la línia actual"
}
},
"tooltip": "Tria l'efecte a aplicar a la línia actual"
},
"precise-timing": {
"label": "Fes que les lletres es sincronitzin a la perfecció",
"tooltip": "Calcula al mil·lisegon l'aparició de la següent línia (pot tenir un petit impacte en el rendiment)"
},
"show-lyrics-even-if-inexact": {
"label": "Mostra la lletra tot i que sigui inexacta",
"tooltip": "Si no es troba la cançó, el plugin torna a intentar obtenir la lletra amb una cerca diferent.\nEl resultat d'aquesta segona cerca podria no ser exacte."
},
"show-time-codes": {
"label": "Mostra els codis de temps",
"tooltip": "Mostra els codis de temps al costat de la lletra"
}
},
"name": "Lletres sincronitzades",
"refetch-btn": {
"fetching": "Obtenint...",
"normal": "Tornar a obtenir la lletra"
},
"warnings": {
"duration-mismatch": "⚠️ - La lletra podria no estar ben sincronitzada, la durada no és coincident.",
"inexact": "⚠️ - La lletra d'aquesta cançó podria no ser exacta",
"instrumental": "⚠️ - Aquesta cançó és instrumental"
}
},
"taskbar-mediacontrol": {
"description": "Controla la reproducció des de la barra de tasques del Windows",
"name": "Control multimèdia a la barra de tasques"
@ -701,7 +754,7 @@
}
}
},
"name": "Commutador de vídeo",
"name": "Botó de vídeo",
"templates": {
"button": "Cançó"
}

View File

@ -668,6 +668,54 @@
"description": "Überspringt automatisch nicht-musikalische Teile wie Intro/Outro oder Teile von Musikvideos, in denen der Song nicht gespielt wird",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Bietet synchronisierte Liedtexte zu Songs, verwendet Anbieter wie LRClib.",
"errors": {
"fetch": "⚠️ - Beim Abrufen des Liedtexts ist ein Fehler aufgetreten. Bitte versuchen Sie es später nochmal.",
"not-found": "⚠️ - Kein Text für diesen Song gefunden."
},
"menu": {
"default-text-string": {
"label": "Standardzeichen zwischen Texten",
"tooltip": "Standardzeichen für die Lücke zwischen Songtexten auswählen"
},
"line-effect": {
"label": "Zeileneffekt",
"submenu": {
"focus": {
"label": "Fokussieren",
"tooltip": "Nur aktive Zeile weiß darstellen"
},
"offset": {
"label": "Versatz"
},
"scale": {
"label": "Skalieren",
"tooltip": "Aktuelle Zeile skalieren"
}
},
"tooltip": "Effekt für aktive Zeile auswählen"
},
"precise-timing": {
"label": "Den Songtext perfekt synchronisieren",
"tooltip": "Auf die Millisekunde genau berechnen, wann die nächste Zeile angezeigt werden soll (Kann Einfluss auf die Leistung haben)"
},
"show-time-codes": {
"label": "Zeitkodierungen anzeigen",
"tooltip": "Zeitkodierungen neben Songtext anzeigen"
}
},
"name": "Synchronisierte Texte",
"refetch-btn": {
"fetching": "Hole Songtext...",
"normal": "Songtext neu holen"
},
"warnings": {
"duration-mismatch": "⚠️ - Es kann sein, dass die Synchronization nicht stimmt, da die Songdauer nicht übereinstimmt.",
"inexact": "⚠️ - Es ist Möglich, dass der Songtext für diesen Song nicht übereinstimmt.",
"instrumental": "⚠️ - Das ist ein instrumentales Lied"
}
},
"taskbar-mediacontrol": {
"description": "Wiedergabe aus der Windows Taskleiste kontrollieren",
"name": "Mediensteuerung in der Taskleiste"

View File

@ -2,7 +2,7 @@
"common": {
"console": {
"plugins": {
"execute-failed": "Αποτυχία εκτέλεσης προσθέτου {{pluginName}}::{{contextName}}",
"execute-failed": "Απέτυχε η εκτέλεση του πρόσθετου {{pluginName}}::{{contextName}}",
"executed-at-ms": "Το πρόσθετο {{pluginName}}::{{contextName}} εκτελέστηκε σε {{ms}}ms",
"initialize-failed": "Απέτυχε η αρχικοποίηση του πρόσθετου \"{{pluginName}}\"",
"load-all": "Φόρτωση όλων των πρόσθετων",
@ -36,7 +36,7 @@
"details": "Σφάλμα ανταπόκρισης!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Εκκαθάριση της cache της εφαρμογής"
"clearing-cache-after-20s": "Εκκαθάριση μνήμης cache εφαρμογής"
},
"window": {
"tried-to-render-offscreen": "Το παράθυρο προσπάθησε να απεικονίσει εκτός οθόνης, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
@ -45,23 +45,23 @@
"dialog": {
"hide-menu-enabled": {
"detail": "Το μενού είναι κρυμμένο, χρησιμοποιήστε το 'Alt' για να το εμφανίσετε (ή το 'Escape' αν χρησιμοποιείτε το μενού εφαρμογής)",
"message": "Απόκρυψη μενού είναι ενεργοποιημένο",
"title": "Ενεργοποιήθηκε η Απόκρυψη του Μενού"
"message": "Η απόκρυψη μενού είναι ενεργοποιημένη",
"title": "Η απόκρυψη μενού ενεργοποιήθηκε"
},
"need-to-restart": {
"buttons": {
"later": "Αργότερα",
"restart-now": "Επανεκκίνηση Τώρα"
"restart-now": "Επανεκκίνηση τώρα"
},
"detail": "Το πρόσθετο \"{{pluginName}}\" απαιτεί επανεκκίνηση για να ισχύσει",
"message": "Το \"{{pluginName}}\" χρειάζεται επανεκκίνηση",
"title": "Απαιτείται Επανεκκίνηση"
"title": "Απαιτείται επανεκκίνηση"
},
"unresponsive": {
"buttons": {
"quit": "Έξοδος",
"relaunch": "Επανεκκίνηση",
"wait": "Περίμενε"
"wait": "Περιμένετε"
},
"detail": "Λυπούμαστε για την ταλαιπωρία! Παρακαλούμε επιλέξτε τι να κάνετε:",
"message": "Η εφαρμογή δεν ανταποκρίνεται",
@ -69,13 +69,13 @@
},
"update-available": {
"buttons": {
"disable": "Απενεργοποίηση Ενημερώσεων",
"disable": "Απενεργοποίηση ενημερώσεων",
"download": "Λήψη",
"ok": "Εντάξει"
"ok": "OK"
},
"detail": "Μια νέα έκδοση είναι διαθέσιμη και μπορεί να ληφθεί από τον σύνδεσμο {{downloadLink}}",
"message": "Μια νέα έκδοση είναι διαθέσιμη",
"title": "Υπάρχει Διαθέσιμη Ενημέρωση"
"title": "Υπάρχει διαθέσιμη ενημέρωση"
}
},
"menu": {
@ -87,7 +87,7 @@
"go-back": "Πήγαινε πίσω",
"go-forward": "Πήγαινε μπροστά",
"quit": "Έξοδος",
"restart": "Επανεκκίνηση Εφαρμογής"
"restart": "Επανεκκίνηση εφαρμογής"
}
},
"options": {
@ -106,7 +106,7 @@
"prompt": {
"label": "Εισαγωγή διεύθυνσης διακομιστή μεσολάβησης (proxy): (αφήστε κενό για απενεργοποίηση)",
"placeholder": "Παράδειγμα: SOCKS5://127.0.0.1:9999",
"title": "Ορισμός διακομιστή μεσολάβησης (proxy)"
"title": "Ορισμός μεσολάβησης"
}
},
"toggle-dev-tools": "Εναλλαγή DevTools"
@ -135,8 +135,8 @@
"single-instance-lock": "Κλείδωμα Μοναδικής Εκδοχής",
"start-at-login": "Έναρξη κατά την σύνδεση",
"starting-page": {
"label": "Σελίδα Έναρξης",
"unset": "Κατάργηση Ορισμού"
"label": "Σελίδα έναρξης",
"unset": "Κατάργηση ορισμού"
},
"tray": {
"label": "Δίσκος",
@ -148,13 +148,27 @@
}
},
"visual-tweaks": {
"label": "Τροποποιήσεις Εμφάνισης",
"submenu": {
"like-buttons": {
"default": "Default"
"default": "Default",
"force-show": "Αναγκαστική Εμφάνιση",
"hide": "Απόκρυψη",
"label": "Μου αρέσει"
},
"remove-upgrade-button": "Αφαίρεση κουμπιού αναβάθμισης",
"theme": {
"label": "Theme",
"dialog": {
"button": {
"cancel": "Άκυρο",
"remove": "Αφαίρεση"
},
"remove-theme": "Είστε βέβαιοι ότι θέλετε να αφαιρέσετε το προσαρμοσμένο θέμα;",
"remove-theme-message": "Αυτό θα αφαιρέσει το προσαρμοσμένο θέμα"
},
"label": "Θέμα",
"submenu": {
"import-css-file": "Εισαγωγή προσαρμοσμένου αρχείου CSS",
"no-theme": "No theme"
}
}
@ -163,29 +177,68 @@
}
},
"plugins": {
"label": "Plugins"
"enabled": "Ενεργοποιημένο",
"label": "Πρόσθετα",
"new": "ΝΕΟ"
},
"view": {
"label": "View"
"label": "Προβολή",
"submenu": {
"force-reload": "Αναγκαστική Eπαναφόρτωση",
"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": {
"ad-speedup": {
"description": "Εαν παίξει διαφήμιση κάνει σίγαση του ήχου και θέτει την ταχύτητα αναπαραγωγής στο 16x",
"name": "Γρήγορη Προώθηση Διαφημίσεων"
},
"adblocker": {
"description": "Αποκλεισμός όλων των διαφημίσεων και tracker",
"menu": {
"blocker": "Μέθοδος αποκλεισμού"
},
"name": "Adblocker"
"name": "Μπλοκάρισμα Διαφημίσεων"
},
"album-actions": {
"description": "Προσθέτει κουμπιά Like/Unlike και Dislike/Undislike που δρουν συνολικά σε όλα τα κομμάτια μιας playlist ή ενός άλμπουμ",
"name": "Ενέργειες σε Άλμπουμ"
},
"album-color-theme": {
"description": "Εφαρμόζει ένα δυναμικό θέμα και εφέ με βάση τη χρωματική παλέτα του άλμπουμ",
"menu": {
"color-mix-ratio": {
"label": "Αναλογία μίξης χρώματος",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Album Color Theme"
},
"ambient-mode": {
"description": "Εφαρμόζει ένα εφέ φωτισμού ρίχνοντας απαλά χρώματα από το βίντεο, στο φόντο της οθόνης σας.",
"menu": {
"blur-amount": {
"label": "Ένταση θαμπώματος",
"submenu": {
"pixels": "{{blurAmount}} pixels"
}
@ -197,25 +250,30 @@
}
},
"opacity": {
"label": "Ποσότητα αδιαφάνειας",
"label": "Αδιαφάνεια",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Ποιότητα",
"submenu": {
"pixels": "{{quality}} pixels"
}
},
"size": {
"label": "Μέγεθος",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"submenu": {
"during": "Σε {{interpolationTime}} δεύτερα"
"during": "Σε {{interpolationTime}} δευτερόλεπτα"
}
},
"use-fullscreen": {
"label": "Χρήση πλήρους οθόνης"
}
}
},
@ -257,11 +315,14 @@
"description": "Κάνει τα τραγούδια να είναι αυτόματα σε παύση",
"menu": {
"apply-once": "Εφαρμόζεται μόνο στο πρώτο τραγούδι"
}
},
"name": "Απενεργοποίηση αυτόματης αναπαραγωγής"
},
"discord": {
"description": "Δείξτε στους φίλους σας τι ακούτε με το Rich Presence",
"menu": {
"auto-reconnect": "Αυτόματη επανασύνδεση",
"clear-activity": "Εκκαθάριση δραστηριότητας",
"hide-duration-left": "Απόκρυψη της διάρκειας που απομένει",
"hide-github-button": "Απόκρυψη του συνδέσμου προς GitHub",
"set-inactivity-timeout": "Ορισμός χρονικού ορίου αδράνειας"
@ -280,34 +341,113 @@
"buttons": {
"ok": "OK"
},
"message": "Λήψη λίστας αναπαραγωγής {{playlistTitle}}",
"title": "Λήψη ξεκίνησε"
"detail": "{{playlistSize}} τραγούδια)",
"message": "Λήψη της λίστας αναπαραγωγής {{playlistTitle}}",
"title": "Η λήψη ξεκίνησε"
}
},
"feedback": {
"conversion-progress": "Μετατροπή: {{percent}}%",
"download-progress": "Download: {{percent}}%",
"preparing-file": "Προετοιμασία αρχείου…"
"converting": "Μετατροπή…",
"download-info": "Λήψη του {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Λήψη: {{percent}}%",
"downloading": "Λήψη…",
"downloading-counter": "Λήψη {{current}}/{{total}}…",
"downloading-playlist": "Λήψη της λίστας αναπαραγωγής \"{{playlistTitle}}\" - {{playlistSize}} τραγούδια ({{playlistId}})",
"folder-already-exists": "Ο φάκελος {{playlistFolder}} υπάρχει ήδη",
"loading": "Φόρτωση…",
"playlist-is-empty": "Η λίστα αναπραγωγής είναι άδεια",
"preparing-file": "Προετοιμασία αρχείου…",
"saving": "Αποθήκευση…",
"video-id-not-found": "Το βίντεο δεν βρέθηκε"
}
},
"menu": {
"download-finish-settings": {
"prompt": {
"last-seconds": "Τελευταία x δευτερόλεπτα"
},
"submenu": {
"percent": "Ποσοστό",
"seconds": "Δευτερόλεπτα"
}
},
"download-playlist": "Λήψη λίστας αναπαραγωγής",
"skip-existing": "Παράλειψη υπάρχοντων αρχείων"
},
"templates": {
"button": "Download"
"button": "Λήψη"
}
},
"music-together": {
"internal": {
"save": "Αποθήκευση",
"unknown-user": "Άγνωστος χρήστης"
},
"menu": {
"connected-users": "Συνδεδεμένοι χρήστες"
},
"toast": {
"add-song-failed": "Απέτυχε η προσθήκη τραγουδιού",
"remove-song-failed": "Απέτυχε η αφαίρεση τραγουδιού"
}
},
"navigation": {
"name": "Navigation"
"name": "Πλοήγηση"
},
"no-google-login": {
"name": "No Google Login"
},
"notifications": {
"name": "Notifications"
"name": "Ειδοποιήσεις"
},
"picture-in-picture": {
"menu": {
"always-on-top": "Πάντα σε πρώτο πλάνο",
"hotkey": {
"label": "Πλήκτρο πρόσβασης",
"prompt": {
"keybind-options": {
"hotkey": "Πλήκτρο πρόσβασης"
}
}
},
"save-window-position": "Αποθήκευση θέσης παραθύρου",
"save-window-size": "Αποθήκευση μεγέθους παραθύρου"
}
},
"playback-speed": {
"name": "Ταχύτητα αναπαραγωγής",
"templates": {
"button": "Ταχύτητα"
}
},
"precise-volume": {
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Μείωση έντασης",
"increase": "Αύξηση έντασης"
}
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Τρέχουσα ποιότητα: {{quality}}"
}
}
}
},
"shortcuts": {
"prompt": {
"keybind": {
"keybind-options": {
"next": "Next"
"next": "Επόμενο",
"play-pause": "Αναπαραγωγή / Παύση",
"previous": "Προηγούμενο"
}
}
}

View File

@ -668,6 +668,59 @@
"description": "Salta automáticamente las partes no musicales como la introducción/final o secciones de videos musicales donde la canción no está sonando",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Proporciona letras de canciones sincronizadas, utilizando proveedores como LRClib.",
"errors": {
"fetch": "⚠️ - Se ha producido un error al descargar la letra. Por favor, vuelve a intentarlo más tarde.",
"not-found": "⚠️ - No se ha encontrado ninguna letra para esta canción."
},
"menu": {
"default-text-string": {
"label": "Carácter predeterminado entre letras",
"tooltip": "Elige el carácter predeterminado que se utilizará para el espacio entre letras"
},
"line-effect": {
"label": "Efecto de la línea",
"submenu": {
"focus": {
"label": "Enfoque",
"tooltip": "Mostrar solo la línea actual en blanco"
},
"offset": {
"label": "Desplazamiento",
"tooltip": "Desplazamiento a la derecha de la línea actual"
},
"scale": {
"label": "Escala",
"tooltip": "Escala de la línea actual"
}
},
"tooltip": "Elige el efecto que deseas aplicar a la línea actual"
},
"precise-timing": {
"label": "Haz que la letra esté perfectamente sincronizada",
"tooltip": "Calcular al milisegundo la visualización de la línea siguiente (puede tener un pequeño impacto en el rendimiento)"
},
"show-lyrics-even-if-inexact": {
"label": "Mostrar la letra aunque sea inexacta",
"tooltip": "Si no se encuentra la canción, el complemento vuelve a intentarlo con una búsqueda diferente.\nEl resultado del segundo intento puede no ser exacto."
},
"show-time-codes": {
"label": "Visualización del código de tiempo",
"tooltip": "Mostrar los códigos de tiempo junto a la letra"
}
},
"name": "Letras sincronizadas",
"refetch-btn": {
"fetching": "Recuperando...",
"normal": "Volver a buscar letras"
},
"warnings": {
"duration-mismatch": "⚠️ - La letra puede estar desincronizada debido a un desajuste en la duración.",
"inexact": "⚠️ - La letra de esta canción puede no ser exacta",
"instrumental": "⚠️ - Se trata de una canción instrumental"
}
},
"taskbar-mediacontrol": {
"description": "Controla la reproducción desde la barra de tareas de Windows",
"name": "Control de medios de la barra de tareas"

182
src/i18n/resources/et.json Normal file
View File

@ -0,0 +1,182 @@
{
"common": {
"console": {
"plugins": {
"execute-failed": "{{pluginName}}::{{contextName}} lisamooduli käivitamine ei õnnestunud",
"executed-at-ms": "{{pluginName}}::{{contextName}} lisamoodul käivitus {{ms}} millisekundiga",
"initialize-failed": "„{{pluginName}}“ lisamooduli töö alustamine ei õnnestunud",
"load-all": "Laadime kõiki lisamooduleid",
"load-failed": "„{{pluginName}}“ lisamooduli laadimine ei õnnestunud",
"loaded": "„{{pluginName}}“ lisamoodul on laaditud",
"unload-failed": "„{{pluginName}}“ lisamooduli mälust eemaldamine ei õnnestunud",
"unloaded": "„{{pluginName}}“ lisamoodul on mälust eemaldatud"
}
}
},
"language": {
"code": "et",
"local-name": "Eesti",
"name": "Estonian"
},
"main": {
"console": {
"did-finish-load": {
"dev-tools": "Laadimine lõppes, arendaja tarvikud on avatud"
},
"i18n": {
"loaded": "i18n on laaditud"
},
"second-instance": {
"receive-command": "„{{command}}“ käsk on vastu võetud"
},
"theme": {
"css-file-not-found": "CSS faili „{{cssFile}}“ pole olemas, seega eirame eelistust"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "Menüü on peidetud ja „Alt“ klahviga saad ta nähtavaks (rakenduse-siseses menüüs „Esc“ klahviga)",
"message": "Menüü peitmine on sisselülitatud",
"title": "Menüü peitmine on sisselülitatud"
},
"need-to-restart": {
"buttons": {
"later": "Hiljem",
"restart-now": "Taaskäivita kohe"
},
"detail": "„{{pluginName}}“ lisamooduli sisselülitamine eeldab rakenduse taaskäivitamist",
"message": "„{{pluginName}}“ lisamoodul eeldab rakenduse taaskäivitamist",
"title": "Palun käivita rakendus uuesti"
},
"unresponsive": {
"buttons": {
"quit": "Välju",
"relaunch": "Käivita uuesti",
"wait": "Oota"
}
}
},
"menu": {
"navigation": {
"label": "Liikumine",
"submenu": {
"copy-current-url": "Kopeeri esitamisel oleva pala URL",
"go-back": "Mine tagasi",
"go-forward": "Mine edasi",
"quit": "Välju",
"restart": "Käivita rakendus uuesti"
}
},
"plugins": {
"label": "Lisamoodulid",
"new": "UUS"
},
"view": {
"submenu": {
"zoom-in": "Suumi sisse",
"zoom-out": "Suumi välja"
}
}
},
"tray": {
"next": "Edasi",
"play-pause": "Esita/Peata esitus",
"previous": "Eelmine",
"quit": "Välju",
"restart": "Käivita rakendus uuesti",
"show": "Näita akent",
"tooltip": {
"default": "YouTube Music",
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
}
}
},
"plugins": {
"ad-speedup": {
"description": "Reklaami esitamisel summutatakse heli ja keritakse edasi 16-kordse kiirusega",
"name": "Reklaamikiirendaja"
},
"adblocker": {
"description": "Blokeeri kõik reklaamid ja jälitajad",
"menu": {
"blocker": "Blokeerijad"
},
"name": "Reklaamiblokeerija"
},
"ambient-mode": {
"menu": {
"opacity": {
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Kvaliteet",
"submenu": {
"pixels": "{{quality}} pikslit"
}
}
}
},
"blur-nav-bar": {
"description": "Muudab navigatsiooniriba läbipaistavaks ja hägusaks",
"name": "Hägus navigatsiooniriba"
},
"lyrics-genius": {
"description": "Lisa enamustele lugudele laulusõnad",
"menu": {
"romanized-lyrics": "Latiniseeritud laulusõnad"
},
"name": "Lyrics Genius",
"renderer": {
"fetched-lyrics": "Leidsime Geeniuse jaoks ühed laulusõnad"
}
},
"navigation": {
"name": "Liikumine"
},
"scrobbler": {
"description": "Lisa kraasimise tugi (last.fm, Listenbrainz, jne)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Last.fm'i autentimine ei õnnestunud\nPeida hüpikaken järgmise taaskäivituseni.",
"title": "Autentimine ei õnnestunud"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API seadistused"
},
"listenbrainz": {
"token": "Sisesta ListenBrainz'i kasutaja tunnusluba"
},
"scrobble-other-media": "Kraasi muud meediat"
},
"name": "Kraasija",
"prompt": {
"lastfm": {
"api-key": "Last.fm API võti",
"api-secret": "Last.fm API saladus"
},
"listenbrainz": {
"token": {
"label": "Sisesta oma ListenBrainz'i tunnusluba:",
"title": "ListenBrainz'i tunnusluba"
}
}
}
},
"synced-lyrics": {
"menu": {
"show-lyrics-even-if-inexact": {
"tooltip": "Kui lugu ei leidu, siis lisamoodul üritab uut otsingut teistsuguse päringuga.\nTeise katse puhul tulemused ei pruugi olla väga täpsed."
}
}
},
"tuna-obs": {
"description": "Lõimimine OBSi Tuna lisamooduliga"
}
}
}

View File

@ -207,10 +207,12 @@
},
"plugins": {
"ad-speedup": {
"description": "Pag mag-play ng ad, I-mute ang audio at i-set ang bilis ng playback ng 16x"
"description": "Pag mag-play ng ad, I-mute ang audio at i-set ang bilis ng playback ng 16x",
"name": "Pagbilis ng Ad"
},
"adblocker": {
"description": "I-block ang lahat ng ad at tracking"
"description": "I-block ang lahat ng ad at tracking",
"name": "Pag-block ng Ad"
},
"album-actions": {
"description": "Idadagdag ang Undislike, Dislike, Like, at Unlike na button para ilapat ito sa lahat ng kanta sa isang playlist o album",
@ -392,6 +394,8 @@
"download-finish-settings": {
"label": "Kung natapos ang download",
"prompt": {
"last-percent": "Tapos ng x na porsyento",
"last-seconds": "Huling x na segundo",
"title": "I-configure kung kailan magda-download"
},
"submenu": {
@ -406,6 +410,9 @@
},
"renderer": {
"can-not-update-progress": "Hindi ma-update ang progress"
},
"templates": {
"button": "Mag download"
}
},
"exponential-volume": {
@ -475,7 +482,8 @@
"name": "Nabigasyon"
},
"no-google-login": {
"description": "Tanggalin ang mga Google login na button at mga link mula sa interface"
"description": "Tanggalin ang mga Google login na button at mga link mula sa interface",
"name": "Walang Google na Login"
},
"notifications": {
"description": "Magpakita ng notification kapag nagsimulang tumugtog ang kanta (magagamit ang mga interactive na notification sa Windows)",
@ -491,7 +499,8 @@
},
"priority": "Prioridad ng Notification",
"unpause-notification": "Ipakita ang notification sa pag-unpause"
}
},
"name": "Mga Abiso"
},
"picture-in-picture": {
"description": "Payagan ang pag-palit ng app sa picture-in-picture mode",
@ -580,6 +589,7 @@
"shortcuts": {
"description": "Nagbibigay-daan sa pagtatakda ng mga global hotkey para sa playback (play/pause/susunod/nakaraan) at pag-off ng media OSD sa pamamagitan ng pag-override sa mga media key, pag-on sa Ctrl/CMD + F para maghanap, pag-on sa suporta ng Linux MPRIS para sa mga media key, at mga custom na hotkey para sa mga advanced na user",
"menu": {
"override-media-keys": "I-override ang mga Media Key",
"set-keybinds": "I-set ang Global Song Control"
},
"name": "Mga shortcut (at MPRIS)",
@ -587,6 +597,7 @@
"keybind": {
"keybind-options": {
"next": "Susunod",
"play-pause": "Mag-play / Mag-pause",
"previous": "Nakaraan"
},
"label": "Pumili ng Global na Keybind para sa Songs Control:"
@ -594,14 +605,65 @@
}
},
"skip-disliked-songs": {
"description": "Laktawan ang na-dislike na kanta"
"description": "Laktawan ang na-dislike na kanta",
"name": "I-skip ang mga Na-dislike na Kanta"
},
"skip-silences": {
"description": "Automatikong laktawan ang mga tahimik na mga seksyon sa kanta"
"description": "Automatikong laktawan ang mga tahimik na mga seksyon sa kanta",
"name": "I-skip ang mga Katahimikan"
},
"sponsorblock": {
"description": "Automatikong Laktawan ang di part ng kanta tulad ng intro/outro o part ng mga music video na ang kanta ay di nagple-play"
},
"synced-lyrics": {
"description": "Nagbibigay ng naka-sync na lyrics sa mga kanta, gamit ang mga provider tulad ng LRClib.",
"errors": {
"fetch": "⚠️ - Nagkaroon ng error habang kinukuha ang lyrics. Subukang muli mamaya.",
"not-found": "⚠️ - Walang nakitang lyrics para sa kantang ito."
},
"menu": {
"default-text-string": {
"label": "Default na character sa pagitan ng lyrics",
"tooltip": "Pumili ng default na character na gagamitin sa pagitan ng lyrics"
},
"line-effect": {
"label": "Effect ng Linya",
"submenu": {
"focus": {
"tooltip": "Gawing puti lamang ang kasalukuyang linya"
},
"offset": {
"tooltip": "I-offset sa kanan ang kasalukuyang linya"
},
"scale": {
"tooltip": "I-scale ang kasalukuyang linya"
}
},
"tooltip": "Pumili ng effect na ilalapat sa kasalukuyang linya"
},
"precise-timing": {
"label": "Gawing perpektong naka-sync ang lyrics",
"tooltip": "Kalkulahin sa millisecond ang pagpapakita ng susunod na linya (maaaring magkaroon ng maliit na epekto sa performance)"
},
"show-lyrics-even-if-inexact": {
"label": "Ipakita ang lyrics kahit di-eksakto",
"tooltip": "Kung hindi matagpuan ang kanta, susubukan muli ng plugin gamit ang ibang query sa paghahanap.\nAng resulta mula sa pangalawang pagsubok ay maaaring hindi eksakto."
},
"show-time-codes": {
"label": "Ipakita ang mga time code",
"tooltip": "Ipakita ang mga time code kasunod sa lyrics"
}
},
"refetch-btn": {
"fetching": "Nag-fe-fetch...",
"normal": "I-fetch muli ang lyrics"
},
"warnings": {
"duration-mismatch": "⚠️ - Maaaring hindi naka-sync ang lyrics dahil sa hindi pagkakatugma ng duration.",
"inexact": "⚠️ - Maaaring hindi eksakto ang lyrics para sa kantang ito",
"instrumental": "⚠️ - Ito ay isang instrumental na kanta"
}
},
"taskbar-mediacontrol": {
"description": "Kontrolin ang pag-play mula sa iyong taskbar ng Windows"
},

View File

@ -668,6 +668,59 @@
"description": "Saute automatiquement les parties non musicales comme l'intro/outro ou les parties de clips vidéo où la chanson n'est pas lue",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Ajoute des paroles synchronisées aux chansons, grâce à LRClib par exemple.",
"errors": {
"fetch": "⚠️ - Une erreur s'est produite en allant chercher les paroles. Merci de réessayer plus tard.",
"not-found": "⚠️ - Aucune paroles trouvées pour cette musique."
},
"menu": {
"default-text-string": {
"label": "Caractère par défaut entre les paroles",
"tooltip": "Choisi le caractère par défaut à utiliser pour l'espace entre les paroles"
},
"line-effect": {
"label": "Effet de ligne",
"submenu": {
"focus": {
"label": "Focus",
"tooltip": "Rend seulement la ligne actuelle blanche"
},
"offset": {
"label": "Décalage",
"tooltip": "Décale sur la droite la ligne actuelle"
},
"scale": {
"label": "Grossissement",
"tooltip": "Agrandis la ligne actuelle"
}
},
"tooltip": "Choisi l'effet à appliquer sur la ligne actuelle"
},
"precise-timing": {
"label": "Rend les paroles parfaitement synchronisées",
"tooltip": "Calcul à la milliseconde près l'affichage de la ligne suivante (peut avoir un faible impact sur les performances)"
},
"show-lyrics-even-if-inexact": {
"label": "Afficher les paroles même si inexactes",
"tooltip": "Si la musique n'est pas trouvé, le plugin essaye à nouveau avec une différence requête.\nLe résultat du deuxième essais peut ne pas être exacte."
},
"show-time-codes": {
"label": "Afficher les timecodes",
"tooltip": "Affiche à côté de chaque paroles son timecode"
}
},
"name": "Paroles Synchronisées",
"refetch-btn": {
"fetching": "Chargement...",
"normal": "Rafraîchir les paroles"
},
"warnings": {
"duration-mismatch": "⚠️ - Les paroles peuvent ne pas être synchronisées à cause d'une différence de durée.",
"inexact": "⚠️ - Les paroles de cette chanson peuvent ne pas être exactes",
"instrumental": "⚠️ - Cette musique n'a pas de paroles"
}
},
"taskbar-mediacontrol": {
"description": "Contrôlez la lecture depuis votre barre des tâches Windows",
"name": "Contrôle multimédia de la barre des tâches"

View File

@ -2,13 +2,14 @@
"common": {
"console": {
"plugins": {
"execute-failed": "נכשל ביצוע תוסף {{pluginName}}::{{contextName}}",
"execute-failed": "שגיאה בהרצת התוסף {{pluginName}}::{{contextName}}",
"executed-at-ms": "התוסף {{pluginName}}:{{contextName}} בוצע ב {{ms}}ms",
"initialize-failed": "טעינת התוסף \"{{pluginName}}\" נכשלה",
"load-all": "טוען את כל התוספים",
"load-failed": "טעינת התוסף \"{{pluginName}}\" נכשלה",
"load-failed": "לא ניתן לטעון את התוסף {{pluginName}}",
"loaded": "התוסף \"{{pluginName}}\" נטען",
"unload-failed": "הסרת התוסף \"{{pluginName}} נכשלה"
"unload-failed": "הסרת התוסף \"{{pluginName}} נכשלה",
"unloaded": "תוסף {{pluginName}} הורד"
}
}
},
@ -25,14 +26,28 @@
"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\" על להציג אותו (או \"Esacpe\" אם משתמשים בתפריט בתוך האפליקציה)",
"message": "הסתרת התפריט מופעלת",
"title": "הסתרת התפריט הופעלה"
},
"need-to-restart": {
"buttons": {
"later": "אחר כך",

View File

@ -7,8 +7,8 @@
"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": "\"{{pluginName}}\" nevű plugin betöltve",
"unload-failed": "Nem sikerült a \"{{pluginName}}\" bővítményt letölteni",
"loaded": "\"{{pluginName}}\" plugin betöltve",
"unload-failed": "Nem sikerült a \"{{pluginName}}\" bővítményt kikapcsolni",
"unloaded": "A \"{{pluginName}}\" bővítmény kikapcsolva"
}
}
@ -372,6 +372,9 @@
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "Rendben"
},
"message": "Hoppá! Elnézést, a letöltés sikertelen volt…",
"title": "A letöltés során hiba történt!"
},
@ -412,6 +415,7 @@
"menu": {
"choose-download-folder": "Letöltési mappa kiválasztása",
"download-finish-settings": {
"label": "Letöltés befejezéskor",
"prompt": {
"last-percent": "x százalék után",
"last-seconds": "Utolsó x másodperc"
@ -425,7 +429,7 @@
}
},
"download-playlist": "Lejátszási lista letöltése",
"presets": "Előbeállítások",
"presets": "Sablonok",
"skip-existing": "Meglévő fájlok kihagyása"
},
"name": "Letöltő",
@ -567,7 +571,7 @@
"menu": {
"arrows-shortcuts": "Helyi nyíl-billentyűkkel való vezérlés",
"custom-volume-steps": "Egyedi hangerőléptetés beállítása",
"global-shortcuts": "Globális gyorsbillentyűk"
"global-shortcuts": "Globális Gyorsbillentyűk"
},
"name": "Precíz hangerő",
"prompt": {
@ -666,6 +670,18 @@
"fetch": "⚠️ - Hiba történt a dalszövegek lekérése közben. Kérlek, próbáld újra később.",
"not-found": "⚠️ - Nem található dalszöveg ehhez a zenéhez."
},
"menu": {
"line-effect": {
"submenu": {
"scale": {
"label": "Mérték"
}
}
},
"precise-timing": {
"label": "Dalszöveg tökéletes szinkronizálása"
}
},
"name": "Szinkronizált dalszövegek",
"refetch-btn": {
"fetching": "Lekérés folyamatban...",

View File

@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "Jika iklan diputar, audio akan dimatikan dan kecepatan pemutaran akan diatur ke 16x",
"name": "Percepatan Iklan"
},
"adblocker": {
"description": "Blokir semua iklan dan pelacakan di luar kotak",
"menu": {
@ -410,6 +414,21 @@
"description": "Unduh MP3 / sumber suara secara langsung via antarmuka",
"menu": {
"choose-download-folder": "Pilih folder unduhan",
"download-finish-settings": {
"label": "Unduh setelah selesai",
"prompt": {
"last-percent": "x persen terakhir",
"last-seconds": "x detik terakhir",
"title": "Konfigurasikan kapan akan mengunduh"
},
"submenu": {
"advanced": "Lanjutan",
"enabled": "Diaktifkan",
"mode": "Mode waktu",
"percent": "Persen",
"seconds": "Detik"
}
},
"download-playlist": "Unduh daftar putar",
"presets": "Prasetel",
"skip-existing": "Lewati berkas yang sudah ada"
@ -649,6 +668,59 @@
"description": "Otomatis Melewati bagian yang bukan musik seperti intro/outro atau bagian dari video musik di mana lagu tidak dimainkan",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Menyediakan lirik lagu yang disinkronkan, menggunakan penyedia seperti LRClib.",
"errors": {
"fetch": "⚠️ - Terjadi kesalahan saat mengambil lirik. Coba lagi nanti.",
"not-found": "⚠️ - Tidak ada lirik yang ditemukan untuk lagu ini."
},
"menu": {
"default-text-string": {
"label": "Karakter default antara lirik",
"tooltip": "Pilih karakter default yang akan digunakan untuk celah antar lirik"
},
"line-effect": {
"label": "Efek garis",
"submenu": {
"focus": {
"label": "Fokus",
"tooltip": "Jadikan hanya baris saat ini berwarna putih"
},
"offset": {
"label": "Offset",
"tooltip": "Mengimbangi garis saat ini di sebelah kanan"
},
"scale": {
"label": "Skala",
"tooltip": "Skala garis saat ini"
}
},
"tooltip": "Pilih efek yang akan diterapkan ke baris saat ini"
},
"precise-timing": {
"label": "Buat liriknya tersinkronisasi dengan sempurna",
"tooltip": "Hitung hingga milidetik tampilan baris berikutnya (dapat berdampak kecil pada kinerja)"
},
"show-lyrics-even-if-inexact": {
"label": "Tampilkan lirik meskipun tidak tepat",
"tooltip": "Jika lagu tidak ditemukan, plugin akan mencoba lagi dengan kueri pencarian yang berbeda.\nHasil dari percobaan kedua mungkin tidak tepat."
},
"show-time-codes": {
"label": "Tampilkan kode waktu",
"tooltip": "Tampilkan kode waktu di samping lirik"
}
},
"name": "Lirik yang Disinkronkan",
"refetch-btn": {
"fetching": "Mengambil...",
"normal": "Ambil ulang lirik"
},
"warnings": {
"duration-mismatch": "⚠️ - Liriknya mungkin tidak sinkron karena ketidakcocokan durasi.",
"inexact": "⚠️ - Lirik lagu ini mungkin tidak tepat",
"instrumental": "⚠️ - Ini adalah lagu instrumental"
}
},
"taskbar-mediacontrol": {
"description": "Kendalikan pemutaran dari bilah alat Windows",
"name": "Pengendali Media di Bilah Alat"

View File

@ -158,6 +158,14 @@
},
"remove-upgrade-button": "Fjarlægja uppgræðartakkan",
"theme": {
"dialog": {
"button": {
"cancel": "Hætta við",
"remove": "Fjarlægja"
},
"remove-theme": "Ertu viss um að þú viljir fjarlægja þetta sérsniðna þema?",
"remove-theme-message": "Þetta mun fjarlægja sérsniðna þema"
},
"label": "Þema",
"submenu": {
"import-css-file": "Flytja inn sérsniðna CSS skrá",
@ -199,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "Ef auglýsing spilar slökknar hún á hljóðinu og stillir spilunarhraðann á 16x",
"name": "Auglýsingahraða"
},
"adblocker": {
"description": "Lokaðu fyrir allar auglýsingar og rakningar úr kassanum",
"menu": {
@ -402,6 +414,21 @@
"description": "Niðurhalar MP3 / upprunahljóði beint úr viðmótinu",
"menu": {
"choose-download-folder": "Veldu niðurhalsmöppu",
"download-finish-settings": {
"label": "Sækja þegar lokið",
"prompt": {
"last-percent": "Eftir x sekúndur",
"last-seconds": "Síðustu x sekúndur",
"title": "Stilla hvenær á að hlaða niður"
},
"submenu": {
"advanced": "Ítarlegri",
"enabled": "Virkt",
"mode": "Tímastilling",
"percent": "Hlutfall",
"seconds": "Sekúndur"
}
},
"download-playlist": "Sækja spilunarlista",
"presets": "Forstillingar",
"skip-existing": "Slepptu núverandi skrám"
@ -641,6 +668,10 @@
"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"
},
"synced-lyrics": {
"description": "Veitir samstillta texta við lög, með því að nota veitur eins og LRClib.",
"name": "Samstilltur texti"
},
"taskbar-mediacontrol": {
"description": "Stjórnaðu spilun frá Windows verkefnastikunni þinni",
"name": "Miðlunarstýringarverkefnastikunnar"

View File

@ -65,7 +65,7 @@
},
"detail": "ご不便をおかけして申し訳ございません! 何をするか選んでください:",
"message": "アプリケーションは応答していません",
"title": "ウィンドウが応答しません"
"title": "ウィンドウが応答していません"
},
"update-available": {
"buttons": {
@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "広告が再生されると、自動的にミュートされ、再生速度が16倍に設定されます",
"name": "広告のスピードを上げる"
},
"adblocker": {
"description": "すべての広告とトラッカーをブロックj",
"menu": {
@ -410,6 +414,21 @@
"description": "UIから直にMP3・ソースオーディオをダウンロードします",
"menu": {
"choose-download-folder": "ダウンロードフォルダ",
"download-finish-settings": {
"label": "完了時にダウンロード",
"prompt": {
"last-percent": "x パーセント後",
"last-seconds": "最後の x 秒",
"title": "保存するタイミング"
},
"submenu": {
"advanced": "高度な設定",
"enabled": "有効",
"mode": "時間モード",
"percent": "パーセント",
"seconds": "秒"
}
},
"download-playlist": "プレイリストをダウンロード",
"presets": "プリセット",
"skip-existing": "存在するファイルをスキップ"
@ -649,6 +668,59 @@
"description": "イントロ/アウトロなどの音楽以外の部分や、曲が再生されていないミュージック ビデオの部分を自動的にスキップします",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "LRClibのようなプロバイダを使って、楽曲に同期した歌詞を使用する。",
"errors": {
"fetch": "⚠️ - 歌詞の取得中にエラーが発生しました。 後でもう一度お試しください。",
"not-found": "⚠️ - この曲の歌詞は見つかりませんでした。"
},
"menu": {
"default-text-string": {
"label": "デフォルトの歌詞間の文字",
"tooltip": "歌詞と歌詞の間に使用するデフォルトの文字を選択してください"
},
"line-effect": {
"label": "歌詞表示のエフェクト",
"submenu": {
"focus": {
"label": "フォーカス",
"tooltip": "現在の行だけを白くする"
},
"offset": {
"label": "オフセット",
"tooltip": "オフセットを現在の行の右側にする"
},
"scale": {
"label": "サイズ",
"tooltip": "現在の行のサイズ変更をする"
}
},
"tooltip": "現在の行に適用するエフェクトを選択"
},
"precise-timing": {
"label": "歌詞を完璧に同期させる",
"tooltip": "次の行の表示をミリ秒単位で計算する(パフォーマンスに若干の影響を与える可能性があります)"
},
"show-lyrics-even-if-inexact": {
"label": "歌詞が不正確でも表示する",
"tooltip": "曲が見つからなかった場合、プラグインは別の検索クエリで再試行します。\nただし、再試行の結果は正確でない可能性があります。"
},
"show-time-codes": {
"label": "タイムコードを表示",
"tooltip": "歌詞の横にタイムコードを表示"
}
},
"name": "歌詞を同期",
"refetch-btn": {
"fetching": "取得中...",
"normal": "歌詞を再取得"
},
"warnings": {
"duration-mismatch": "⚠️ - タイミングが合わないため、歌詞が同期されていない可能性があります。",
"inexact": "⚠️ - この曲の歌詞は正確ではないかもしれません",
"instrumental": "⚠️ - これは演奏のみの曲です"
}
},
"taskbar-mediacontrol": {
"description": "Windowsタスクバーから再生をコントロール",
"name": "タスクバーメディアコントロール"

View File

@ -5,6 +5,7 @@
"execute-failed": "Pelaksaan plugin gagal {{pluginName}}::{{contextName}}",
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} dilaksanakan pada {{ms}}ms",
"initialize-failed": "Gagal untuk memulakan plugin \"{{pluginName}}\"",
"load-all": "Memuatkan semua plugin",
"loaded": "Plugin \"{{pluginName}}\" dimuatkan",
"unload-failed": "Gagal untuk memunggah plugin \"{{pluginName}}\"",
"unloaded": "Plugin \"{{pluginName}}\" dipunggahkan"
@ -39,15 +40,22 @@
"detail": "Menu telah disembunyikan, guna 'Alt' untuk menunjukkannya (atau 'Escape' jika menggunakan In-App Menu)"
},
"need-to-restart": {
"buttons": {
"later": "Nanti",
"restart-now": "Restart Sekarang"
},
"message": "\"{{pluginName}}\" perlu dimulakan semula",
"title": "Mulakan Semula Diperlukan"
},
"unresponsive": {
"buttons": {
"quit": "Berhenti",
"relaunch": "Lancar Semula",
"wait": "Tunggu"
},
"detail": "Kami memohon maaf atas kesulitan! sila pilih apa yang perlu dilakukan:"
"detail": "Kami memohon maaf atas kesulitan! sila pilih apa yang perlu dilakukan:",
"message": "Aplikasi Tidak Responsif",
"title": "Window Tidak Responsif"
},
"update-available": {
"buttons": {
@ -58,16 +66,137 @@
}
},
"menu": {
"about": "Mengenai",
"navigation": {
"label": "Navigasi",
"submenu": {
"copy-current-url": "Salin URL semasa",
"go-back": "Pulang",
"go-back": "Belakang",
"go-forward": "Depan",
"quit": "Keluar"
}
},
"options": {
"label": "Pilihan"
"label": "Tetapan",
"submenu": {
"advanced-options": {
"label": "Tetapan Lanjutan",
"submenu": {
"set-proxy": {
"prompt": {
"placeholder": "Contoh: SOCKS5://127.0.0.1:9999",
"title": "Set proksi"
}
}
}
},
"always-on-top": "Sentiasa di atas",
"auto-update": "Kemas Kini Automatik",
"hide-menu": {
"dialog": {
"message": "Menu akan disembunyikan pada pelancaran seterusnya, gunakan [Alt] untuk menunjukkannya (atau backtick [`] jika menggunakan dalam aplikasi-menu)"
}
},
"language": {
"dialog": {
"message": "Bahasa akan ditukar selepas dimulakan semula",
"title": "Bahasa Berubah"
},
"label": "Bahasa",
"submenu": {
"to-help-translate": "Ingin membantu menterjemah? Klik di sini"
}
},
"resume-on-start": "Mulakan semula lagu terakhir apabila aplikasi dimulakan",
"start-at-login": "Mulakan semasa log masuk",
"starting-page": {
"label": "Halaman Permulaan"
},
"tray": {
"submenu": {
"play-pause-on-click": "Main / Hentikan pada klik"
}
},
"visual-tweaks": {
"label": "Pembaikan Visual",
"submenu": {
"like-buttons": {
"default": "Lalai",
"hide": "Sembunyi"
},
"theme": {
"dialog": {
"button": {
"cancel": "Batalkan",
"remove": "Padam"
}
},
"label": "Tema"
}
}
}
}
}
},
"tray": {
"next": "Seterusnya",
"play-pause": "Main / Jeda",
"previous": "Sebelumnya",
"quit": "Keluar",
"restart": "Mulakan Semula Aplikasi"
}
},
"plugins": {
"ambient-mode": {
"menu": {
"quality": {
"label": "Kualiti"
},
"size": {
"label": "Saiz"
}
}
},
"captions-selector": {
"prompt": {
"selector": {
"title": "Pilih bahasa kapsyen"
}
}
},
"synced-lyrics": {
"menu": {
"show-lyrics-even-if-inexact": {
"label": "Tunjukkan lirik walaupun tidak tepat",
"tooltip": "Jika lagu tidak ditemui, plugin cuba lagi dengan pertanyaan carian yang berbeza. \nHasil dari percubaan kedua mungkin tidak tepat."
},
"show-time-codes": {
"tooltip": "Tunjukkan kod masa di sebelah lirik"
}
}
},
"taskbar-mediacontrol": {
"description": "Kawalan main balik dari bar tugas Windows anda",
"name": "Kawalan Media Bar Tugas"
},
"video-toggle": {
"menu": {
"align": {
"submenu": {
"left": "Kiri",
"middle": "Tengah",
"right": "Kanan"
}
},
"force-hide": "Alih Keluar Tab Video",
"mode": {
"submenu": {
"disabled": "Tidak Aktif"
}
}
},
"templates": {
"button": "Lagu"
}
}
}

View File

@ -158,6 +158,14 @@
},
"remove-upgrade-button": "Upgrade-knop verwijderen",
"theme": {
"dialog": {
"button": {
"cancel": "Annuleren",
"remove": "Verwijderen"
},
"remove-theme": "Weet je zeker dat je het aangepaste thema wilt verwijderen?",
"remove-theme-message": "Dit verwijderd het aangepaste thema"
},
"label": "Thema",
"submenu": {
"import-css-file": "Aangepast CSS-bestand importeren",
@ -199,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "Wanneer een advertentie afspeelt, dempt het geluid en versnelt de playback naar 16x",
"name": "Snellere advertenties"
},
"adblocker": {
"description": "Blokkeer alle advertenties en tracking vanuit de doos",
"menu": {
@ -402,6 +414,21 @@
"description": "Download MP3 / bron-audio rechtstreeks vanuit de interface",
"menu": {
"choose-download-folder": "Kies de downloadmap",
"download-finish-settings": {
"label": "Downloaden bij voltooiing",
"prompt": {
"last-percent": "Na x procent",
"last-seconds": "Laatste x seconden",
"title": "Configureren wanneer te downloaden"
},
"submenu": {
"advanced": "Geavanceerd",
"enabled": "Ingeschakeld",
"mode": "Tijd-modus",
"percent": "Procent",
"seconds": "Seconden"
}
},
"download-playlist": "Afspeellijst downloaden",
"presets": "Voorinstellingen",
"skip-existing": "Bestaande bestanden overslaan"
@ -523,8 +550,20 @@
"save-window-size": "Sla schermgrootte op"
}
},
"video-toggle": {
"menu": {
"mode": {
"submenu": {
"disabled": "Uitgeschakeld"
}
}
}
},
"visualizer": {
"description": "Voeg een visuele equalizer toe",
"menu": {
"visualizer-type": "Type visualisator"
},
"name": "Visualisator"
}
}

View File

@ -668,6 +668,22 @@
"description": "Automatycznie pomija fragmenty niebędące muzyką, takie jak wstęp/zakończenie lub fragmenty teledysków, w których utwór nie jest odtwarzany",
"name": "Pomiń nieistotne fragmenty"
},
"synced-lyrics": {
"description": "Dodaje zsynchronizowane napisy do utworów używając między innymi LRClib.",
"errors": {
"fetch": "⚠️ - Wystąpił błąd podczas pobierania tekstu utworu. Spróbuj ponownie później.",
"not-found": "⚠️ - Nie znaleziono napisów dla tego utworu."
},
"name": "Napisy zsynchronizowane",
"refetch-btn": {
"fetching": "Pobieranie napisów...",
"normal": "Odśwież napisy"
},
"warnings": {
"duration-mismatch": "⚠️ - Napisy mogą nie być zsynchronizowane z powodu różnicy w czasie trwania.",
"instrumental": "⚠️ - To jest utwór instrumentalny"
}
},
"taskbar-mediacontrol": {
"description": "Steruj odtwarzaniem z paska zadań systemu Windows",
"name": "Kontroler odtwarzania z paska zadań"

View File

@ -668,6 +668,59 @@
"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)"
},
"synced-lyrics": {
"description": "Fornece letras sincronizadas de músicas, utilizando fornecedores como o LRClib.",
"errors": {
"fetch": "⚠️ - Ocorreu um erro ao obter as letras da música. Por favor, tenta novamente mais tarde.",
"not-found": "⚠️ - Não foram encontradas letras para esta música."
},
"menu": {
"default-text-string": {
"label": "Caractere padrão entre as letras",
"tooltip": "Escolha o caractere padrão para usar no espaço entre as letras"
},
"line-effect": {
"label": "Efeito de linha",
"submenu": {
"focus": {
"label": "Foco",
"tooltip": "Deixe apenas a linha atual branca"
},
"offset": {
"label": "Deslocamento",
"tooltip": "Desloque a linha atual para a direita"
},
"scale": {
"label": "Escala",
"tooltip": "Escalar a linha atual"
}
},
"tooltip": "Escolha o efeito a ser aplicado à linha atual"
},
"precise-timing": {
"label": "Sincronize perfeitamente as letras",
"tooltip": "Calcule até o milissegundo a exibição da próxima linha (pode ter um pequeno impacto no desempenho)"
},
"show-lyrics-even-if-inexact": {
"label": "Mostrar letras mesmo que imprecisas",
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
},
"show-time-codes": {
"label": "Mostrar códigos de tempo",
"tooltip": "Mostrar os códigos de tempo ao lado das letras"
}
},
"name": "Letras Sincronizadas",
"refetch-btn": {
"fetching": "Buscando...",
"normal": "Buscar as letras novamente"
},
"warnings": {
"duration-mismatch": "⚠️ - As letras da música pode estar dessincronizada devido a um erro de duração.",
"inexact": "⚠️ - As letras desta música podem não ser exactas.",
"instrumental": "⚠️ - Esta é uma música instrumental."
}
},
"taskbar-mediacontrol": {
"description": "Controle a reprodução na barra de tarefas do Windows",
"name": "Controle de mídia da barra de tarefas"

View File

@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "Если воспроизводится реклама, аудио заглушается и скорость воспроизведения устанавливается на 16х",
"name": "Ускоренная перемотка"
},
"adblocker": {
"description": "Блокируйте всю рекламу и трекинг сразу после установки",
"menu": {
@ -277,7 +281,7 @@
},
"audio-compressor": {
"description": "Применяет компрессию к аудио (уменьшает громкость самых громких частей сигнала и повышает громкость самых тихих частей)",
"name": "Аудио компрессор"
"name": "Нормализация аудио"
},
"blur-nav-bar": {
"description": "Делает панель навигации прозрачной и размытой",
@ -649,6 +653,58 @@
"description": "Автоматически пропускает не музыкальные фрагменты, например интро/аутро или фрагменты музыкальных клипов, в которых песня не звучит (тишина)",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "Предоставляет синхронизированные слова для песен из таких источников, как LRClib.",
"errors": {
"fetch": "⚠️ - Возникла ошибка во время получения слов. Повторите попытку позже.",
"not-found": "⚠️ - Для этой песни не найдено слов."
},
"menu": {
"default-text-string": {
"label": "Стандартный символ между словами",
"tooltip": "Выберите стандартный символ для заполнения пространства между словами"
},
"line-effect": {
"label": "Эффект строки",
"submenu": {
"focus": {
"label": "Фокусировка",
"tooltip": "Делает только текущую строку белой"
},
"offset": {
"label": "Сдвиг",
"tooltip": "Сдвигает текущую строку вправо"
},
"scale": {
"label": "Увеличение",
"tooltip": "Увеличивает текущую строку"
}
},
"tooltip": "Выберите эффект применяемый к текущей строке"
},
"precise-timing": {
"label": "Идеально синхронизировать слова",
"tooltip": "До миллисекунды рассчитывает отображение следующей строки(может оказать небольшое влияние на производительность)"
},
"show-lyrics-even-if-inexact": {
"label": "Показывать слова, даже если неточные",
"tooltip": "Если песня не найдена, плагин попытается снова с другим поисковым запросом.\nСо второй попытки результат может быть неточным."
},
"show-time-codes": {
"label": "Показывать временные метки",
"tooltip": "Показывает временные метки рядом со словами"
}
},
"refetch-btn": {
"fetching": "Сбор данных...",
"normal": "Обновить слова"
},
"warnings": {
"duration-mismatch": "⚠️ - Слова могут быть неточно синхронизированы из-за несовпадения длины трека.",
"inexact": "⚠️ - Слова для этой песни могут быть неточными",
"instrumental": "⚠️ - Это инструментальная музыка"
}
},
"taskbar-mediacontrol": {
"description": "Управляйте воспроизведением с панели задач Windows",
"name": "Управление мультимедиа на панели задач"
@ -692,7 +748,7 @@
"menu": {
"visualizer-type": "Вид визуализации"
},
"name": "Визуалайзер"
"name": "Визуализатор"
}
}
}

View File

@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "Bir reklam oynatılırsa sesi kapatır ve oynatma hızını 16x olarak ayarlar",
"name": "Hızlandırma"
},
"adblocker": {
"description": "Tüm reklamları ve izleyicileri engelle",
"menu": {
@ -664,6 +668,59 @@
"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"
},
"synced-lyrics": {
"description": "LRClib gibi sağlayıcıları kullanarak şarkılara senkronize şarkı sözleri sağlar.",
"errors": {
"fetch": "⚠️ - Şarkı sözleri getirilirken bir hata oluştu. Lütfen daha sonra tekrar deneyin.",
"not-found": "⚠️ - Bu şarkı için şarkı sözü bulunamadı."
},
"menu": {
"default-text-string": {
"label": "Şarkı sözleri arasında varsayılan karakter",
"tooltip": "Şarkı sözleri arasındaki boşluk için kullanılacak varsayılan karakteri seçin"
},
"line-effect": {
"label": "Çizgi etkisi",
"submenu": {
"focus": {
"label": "odak",
"tooltip": "Yalnızca geçerli satırı beyaz yapın"
},
"offset": {
"label": "telafi etmek,ofset",
"tooltip": "Geçerli satırın sağındaki ofset"
},
"scale": {
"label": "ölçek",
"tooltip": "Geçerli satırı ölçeklendirir"
}
},
"tooltip": "Geçerli satıra uygulanacak efekti seçin"
},
"precise-timing": {
"label": "Şarkı sözlerini mükemmel şekilde senkronize edin",
"tooltip": "Bir sonraki satırın görüntülenmesini milisaniyesine kadar hesaplayın (performans üzerinde küçük bir etkisi olabilir)"
},
"show-lyrics-even-if-inexact": {
"label": "Kesin olmasa bile şarkı sözlerini gösterin",
"tooltip": "Şarkı bulunamazsa, eklenti farklı bir arama sorgusuyla tekrar dener. \nİkinci denemenin sonucu tam olmayabilir."
},
"show-time-codes": {
"label": "Zaman kodlarını göster",
"tooltip": "Şarkı sözlerinin yanında zaman kodlarını gösterin"
}
},
"name": "Senkronize Şarkı Sözleri",
"refetch-btn": {
"fetching": "Getiriliyor...",
"normal": "Refetch şarkı sözleri"
},
"warnings": {
"duration-mismatch": "⚠️ - Süre uyuşmazlığı nedeniyle şarkı sözleri senkronize olmayabilir.",
"inexact": "⚠️ - Bu şarkının sözleri tam olmayabilir",
"instrumental": "⚠️ - Bu enstrümantal bir şarkıdır"
}
},
"taskbar-mediacontrol": {
"description": "Windows görev çubuğu üzerinden oynatmayı kontrol edebilmenize olanak sağlar",
"name": "Görev Çubuğu Medya Kontrolü"

View File

@ -674,6 +674,38 @@
"fetch": "⚠️ - Đã xảy ra lỗi khi tìm nạp lời bài hát, Vui lòng thử lại sau.",
"not-found": "⚠️ - Không tìm thấy lời cho bài hát này."
},
"menu": {
"default-text-string": {
"label": "Kí tự mặc định giữa các lời bài hát",
"tooltip": "Chọn kí tự mặc định cho khoảng trống giữa các lời bài hát"
},
"line-effect": {
"label": "Kiểu đường thẳng",
"submenu": {
"focus": {
"label": "Tập trung",
"tooltip": "Chỉ làm cho dòng hiện tại có màu trắng"
},
"scale": {
"label": "Tỉ lệ",
"tooltip": "Áp dụng tỉ lệ cho dòng hiện tại"
}
},
"tooltip": "Chọn kiểu để áp dụng cho dòng hiện tại"
},
"precise-timing": {
"label": "Làm cho lời bài hát được đồng bộ hoàn hảo",
"tooltip": "Tính toán chính xác đến mili giây thời gian hiển thị dòng tiếp theo (có thể có tác động nhỏ đến hiệu suất)"
},
"show-lyrics-even-if-inexact": {
"label": "Hiển thị lời bài hát ngay cả khi không chính xác",
"tooltip": "Nếu không tìm thấy bài hát, plugin sẽ thử lại bằng truy vấn tìm kiếm khác.\nKết quả từ lần thử thứ hai có thể không chính xác."
},
"show-time-codes": {
"label": "Hiện mốc thời gian",
"tooltip": "Hiện mốc thời gian bên cạnh lời bài hát"
}
},
"name": "Lời bài hát được đồng bộ hoá",
"refetch-btn": {
"fetching": "Đang tìm nạp...",

View File

@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "使用静音以及 16 倍速播放跳过广告片段",
"name": "广告加速跳过"
},
"adblocker": {
"description": "屏蔽所有广告与跟踪器",
"menu": {
@ -664,6 +668,59 @@
"description": "自动跳过非音乐部分,如 MV 的介绍/结语以及歌曲未开始的部分",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "透过 LRClib 等服务提供滚动歌词显示。",
"errors": {
"fetch": "⚠️ - 获取歌词时发生错误。请稍后再试。",
"not-found": "⚠️ - 未找到此歌曲的歌词。"
},
"menu": {
"default-text-string": {
"label": "默认的歌词行间字符",
"tooltip": "选择在歌词间隙期间默认显示的字符"
},
"line-effect": {
"label": "歌词行特效",
"submenu": {
"focus": {
"label": "高亮",
"tooltip": "仅将当前歌词行显示为白色"
},
"offset": {
"label": "偏移",
"tooltip": "将当前歌词行向右偏移"
},
"scale": {
"label": "放大",
"tooltip": "放大当前歌词行"
}
},
"tooltip": "选择当前歌词行应用的特效"
},
"precise-timing": {
"label": "让滚动歌词完全同步",
"tooltip": "以毫秒精度估算下句歌词的显示时间(可能对性能有小幅影响)"
},
"show-lyrics-even-if-inexact": {
"label": "即使时值不精确依然显示歌词",
"tooltip": "若首次搜索未找到该歌曲的歌词,插件将尝试用不同的查询方式重新获取。\n重试查询的结果可能不精确。"
},
"show-time-codes": {
"label": "显示时值",
"tooltip": "在歌词旁显示时值"
}
},
"name": "滚动歌词",
"refetch-btn": {
"fetching": "正在获取…",
"normal": "重新获取歌词"
},
"warnings": {
"duration-mismatch": "⚠️ - 由于持续时间不对应,滚动歌词可能不同步。",
"inexact": "⚠️ - 此曲目的歌词可能不准确",
"instrumental": "⚠️ - 此曲目为纯音乐"
}
},
"taskbar-mediacontrol": {
"description": "从 Windows 任务栏控制音乐回放",
"name": "任务栏媒体控件"

View File

@ -207,6 +207,10 @@
}
},
"plugins": {
"ad-speedup": {
"description": "使用 16 倍速播放及靜音來跳過廣告片段",
"name": "加速略過"
},
"adblocker": {
"description": "阻擋所有廣告",
"menu": {
@ -664,6 +668,59 @@
"description": "自動跳過贊助片段",
"name": "贊助阻擋"
},
"synced-lyrics": {
"description": "使用 LRClib 等管道提供歌詞同步顯示。",
"errors": {
"fetch": "⚠️擷取歌詞時發生錯誤。請稍後再試。",
"not-found": "⚠️未找到該首歌曲的歌詞。"
},
"menu": {
"default-text-string": {
"label": "預設歌詞中間隔的符號",
"tooltip": "選擇歌詞中間隔要使用的符號"
},
"line-effect": {
"label": "歌詞顯示效果",
"submenu": {
"focus": {
"label": "高亮",
"tooltip": "高亮當前的歌詞"
},
"offset": {
"label": "凸行",
"tooltip": "凸行當前的歌詞"
},
"scale": {
"label": "放大",
"tooltip": "放大當前的歌詞"
}
},
"tooltip": "選擇要使用的歌詞顯示效果"
},
"precise-timing": {
"label": "使歌詞完美同步",
"tooltip": "更精確的計算下一行歌詞的顯示(將會降低些許效能)"
},
"show-lyrics-even-if-inexact": {
"label": "即使不精確依然強制顯示歌詞",
"tooltip": "當找不到符合該歌曲的歌詞時,該功能會嘗試不同的搜尋方式\n使用不同的搜尋方式會導致不精確的結果。"
},
"show-time-codes": {
"label": "顯示時間線",
"tooltip": "在歌詞旁顯示時間線"
}
},
"name": "歌詞同步",
"refetch-btn": {
"fetching": "擷取中...",
"normal": "重新擷取歌詞"
},
"warnings": {
"duration-mismatch": "⚠️歌詞可能會出現不同步的情況。",
"inexact": "⚠️該歌曲的歌詞可能並不精確",
"instrumental": "⚠️該首歌曲並無人聲"
}
},
"taskbar-mediacontrol": {
"description": "允許工作列應用程式預覽介面顯示媒體控制相關按鈕",
"name": "工作列媒體控制"

View File

@ -11,6 +11,7 @@ import {
shell,
dialog,
ipcMain,
type BrowserWindowConstructorOptions,
} from 'electron';
import enhanceWebRequest, {
BetterSession,
@ -286,6 +287,23 @@ async function createMainWindow() {
height: 32,
};
const decorations: Partial<BrowserWindowConstructorOptions> = {
frame: !is.macOS() && !useInlineMenu,
titleBarOverlay: defaultTitleBarOverlayOptions,
titleBarStyle: useInlineMenu
? 'hidden'
: is.macOS()
? 'hiddenInset'
: 'default',
autoHideMenuBar: config.get('options.hideMenu'),
};
// Note: on linux, for some weird reason, having these extra properties with 'frame: false' does not work
if (is.linux() && useInlineMenu) {
delete decorations.titleBarOverlay;
delete decorations.titleBarStyle;
}
const win = new BrowserWindow({
icon,
width: windowSize.width,
@ -303,14 +321,7 @@ async function createMainWindow() {
sandbox: false,
}),
},
frame: !is.macOS() && !useInlineMenu,
titleBarOverlay: defaultTitleBarOverlayOptions,
titleBarStyle: useInlineMenu
? 'hidden'
: is.macOS()
? 'hiddenInset'
: 'default',
autoHideMenuBar: config.get('options.hideMenu'),
...decorations,
});
initHook(win);
initTheme(win);
@ -607,6 +618,7 @@ app.whenReady().then(async () => {
shortcutDetails.target !== appLocation ||
shortcutDetails.appUserModelId !== appID
) {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw 'needUpdate';
}
} catch (error) {

View File

@ -10,11 +10,11 @@ import {
import injectCliqzPreload from './injectors/inject-cliqz-preload';
import { inject, isInjected } from './injectors/inject';
import { loadAdSpeedup } from './adSpeedup';
import { t } from '@/i18n';
import type { BrowserWindow } from 'electron';
import { loadAdSpeedup } from './adSpeedup';
interface AdblockerConfig {
/**
@ -118,7 +118,19 @@ export default createPlugin({
},
},
preload: {
script: 'window.JSON.parse = window._proxyJsonParse; window._proxyJsonParse = undefined; window.Response.prototype.json = window._proxyResponseJson; window._proxyResponseJson = undefined; 0',
// see #1478
script: `const _prunerFn = window._pruner;
window._pruner = undefined;
JSON.parse = new Proxy(JSON.parse, {
apply() {
return _prunerFn(Reflect.apply(...arguments));
},
});
Response.prototype.json = new Proxy(Response.prototype.json, {
apply() {
return Reflect.apply(...arguments).then((o) => _prunerFn(o));
},
}); 0`,
async start({ getConfig }) {
const config = await getConfig();

View File

@ -37,19 +37,9 @@ export const inject = (contextBridge) => {
//
return o;
};
}
contextBridge.exposeInMainWorld('_proxyJsonParse', new Proxy(JSON.parse, {
apply() {
return pruner(Reflect.apply(...arguments));
},
}));
contextBridge.exposeInMainWorld('_proxyResponseJson', new Proxy(Response.prototype.json, {
apply() {
return Reflect.apply(...arguments).then((o) => pruner(o));
},
}));
contextBridge.exposeInMainWorld('_pruner', pruner);
}
const chains = [

View File

@ -261,12 +261,12 @@ async function downloadSongUnsafe(
let playabilityStatus = info.playability_status;
let bypassedResult = null;
if (playabilityStatus.status === 'LOGIN_REQUIRED') {
if (playabilityStatus?.status === 'LOGIN_REQUIRED') {
// Try to bypass the age restriction
bypassedResult = await getAndroidTvInfo(id);
playabilityStatus = bypassedResult.playability_status;
if (playabilityStatus.status === 'LOGIN_REQUIRED') {
if (playabilityStatus?.status === 'LOGIN_REQUIRED') {
throw new Error(
`[${playabilityStatus.status}] ${playabilityStatus.reason}`,
);
@ -275,7 +275,7 @@ async function downloadSongUnsafe(
info = bypassedResult;
}
if (playabilityStatus.status === 'UNPLAYABLE') {
if (playabilityStatus?.status === 'UNPLAYABLE') {
const errorScreen =
playabilityStatus.error_screen as PlayerErrorMessage | null;
throw new Error(

View File

@ -1,9 +1,9 @@
import { JSX } from 'solid-js';
import { css } from 'solid-styled-components';
import { cache } from '@/providers/decorators';
import { cacheNoArgs } from '@/providers/decorators';
const iconButton = cache(() => css`
const iconButton = cacheNoArgs(() => css`
-webkit-app-region: none;
background: transparent;

View File

@ -1,9 +1,9 @@
import { JSX, splitProps } from 'solid-js';
import { css } from 'solid-styled-components';
import { cache } from '@/providers/decorators';
import { cacheNoArgs } from '@/providers/decorators';
const menuStyle = cache(() => css`
const menuStyle = cacheNoArgs(() => css`
-webkit-app-region: none;
display: flex;

View File

@ -5,9 +5,9 @@ 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';
import { cacheNoArgs } from '@/providers/decorators';
const panelStyle = cache(() => css`
const panelStyle = cacheNoArgs(() => css`
position: fixed;
top: var(--offset-y, 0);
left: var(--offset-x, 0);
@ -36,7 +36,7 @@ const panelStyle = cache(() => css`
transform-origin: var(--origin-x, 50%) var(--origin-y, 50%);
`);
const animationStyle = cache(() => ({
const animationStyle = cacheNoArgs(() => ({
enter: css`
opacity: 0;
transform: scale(0.9);

View File

@ -8,9 +8,9 @@ import { useFloating } from 'solid-floating-ui';
import { autoUpdate, offset, size } from '@floating-ui/dom';
import { Panel } from './Panel';
import { cache } from '@/providers/decorators';
import { cacheNoArgs } from '@/providers/decorators';
const itemStyle = cache(() => css`
const itemStyle = cacheNoArgs(() => css`
position: relative;
-webkit-app-region: none;
@ -47,18 +47,18 @@ const itemStyle = cache(() => css`
}
`);
const itemIconStyle = cache(() => css`
const itemIconStyle = cacheNoArgs(() => css`
height: 32px;
padding: 4px;
color: white;
`);
const itemLabelStyle = cache(() => css`
const itemLabelStyle = cacheNoArgs(() => css`
font-size: 12px;
color: white;
`);
const itemChipStyle = cache(() => css`
const itemChipStyle = cacheNoArgs(() => css`
display: flex;
justify-content: center;
align-items: center;
@ -76,7 +76,7 @@ const itemChipStyle = cache(() => css`
line-height: 1;
`);
const toolTipStyle = cache(() => css`
const toolTipStyle = cacheNoArgs(() => css`
min-width: 32px;
width: 100%;
height: 100%;
@ -92,7 +92,7 @@ const toolTipStyle = cache(() => css`
font-size: 10px;
`);
const popupStyle = cache(() => css`
const popupStyle = cacheNoArgs(() => css`
position: fixed;
top: var(--offset-y, 0);
left: var(--offset-x, 0);
@ -105,7 +105,7 @@ const popupStyle = cache(() => css`
`);
const animationStyle = cache(() => ({
const animationStyle = cacheNoArgs(() => ({
enter: css`
opacity: 0;
transform: scale(0.9);

View File

@ -9,12 +9,12 @@ import { PanelItem } from './PanelItem';
import { IconButton } from './IconButton';
import { WindowController } from './WindowController';
import { cache } from '@/providers/decorators';
import { cacheNoArgs } from '@/providers/decorators';
import type { RendererContext } from '@/types/contexts';
import type { InAppMenuConfig } from '../constants';
const titleStyle = cache(() => css`
const titleStyle = cacheNoArgs(() => css`
-webkit-app-region: drag;
box-sizing: border-box;
@ -50,7 +50,7 @@ const titleStyle = cache(() => css`
}
`);
const separatorStyle = cache(() => css`
const separatorStyle = cacheNoArgs(() => css`
min-height: 1px;
height: 1px;
margin: 4px 0;
@ -58,7 +58,7 @@ const separatorStyle = cache(() => css`
background-color: rgba(255, 255, 255, 0.2);
`);
const animationStyle = cache(() => ({
const animationStyle = cacheNoArgs(() => ({
enter: css`
opacity: 0;
transform: translateX(-50%) scale(0.8);
@ -271,16 +271,15 @@ export const TitleBar = (props: TitleBarProps) => {
// tracking mouse position
window.addEventListener('mousemove', listener);
const ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
ytmusicAppLayout?.addEventListener("scroll",()=>{
ytmusicAppLayout?.addEventListener('scroll', () => {
const scrollValue = ytmusicAppLayout.scrollTop;
if (scrollValue > 20){
ytmusicAppLayout.classList.add("content-scrolled");
ytmusicAppLayout.classList.add('content-scrolled');
}
else{
ytmusicAppLayout.classList.remove("content-scrolled");
ytmusicAppLayout.classList.remove('content-scrolled');
}
})
});
});

View File

@ -2,9 +2,9 @@ import { css } from 'solid-styled-components';
import { Show } from 'solid-js';
import { IconButton } from './IconButton';
import { cache } from '@/providers/decorators';
import { cacheNoArgs } from '@/providers/decorators';
const containerStyle = cache(() => css`
const containerStyle = cacheNoArgs(() => css`
display: flex;
justify-content: flex-end;
align-items: center;

View File

@ -166,13 +166,13 @@ export default createPlugin<
this.profiles = {};
this.connection.onConnections((connection) => {
if (!connection) {
this.api?.openToast(t('plugins.music-together.toast.disconnected'));
this.api?.toastService?.show(t('plugins.music-together.toast.disconnected'));
this.onStop();
return;
}
if (!connection.open) {
this.api?.openToast(t('plugins.music-together.toast.user-disconnected', {
this.api?.toastService?.show(t('plugins.music-together.toast.user-disconnected', {
name: this.profiles[connection.peer]?.name
}));
this.putProfile(connection.peer, undefined);
@ -219,7 +219,7 @@ export default createPlugin<
break;
}
this.api?.openToast(t('plugins.music-together.toast.user-connected', { name: event.payload.profile.name }));
this.api?.toastService?.show(t('plugins.music-together.toast.user-connected', { name: event.payload.profile.name }));
this.putProfile(conn.peer, event.payload.profile);
break;
}
@ -307,7 +307,7 @@ export default createPlugin<
if (!connection) return false;
this.connection.onConnections((connection) => {
if (!connection?.open) {
this.api?.openToast(t('plugins.music-together.toast.disconnected'));
this.api?.toastService?.show(t('plugins.music-together.toast.disconnected'));
this.onStop();
}
});
@ -381,7 +381,7 @@ export default createPlugin<
const permissionLabel = t(`plugins.music-together.menu.permission.${this.permission}`);
this.api?.openToast(t('plugins.music-together.toast.permission-changed', { permission: permissionLabel }));
this.api?.toastService?.show(t('plugins.music-together.toast.permission-changed', { permission: permissionLabel }));
break;
}
default: {
@ -593,18 +593,18 @@ export default createPlugin<
onItemClick: (id) => {
if (id === 'music-together-close') {
this.onStop();
this.api?.openToast(t('plugins.music-together.toast.closed'));
this.api?.toastService?.show(t('plugins.music-together.toast.closed'));
hostPopup.dismiss();
}
if (id === 'music-together-copy-id') {
navigator.clipboard.writeText(this.connection?.id ?? '')
.then(() => {
this.api?.openToast(t('plugins.music-together.toast.id-copied'));
this.api?.toastService?.show(t('plugins.music-together.toast.id-copied'));
hostPopup.dismiss();
})
.catch(() => {
this.api?.openToast(t('plugins.music-together.toast.id-copy-failed'));
this.api?.toastService?.show(t('plugins.music-together.toast.id-copy-failed'));
hostPopup.dismiss();
});
}
@ -620,7 +620,7 @@ export default createPlugin<
settingPopup.setPermission(this.permission);
const permissionLabel = t(`plugins.music-together.menu.permission.${this.permission}`);
this.api?.openToast(t('plugins.music-together.toast.permission-changed', { permission: permissionLabel }));
this.api?.toastService?.show(t('plugins.music-together.toast.permission-changed', { permission: permissionLabel }));
const item = hostPopup.items.find((it) => it?.element.id === id);
if (item?.type === 'item') {
item.setText(t('plugins.music-together.menu.set-permission'));
@ -632,7 +632,7 @@ export default createPlugin<
onItemClick: (id) => {
if (id === 'music-together-disconnect') {
this.onStop();
this.api?.openToast(t('plugins.music-together.toast.disconnected'));
this.api?.toastService?.show(t('plugins.music-together.toast.disconnected'));
guestPopup.dismiss();
}
}
@ -648,14 +648,14 @@ export default createPlugin<
if (result) {
navigator.clipboard.writeText(this.connection?.id ?? '')
.then(() => {
this.api?.openToast(t('plugins.music-together.toast.id-copied'));
this.api?.toastService?.show(t('plugins.music-together.toast.id-copied'));
hostPopup.showAtAnchor(setting);
}).catch(() => {
this.api?.openToast(t('plugins.music-together.toast.id-copy-failed'));
this.api?.toastService?.show(t('plugins.music-together.toast.id-copy-failed'));
hostPopup.showAtAnchor(setting);
});
} else {
this.api?.openToast(t('plugins.music-together.toast.host-failed'));
this.api?.toastService?.show(t('plugins.music-together.toast.host-failed'));
}
}
@ -666,10 +666,10 @@ export default createPlugin<
this.hideSpinner();
if (result) {
this.api?.openToast(t('plugins.music-together.toast.joined'));
this.api?.toastService?.show(t('plugins.music-together.toast.joined'));
guestPopup.showAtAnchor(setting);
} else {
this.api?.openToast(t('plugins.music-together.toast.join-failed'));
this.api?.toastService?.show(t('plugins.music-together.toast.join-failed'));
}
}
}

View File

@ -1,4 +1,4 @@
import { BrowserWindow, ipcMain, globalShortcut } from 'electron';
import { BrowserWindow, globalShortcut } from 'electron';
import is from 'electron-is';
import { register as registerElectronLocalShortcut } from 'electron-localshortcut';
@ -48,9 +48,7 @@ export const onMainLoad = async ({
_registerLocalShortcut(window, 'CommandOrControl+L', search);
if (is.linux()) {
ipcMain.once('ytmd:video-src-changed', (_) => {
registerMPRIS(window);
});
}
const { global, local } = config;

View File

@ -16,10 +16,9 @@ export let _ytAPI: YoutubePlayer | null = null;
export const renderer = createRenderer<{
observerCallback: MutationCallback;
hasAddedEvents: boolean;
observer?: MutationObserver;
videoDataChange: () => Promise<void>;
progressCallback: (evt: Event) => void;
updateTimestampInterval?: NodeJS.Timeout | string | number;
}, SyncedLyricsPluginConfig>({
onConfigChange(newConfig) {
setConfig(newConfig);
@ -50,15 +49,12 @@ export const renderer = createRenderer<{
await this.videoDataChange();
},
hasAddedEvents: false,
async videoDataChange() {
if (!this.hasAddedEvents) {
const video = document.querySelector('video');
video?.addEventListener('timeupdate', this.progressCallback);
if (video) this.hasAddedEvents = true;
if (!this.updateTimestampInterval) {
this.updateTimestampInterval = setInterval(
() => setCurrentTime((_ytAPI?.getCurrentTime() ?? 0) * 1000),
100,
);
}
this.observer ??= new MutationObserver(
@ -73,16 +69,6 @@ export const renderer = createRenderer<{
header.removeAttribute('disabled');
},
progressCallback(evt: Event) {
switch (evt.type) {
case 'timeupdate': {
const video = evt.target as HTMLVideoElement;
setCurrentTime(video.currentTime * 1000);
break;
}
}
},
async start(ctx: RendererContext<SyncedLyricsPluginConfig>) {
setConfig(await ctx.getConfig());

View File

@ -17,14 +17,6 @@ export const [hadSecondAttempt, setHadSecondAttempt] = createSignal(false);
// prettier-ignore
export const [differentDuration, setDifferentDuration] = createSignal(false);
// eslint-disable-next-line prefer-const
export let foundPlainTextLyrics = false;
export type SongData = {
title: string;
artist: string;
album: string;
songDuration: number;
};
export const extractTimeAndText = (
line: string,
@ -33,7 +25,7 @@ export const extractTimeAndText = (
const groups = /\[(\d+):(\d+)\.(\d+)\](.+)/.exec(line);
if (!groups) return null;
const [_, rMinutes, rSeconds, rMillis, text] = groups;
const [, rMinutes, rSeconds, rMillis, text] = groups;
const [minutes, seconds, millis] = [
parseInt(rMinutes),
parseInt(rSeconds),
@ -46,7 +38,7 @@ export const extractTimeAndText = (
return {
index,
timeInMs,
time: `${minutes}:${seconds}:${millis}`,
time: `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}:${millis}`,
text: text?.trim() ?? config()!.defaultTextString,
status: 'upcoming',
duration: 0,
@ -54,22 +46,31 @@ export const extractTimeAndText = (
};
export const makeLyricsRequest = async (extractedSongInfo: SongInfo) => {
setIsFetching(true);
setLineLyrics([]);
const songData: SongData = {
const songData: Parameters<typeof getLyricsList>[0] = {
title: `${extractedSongInfo.title}`,
artist: `${extractedSongInfo.artist}`,
album: `${extractedSongInfo.album}`,
songDuration: extractedSongInfo.songDuration,
};
const lyrics = await getLyricsList(songData);
if (extractedSongInfo.album) {
songData.album = extractedSongInfo.album;
}
let lyrics;
try {
lyrics = await getLyricsList(songData);
} catch {}
setLineLyrics(lyrics ?? []);
setIsFetching(false);
};
export const getLyricsList = async (
songData: SongData,
songData: Pick<SongInfo, 'title' | 'artist' | 'album' | 'songDuration'>,
): Promise<LineLyrics[] | null> => {
setIsFetching(true);
setIsInstrumental(false);
setHadSecondAttempt(false);
setDifferentDuration(false);
@ -80,6 +81,7 @@ export const getLyricsList = async (
track_name: songData.title,
});
if (songData.album) {
query.set('album_name', songData.album);
}
@ -88,18 +90,12 @@ export const getLyricsList = async (
let response = await fetch(url);
if (!response.ok) {
setIsFetching(false);
setDebugInfo('Got non-OK response from server.');
return null;
}
let data = (await response.json().catch((e: Error) => {
setDebugInfo(`Error: ${e.message}\n\n${e.stack}`);
return null;
})) as LRCLIBSearchResponse | null;
let data = await response.json() as LRCLIBSearchResponse;
if (!data || !Array.isArray(data)) {
setIsFetching(false);
setDebugInfo('Unexpected server response.');
return null;
}
@ -115,14 +111,12 @@ export const getLyricsList = async (
response = await fetch(url);
if (!response.ok) {
setIsFetching(false);
setDebugInfo('Got non-OK response from server. (2)');
return null;
}
data = (await response.json()) as LRCLIBSearchResponse;
if (!Array.isArray(data)) {
setIsFetching(false);
setDebugInfo('Unexpected server response. (2)');
return null;
}
@ -132,15 +126,18 @@ export const getLyricsList = async (
const filteredResults = [];
for (const item of data) {
if (!item.syncedLyrics) continue;
const { artist } = songData;
const { artistName } = item;
const ratio = jaroWinkler(artist.toLowerCase(), artistName.toLowerCase());
const artists = artist.split(/[&,]/g).map((i) => i.trim());
const itemArtists = artistName.split(/[&,]/g).map((i) => i.trim());
if (ratio <= 0.9) continue;
filteredResults.push(item);
const permutations = artists.flatMap((artistA) =>
itemArtists.map((artistB) => [artistA.toLowerCase(), artistB.toLowerCase()])
);
const ratio = Math.max(...permutations.map(([x, y]) => jaroWinkler(x, y)));
if (ratio > 0.9) filteredResults.push(item);
}
const duration = songData.songDuration;
@ -153,36 +150,44 @@ export const getLyricsList = async (
const closestResult = filteredResults[0];
if (!closestResult) {
setIsFetching(false);
setDebugInfo('No search result matched the criteria.');
return null;
}
// setDebugInfo(JSON.stringify(closestResult, null, 4));
setDebugInfo(JSON.stringify(closestResult, null, 4));
if (Math.abs(closestResult.duration - duration) > 15) {
return null;
}
if (Math.abs(closestResult.duration - duration) > 15) return null;
if (Math.abs(closestResult.duration - duration) > 5) {
// show message that the timings may be wrong
setDifferentDuration(true);
}
setIsInstrumental(closestResult.instrumental);
if (closestResult.instrumental) {
return null;
}
// Separate the lyrics into lines
const raw = closestResult.syncedLyrics.split('\n');
const raw = closestResult.syncedLyrics?.split('\n') ?? [];
if (!raw.length) {
return null;
}
// Add a blank line at the beginning
raw.unshift('[0:0.0] ');
const syncedLyricList = [];
for (let idx = 0; idx < raw.length; idx++) {
const syncedLine = extractTimeAndText(raw[idx], idx);
const syncedLyricList = raw.reduce<LineLyrics[]>((acc, line, index) => {
const syncedLine = extractTimeAndText(line, index);
if (syncedLine) {
syncedLyricList.push(syncedLine);
}
acc.push(syncedLine);
}
return acc;
}, []);
for (const line of syncedLyricList) {
const next = syncedLyricList[line.index + 1];
if (!next) {
@ -193,6 +198,5 @@ export const getLyricsList = async (
line.duration = next.timeInMs - line.timeInMs;
}
setIsFetching(false);
return syncedLyricList;
};

View File

@ -40,6 +40,16 @@ export function cache<T extends (...params: P) => R, P extends never[], R>(
}) as T;
}
export function cacheNoArgs<R>(fn: () => R): () => R {
let cached: R;
return () => {
if (cached === undefined) {
cached = fn();
}
return cached;
};
}
/*
The following are currently unused, but potentially useful in the future
*/

View File

@ -2,7 +2,7 @@ import { singleton } from './decorators';
import type { YoutubePlayer } from '@/types/youtube-player';
import type { GetState } from '@/types/datahost-get-state';
import type { AlbumDetails, VideoDataChangeValue } from '@/types/player-api-events';
import type { AlbumDetails, PlayerOverlays, VideoDataChangeValue } from '@/types/player-api-events';
import type { SongInfo } from './song-info';
import type { VideoDataChanged } from '@/types/video-data-changed';
@ -200,16 +200,43 @@ export default (api: YoutubePlayer) => {
for (const status of ['playing', 'pause'] as const) {
video.addEventListener(status, playPausedHandlers[status]);
}
if (!isNaN(video.duration)) {
const {
title, author,
video_id: videoId,
list: playlistId
} = api.getVideoData();
const watchNextResponse = api.getWatchNextResponse();
sendSongInfo({
title, author, videoId, playlistId,
isUpcoming: false,
lengthSeconds: video.duration,
loading: true,
ytmdWatchNextResponse: watchNextResponse,
} satisfies VideoDataChangeValue);
}
}
function sendSongInfo(videoData: VideoDataChangeValue) {
const data = api.getPlayerResponse();
data.videoDetails.album = (
let playerOverlay: PlayerOverlays | undefined;
if (!videoData.ytmdWatchNextResponse) {
playerOverlay = (
Object.entries(videoData).find(
([, value]) => value && Object.hasOwn(value, 'playerOverlays'),
) as [string, AlbumDetails | undefined]
)?.[1]?.playerOverlays?.playerOverlayRenderer?.browserMediaSession?.browserMediaSessionRenderer?.album?.runs?.at(
)?.[1]?.playerOverlays;
} else {
playerOverlay = videoData.ytmdWatchNextResponse?.playerOverlays;
}
data.videoDetails.album = playerOverlay?.playerOverlayRenderer?.browserMediaSession?.browserMediaSessionRenderer?.album?.runs?.at(
0,
)?.text;
data.videoDetails.elapsedSeconds = 0;

View File

@ -214,14 +214,14 @@ const suffixesToRemove = [
/\s*vevo$/i,
// Video titles
/\s*[(|\[]official(.*?)[)|\]]/i, // (Official Music Video), [Official Visualizer], etc...
/\s*[(|\[]((lyrics?|visualizer|audio)\s*(video)?)[)|\]]/i,
/\s*[(|\[](performance video)[)|\]]/i,
/\s*[(|\[](clip official)[)|\]]/i,
/\s*[(|\[](video version)[)|\]]/i,
/\s*[(|\[](HD|HQ)\s*?(?:audio)?[)|\]]$/i,
/\s*[(|\[](live)[)|\]]$/i,
/\s*[(|\[]4K\s*?(?:upgrade)?[)|\]]$/i,
/\s*[(|[]official(.*?)[)|\]]/i, // (Official Music Video), [Official Visualizer], etc...
/\s*[(|[]((lyrics?|visualizer|audio)\s*(video)?)[)|\]]/i,
/\s*[(|[](performance video)[)|\]]/i,
/\s*[(|[](clip official)[)|\]]/i,
/\s*[(|[](video version)[)|\]]/i,
/\s*[(|[](HD|HQ)\s*?(?:audio)?[)|\]]$/i,
/\s*[(|[](live)[)|\]]$/i,
/\s*[(|[]4K\s*?(?:upgrade)?[)|\]]$/i,
];
export function cleanupName(name: string): string {

View File

@ -23,6 +23,14 @@ let isPluginLoaded = false;
let isApiLoaded = false;
let firstDataLoaded = false;
if (window.trustedTypes && window.trustedTypes.createPolicy && !window.trustedTypes.defaultPolicy) {
window.trustedTypes.createPolicy('default', {
createHTML: (input) => input,
createScriptURL: (input) => input,
createScript: (input) => input,
});
}
async function listenForApiLoad() {
if (!isApiLoaded) {
api = document.querySelector('#movie_player');
@ -172,10 +180,19 @@ async function onApiLoaded() {
// Remove upgrade button
if (window.mainConfig.get('options.removeUpgradeButton')) {
const itemsSelector = 'ytmusic-guide-section-renderer #items';
let selector = 'ytmusic-guide-entry-renderer:last-child';
const upgradeBtnIcon = document.querySelector<SVGGElement>('iron-iconset-svg[name="yt-sys-icons"] #youtube_music_monochrome');
if (upgradeBtnIcon) {
const path = upgradeBtnIcon.firstChild as SVGPathElement;
const data = path.getAttribute('d')!.substring(0, 15);
selector = `ytmusic-guide-entry-renderer:has(> tp-yt-paper-item > yt-icon path[d^="${data}"])`;
}
const styles = document.createElement('style');
styles.innerHTML = `ytmusic-guide-section-renderer #items ytmusic-guide-entry-renderer:last-child {
display: none;
}`;
styles.textContent = `${itemsSelector} ${selector} { display: none; }`;
document.head.appendChild(styles);
}

2
src/reset.d.ts vendored
View File

@ -6,6 +6,7 @@ import type is from 'electron-is';
import type config from './config';
import type { VideoDataChanged } from '@/types/video-data-changed';
import type { t } from '@/i18n';
import type { trustedTypes } from 'trusted-types';
declare global {
interface Compressor {
@ -19,6 +20,7 @@ declare global {
}
interface Window {
trustedTypes?: typeof trustedTypes;
ipcRenderer: typeof electronIpcRenderer;
mainConfig: typeof config;
electronIs: typeof is;

View File

@ -1,3 +1,5 @@
import type { WatchNextResponse } from '@/types/youtube-music-desktop-internal';
export interface AlbumDetails {
responseContext: ResponseContext;
contents: Contents;
@ -252,6 +254,11 @@ export type VideoDataChangeValue = Record<string, unknown> & {
loading: boolean;
lengthSeconds: number;
/**
* YouTube Music Desktop internal variable (for album data)
**/
ytmdWatchNextResponse?: WatchNextResponse;
};
export interface PlayerAPIEvents {

View File

@ -30,11 +30,39 @@ export type QueueAPI = {
continuation?: string;
autoPlaying?: boolean;
};
export type ToastElement = HTMLElement & {
autoFitOnAttach: boolean;
duration: number;
expandSizingTargetForScrollbars: boolean;
horizontalAlign: 'left' | 'right' | 'center';
importPath?: unknown;
label: string;
noAutoFocus: boolean;
noCancelOnEscKey: boolean;
noCancelOnOutsideClick: boolean;
noIronAnnounce: boolean;
restoreFocusOnClose: boolean;
root: ToastElement;
rootPath: string;
sizingTarget: ToastElement;
verticalAlign: 'bottom' | 'top' | 'center';
};
export interface ToastService {
attached: boolean;
displaying: boolean;
messageQueue: string[];
toastElement: ToastElement;
show: (message: string) => void;
}
export type AppElement = HTMLElement & AppAPI;
export type AppAPI = {
queue_: QueueAPI;
playerApi_: YoutubePlayer;
openToast: (message: string) => void;
queue: QueueAPI;
playerApi: YoutubePlayer;
toastService: ToastService;
// TODO: Add more
};

View File

@ -1,7 +1,12 @@
import type { QueueItem } from '@/types/datahost-get-state';
import type { PlayerOverlays } from '@/types/player-api-events';
export interface QueueResponse {
items?: QueueItem[];
autoPlaying?: boolean;
continuation?: string;
}
export interface WatchNextResponse {
playerOverlays?: PlayerOverlays;
}

View File

@ -3,6 +3,7 @@
import { VideoDetails } from './video-details';
import { GetPlayerResponse } from './get-player-response';
import { PlayerAPIEvents } from './player-api-events';
import { WatchNextResponse } from '@/types/youtube-music-desktop-internal';
export interface YoutubePlayer {
getInternalApiInterface: <Parameters extends unknown[], Return>(
@ -427,4 +428,6 @@ export interface YoutubePlayer {
addEmbedsConversionTrackingParams: <Parameters extends unknown[], Return>(
...params: Parameters
) => Return;
getWatchNextResponse(): WatchNextResponse;
}