Compare commits

..

36 Commits

Author SHA1 Message Date
1e9f32e248 Merge branch 'master' into synced-lyrics/netease 2025-12-04 09:26:15 +02:00
6c4ae0dbfa chore(i18n): Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (457 of 457 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hans/
2025-12-03 01:00:18 +01:00
f7aaa3377a chore(i18n): Translated using Weblate (Slovak)
Currently translated at 88.3% (403 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-12-01 22:00:36 +01:00
ab1a0478cf chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2025-12-01 22:00:35 +01:00
127f56905c fix(album-color-theme): improve theming consistency across UI elements (#4109)
Co-authored-by: 최민우 <chaeminu0711@gmail.com>
2025-12-01 16:25:14 +09:00
8d448c667f chore(i18n): Translated using Weblate (Urdu)
Currently translated at 25.0% (114 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ur/
2025-11-29 08:01:53 +01:00
e00f33eb2d chore(i18n): Translated using Weblate (Slovak)
Currently translated at 84.4% (385 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-29 08:01:52 +01:00
8100804ced chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 46.9% (214 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-11-28 06:02:01 +01:00
dbbdb63aa8 feat(synced-lyrics): NetEase provider 2025-11-26 23:23:00 +02:00
4fba3ffd92 fix(downloader): update youtubei.js and remove player_id (#4069) 2025-11-26 21:20:58 +02:00
bef8252314 chore(i18n): Translated using Weblate (Slovak)
Currently translated at 84.4% (385 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-22 23:51:18 +01:00
a96cc5aa8a chore(i18n): Translated using Weblate (German)
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/de/
2025-11-22 23:51:16 +01:00
b7e43e3125 chore(i18n): Translated using Weblate (Galician)
Currently translated at 23.2% (106 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/gl/
2025-11-21 21:51:18 +00:00
2d059eb353 chore(i18n): Translated using Weblate (Hindi)
Currently translated at 86.6% (395 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hi/
2025-11-20 13:51:30 +01:00
bce0f8ad17 chore(i18n): Translated using Weblate (Hindi)
Currently translated at 86.6% (395 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/hi/
2025-11-20 13:51:22 +01:00
e04a084be9 chore(i18n): Translated using Weblate (Estonian)
Currently translated at 33.3% (152 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2025-11-20 13:51:21 +01:00
J
e94aa5c513 chore(i18n): Translated using Weblate (Estonian)
Currently translated at 33.3% (152 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2025-11-20 13:51:20 +01:00
fa2862ca9a chore(i18n): Translated using Weblate (Azerbaijani)
Currently translated at 16.4% (75 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/az/
2025-11-17 18:51:19 +01:00
e764c69f2b chore(i18n): Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/pt_BR/
2025-11-15 14:51:17 +01:00
b5052d85ad chore(i18n): Translated using Weblate (Slovak)
Currently translated at 81.1% (370 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-08 09:51:16 +00:00
e4fa850871 chore(i18n): Translated using Weblate (Slovak)
Currently translated at 77.6% (354 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-06 14:51:55 +01:00
db4be4ae25 chore(i18n): Translated using Weblate (Slovak)
Currently translated at 77.6% (354 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-06 14:51:54 +01:00
55680531c5 chore(i18n): Translated using Weblate (Slovak)
Currently translated at 77.6% (354 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-06 14:51:19 +01:00
ae4557d32c chore(i18n): Translated using Weblate (Czech)
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/cs/
2025-11-06 14:51:14 +01:00
f5f65e73ca chore(i18n): Translated using Weblate (Slovak)
Currently translated at 25.2% (115 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-05 08:51:18 +01:00
e9f4958252 chore(i18n): Translated using Weblate (Slovak)
Currently translated at 25.0% (114 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-04 04:51:18 +01:00
00626bc37d chore(i18n): Translated using Weblate (Urdu)
Currently translated at 24.3% (111 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ur/
2025-11-04 04:51:13 +01:00
8e36d77245 chore(i18n): Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/zh_Hant/
2025-11-02 20:51:14 +00:00
8f6d16ae89 chore(i18n): Translated using Weblate (Korean)
Currently translated at 100.0% (456 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ko/
2025-11-02 20:51:12 +00:00
2d1d0257ef chore(i18n): Added translation using Weblate (Belarusian) 2025-10-31 19:41:59 +01:00
7b2543847a chore(i18n): Translated using Weblate (Malay)
Currently translated at 70.3% (321 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ms/
2025-10-31 19:41:57 +01:00
00af45ddee chore(i18n): Translated using Weblate (Malay)
Currently translated at 70.3% (321 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ms/
2025-10-31 19:41:57 +01:00
786961c33b chore(i18n): Translated using Weblate (Estonian)
Currently translated at 25.2% (115 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/et/
2025-10-29 13:50:16 +01:00
8dc69cd9ac chore(i18n): Translated using Weblate (Ukrainian)
Currently translated at 96.0% (438 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/uk/
2025-10-29 13:50:15 +01:00
d8e0bd903e chore(i18n): Translated using Weblate (Azerbaijani)
Currently translated at 16.0% (73 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/az/
2025-10-27 16:02:51 +00:00
4f31d47097 chore(i18n): Translated using Weblate (Georgian)
Currently translated at 20.1% (92 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ka/
2025-10-23 06:02:44 +00:00
27 changed files with 1748 additions and 161 deletions

View File

@ -90,6 +90,7 @@
"butterchurn-presets": "3.0.0-beta.4",
"color": "5.0.0",
"conf": "14.0.0",
"crypto-js": "^4.2.0",
"custom-electron-prompt": "1.5.8",
"deepmerge-ts": "7.1.5",
"delay": "6.0.0",
@ -134,7 +135,7 @@
"virtua": "0.42.3",
"vudio": "2.1.1",
"x11": "2.3.0",
"youtubei.js": "15.0.1",
"youtubei.js": "^16.0.1",
"zod": "4.1.5"
},
"devDependencies": {
@ -144,6 +145,7 @@
"@playwright/test": "1.55.0",
"@stylistic/eslint-plugin": "5.3.1",
"@total-typescript/ts-reset": "0.6.1",
"@types/crypto-js": "^4.2.2",
"@types/electron-localshortcut": "3.1.3",
"@types/howler": "2.2.12",
"@types/html-to-text": "9.0.4",
@ -168,7 +170,7 @@
"eslint-plugin-solid": "0.14.5",
"glob": "11.0.3",
"node-gyp": "11.4.2",
"playwright": "1.55.1",
"playwright": "1.55.0",
"ts-morph": "27.0.0",
"typescript": "5.9.2",
"typescript-eslint": "8.43.0",

187
pnpm-lock.yaml generated
View File

@ -117,6 +117,9 @@ importers:
conf:
specifier: 14.0.0
version: 14.0.0
crypto-js:
specifier: ^4.2.0
version: 4.2.0
custom-electron-prompt:
specifier: 1.5.8
version: 1.5.8(electron@38.2.0)
@ -250,8 +253,8 @@ importers:
specifier: 2.3.0
version: 2.3.0
youtubei.js:
specifier: 15.0.1
version: 15.0.1
specifier: ^16.0.1
version: 16.0.1
zod:
specifier: 4.1.5
version: 4.1.5
@ -271,6 +274,9 @@ importers:
'@total-typescript/ts-reset':
specifier: 0.6.1
version: 0.6.1
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
'@types/electron-localshortcut':
specifier: 3.1.3
version: 3.1.3
@ -344,8 +350,8 @@ importers:
specifier: 11.4.2
version: 11.4.2
playwright:
specifier: 1.55.1
version: 1.55.1
specifier: 1.55.0
version: 1.55.0
ts-morph:
specifier: 27.0.0
version: 27.0.0
@ -482,8 +488,8 @@ packages:
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
engines: {node: '>=6.9.0'}
'@bufbuild/protobuf@2.6.3':
resolution: {integrity: sha512-w/gJKME9mYN7ZoUAmSMAWXk4hkVpxRKvEJCb3dV5g9wwWdxTJJ0ayOJAVcNxtdqaxDyFuC0uz4RSGVacJ030PQ==}
'@bufbuild/protobuf@2.10.0':
resolution: {integrity: sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ==}
'@dehoist/romanize-thai@1.0.0':
resolution: {integrity: sha512-6SqD4vyZ48otnypLXMh901CeQetoP5ptYOaIr58N6zDqjjoN0bHszMb5d/6AXJJQf8kIvbmSWBeuDrbAWLajPQ==}
@ -1298,6 +1304,9 @@ packages:
'@types/cacheable-request@6.0.3':
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
'@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
'@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
@ -1379,16 +1388,32 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.42.0':
resolution: {integrity: sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.43.0':
resolution: {integrity: sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.42.0':
resolution: {integrity: sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/scope-manager@8.43.0':
resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.42.0':
resolution: {integrity: sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/tsconfig-utils@8.43.0':
resolution: {integrity: sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1402,16 +1427,33 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.42.0':
resolution: {integrity: sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/types@8.43.0':
resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.42.0':
resolution: {integrity: sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/typescript-estree@8.43.0':
resolution: {integrity: sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.42.0':
resolution: {integrity: sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.43.0':
resolution: {integrity: sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -1419,6 +1461,10 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.42.0':
resolution: {integrity: sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/visitor-keys@8.43.0':
resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -2017,6 +2063,9 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
@ -2534,6 +2583,9 @@ packages:
exponential-backoff@3.1.2:
resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==}
exponential-backoff@3.1.3:
resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==}
extract-zip@2.0.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
@ -3177,9 +3229,6 @@ packages:
resolution: {integrity: sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==}
engines: {node: '>=18'}
jintr@3.3.1:
resolution: {integrity: sha512-nnOzyhf0SLpbWuZ270Omwbj5LcXUkTcZkVnK8/veJXtSZOiATM5gMZMdmzN75FmTyj+NVgrGaPdH12zIJ24oIA==}
jpeg-js@0.4.4:
resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
@ -3443,6 +3492,10 @@ packages:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
meriyah@6.1.4:
resolution: {integrity: sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==}
engines: {node: '>=18.0.0'}
micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
@ -3862,21 +3915,11 @@ packages:
engines: {node: '>=18'}
hasBin: true
playwright-core@1.55.1:
resolution: {integrity: sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==}
engines: {node: '>=18'}
hasBin: true
playwright@1.55.0:
resolution: {integrity: sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==}
engines: {node: '>=18'}
hasBin: true
playwright@1.55.1:
resolution: {integrity: sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==}
engines: {node: '>=18'}
hasBin: true
plist@3.1.0:
resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==}
engines: {node: '>=10.4.0'}
@ -4454,6 +4497,10 @@ packages:
tinycolor2@1.6.0:
resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==}
tinyglobby@0.2.14:
resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==}
engines: {node: '>=12.0.0'}
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
@ -4844,8 +4891,8 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
youtubei.js@15.0.1:
resolution: {integrity: sha512-2slapqJS5NuXKHvcACEknyVz0AjH/TrXaOhDM0q2twQKa54kCmfj+7B/2nGfd20uzAe29zW1ejk2qOc4ABuGkg==}
youtubei.js@16.0.1:
resolution: {integrity: sha512-3802bCAGkBc2/G5WUTc0l/bO5mPYJbQAHL04d9hE9PnrDHoBUT8MN721Yqt4RCNncAXdHcfee9VdJy3Fhq1r5g==}
zlibjs@0.3.1:
resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==}
@ -4990,7 +5037,7 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@bufbuild/protobuf@2.6.3': {}
'@bufbuild/protobuf@2.10.0': {}
'@dehoist/romanize-thai@1.0.0': {}
@ -5060,7 +5107,7 @@ snapshots:
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
dependencies:
env-paths: 2.2.1
exponential-backoff: 3.1.2
exponential-backoff: 3.1.3
glob: 8.1.0
graceful-fs: 4.2.11
make-fetch-happen: 10.2.1
@ -5827,7 +5874,7 @@ snapshots:
'@stylistic/eslint-plugin@5.3.1(eslint@9.35.0)':
dependencies:
'@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0)
'@typescript-eslint/types': 8.43.0
'@typescript-eslint/types': 8.42.0
eslint: 9.35.0
eslint-visitor-keys: 4.2.1
espree: 10.4.0
@ -5848,7 +5895,7 @@ snapshots:
dependencies:
minimatch: 10.0.3
path-browserify: 1.0.1
tinyglobby: 0.2.15
tinyglobby: 0.2.14
'@tybys/wasm-util@0.10.0':
dependencies:
@ -5883,6 +5930,8 @@ snapshots:
'@types/node': 24.3.0
'@types/responselike': 1.0.3
'@types/crypto-js@4.2.2': {}
'@types/debug@4.1.12':
dependencies:
'@types/ms': 2.1.0
@ -5982,6 +6031,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.42.0(typescript@5.9.2)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.9.2)
'@typescript-eslint/types': 8.42.0
debug: 4.4.1
typescript: 5.9.2
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.43.0(typescript@5.9.2)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.43.0(typescript@5.9.2)
@ -5991,11 +6049,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.42.0':
dependencies:
'@typescript-eslint/types': 8.42.0
'@typescript-eslint/visitor-keys': 8.42.0
'@typescript-eslint/scope-manager@8.43.0':
dependencies:
'@typescript-eslint/types': 8.43.0
'@typescript-eslint/visitor-keys': 8.43.0
'@typescript-eslint/tsconfig-utils@8.42.0(typescript@5.9.2)':
dependencies:
typescript: 5.9.2
'@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.2)':
dependencies:
typescript: 5.9.2
@ -6012,8 +6079,26 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.42.0': {}
'@typescript-eslint/types@8.43.0': {}
'@typescript-eslint/typescript-estree@8.42.0(typescript@5.9.2)':
dependencies:
'@typescript-eslint/project-service': 8.42.0(typescript@5.9.2)
'@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.9.2)
'@typescript-eslint/types': 8.42.0
'@typescript-eslint/visitor-keys': 8.42.0
debug: 4.4.1
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.7.2
ts-api-utils: 2.1.0(typescript@5.9.2)
typescript: 5.9.2
transitivePeerDependencies:
- supports-color
'@typescript-eslint/typescript-estree@8.43.0(typescript@5.9.2)':
dependencies:
'@typescript-eslint/project-service': 8.43.0(typescript@5.9.2)
@ -6030,6 +6115,17 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.42.0(eslint@9.35.0)(typescript@5.9.2)':
dependencies:
'@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0)
'@typescript-eslint/scope-manager': 8.42.0
'@typescript-eslint/types': 8.42.0
'@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2)
eslint: 9.35.0
typescript: 5.9.2
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.43.0(eslint@9.35.0)(typescript@5.9.2)':
dependencies:
'@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0)
@ -6041,6 +6137,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.42.0':
dependencies:
'@typescript-eslint/types': 8.42.0
eslint-visitor-keys: 4.2.1
'@typescript-eslint/visitor-keys@8.43.0':
dependencies:
'@typescript-eslint/types': 8.43.0
@ -6708,6 +6809,8 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
crypto-js@4.2.0: {}
css-select@5.2.2:
dependencies:
boolbase: 1.0.0
@ -7254,7 +7357,7 @@ snapshots:
get-tsconfig: 4.10.1
is-bun-module: 2.0.0
stable-hash-x: 0.2.0
tinyglobby: 0.2.15
tinyglobby: 0.2.14
unrs-resolver: 1.11.1
optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.43.0(eslint@9.35.0)(typescript@5.9.2))(eslint-import-resolver-typescript@4.4.4)(eslint@9.35.0)
@ -7312,7 +7415,7 @@ snapshots:
eslint-plugin-solid@0.14.5(eslint@9.35.0)(typescript@5.9.2):
dependencies:
'@typescript-eslint/utils': 8.43.0(eslint@9.35.0)(typescript@5.9.2)
'@typescript-eslint/utils': 8.42.0(eslint@9.35.0)(typescript@5.9.2)
eslint: 9.35.0
estraverse: 5.3.0
is-html: 2.0.0
@ -7422,6 +7525,8 @@ snapshots:
exponential-backoff@3.1.2: {}
exponential-backoff@3.1.3: {}
extract-zip@2.0.1:
dependencies:
debug: 4.4.1
@ -8117,10 +8222,6 @@ snapshots:
'@jimp/types': 1.6.0
'@jimp/utils': 1.6.0
jintr@3.3.1:
dependencies:
acorn: 8.15.0
jpeg-js@0.4.4: {}
js-tokens@4.0.0: {}
@ -8387,6 +8488,8 @@ snapshots:
merge2@1.4.1: {}
meriyah@6.1.4: {}
micromatch@4.0.8:
dependencies:
braces: 3.0.3
@ -8544,7 +8647,7 @@ snapshots:
proc-log: 5.0.0
semver: 7.7.2
tar: 7.4.3
tinyglobby: 0.2.15
tinyglobby: 0.2.14
which: 5.0.0
transitivePeerDependencies:
- supports-color
@ -8775,20 +8878,12 @@ snapshots:
playwright-core@1.55.0: {}
playwright-core@1.55.1: {}
playwright@1.55.0:
dependencies:
playwright-core: 1.55.0
optionalDependencies:
fsevents: 2.3.2
playwright@1.55.1:
dependencies:
playwright-core: 1.55.1
optionalDependencies:
fsevents: 2.3.2
plist@3.1.0:
dependencies:
'@xmldom/xmldom': 0.8.11
@ -9413,6 +9508,11 @@ snapshots:
tinycolor2@1.6.0: {}
tinyglobby@0.2.14:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
@ -9824,11 +9924,10 @@ snapshots:
yocto-queue@0.1.0: {}
youtubei.js@15.0.1:
youtubei.js@16.0.1:
dependencies:
'@bufbuild/protobuf': 2.6.3
jintr: 3.3.1
undici: 6.21.3
'@bufbuild/protobuf': 2.10.0
meriyah: 6.1.4
zlibjs@0.3.1: {}

View File

@ -116,7 +116,54 @@
"auto-update": "Avtomatik Yeniləmə",
"hide-menu": {
"dialog": {
"message": "Menu will be hidden on next launch, use [Alt] to show it (or backtick [`] if using in-app-menu)"
"message": "Menyu növbəti açılışda gizlədiləcək, göstərmək üçün [Alt] düyməsini basın (proqramdaxili menyudan istifadə edildikdə isə, [`] düyməsi).",
"title": "Menyu gizlətmə aktivdir"
},
"label": "Menyunu gizlət"
},
"language": {
"dialog": {
"message": "Dil yenidən başlatmadan sonra dəyişiləcək",
"title": "Dil dəyişdirildi"
},
"label": "Dil",
"submenu": {
"to-help-translate": "Tərcüməyə kömək etmək istəyirsiniz? Buraya basın"
}
},
"resume-on-start": "Tətbiq başladıqda son mahnıdan davam et",
"single-instance-lock": "Tək proqram kilidi",
"start-at-login": "Giriş səhifəsində başlat",
"starting-page": {
"label": "Giriş səhifəsi",
"unset": "Təyin edilməyib"
},
"tray": {
"submenu": {
"disabled": "Deaktiv edilib"
}
},
"visual-tweaks": {
"label": "Vizual düzəlişlər",
"submenu": {
"custom-window-title": {
"prompt": {
"placeholder": "Nümunə: Pear Desktop"
}
},
"like-buttons": {
"default": "Standart",
"hide": "Gizlət"
},
"remove-upgrade-button": "Yeniləmə düyməsini sil",
"theme": {
"dialog": {
"button": {
"cancel": "Ləğv et",
"remove": "Sil"
}
}
}
}
}
}

View File

@ -0,0 +1 @@
{}

View File

@ -337,7 +337,7 @@
}
},
"audio-compressor": {
"description": "Apply compression k audiu (snižuje hlasitost nejhlasitěších částí signálu and zvyšuje hlasitost nejjemnějších částí)",
"description": "Aplikuje kompresi k audiu (snižuje hlasitost nejhlasitěších částí signálu a zvyšuje hlasitost nejjemnějších částí)",
"name": "Audio kompresor"
},
"auth-proxy-adapter": {
@ -462,8 +462,8 @@
"label": "Text statusu",
"submenu": {
"artist": "Poslouchám: {artist}",
"title": "Poslouchám {song title}",
"pear-desktop": "Poslouchám Pear Desktop"
"pear-desktop": "Poslouchám Pear Desktop",
"title": "Poslouchám {song title}"
}
}
},

View File

@ -3,7 +3,7 @@
"console": {
"plugins": {
"execute-failed": "Erweiterung {{pluginName}}::{{contextName}} konnte nicht ausgeführt werden",
"executed-at-ms": "Erweiterung {{pluginName}}::{{contextName}} ausgeführt in {{ms}}ms",
"executed-at-ms": "Erweiterung {{pluginName}}::{{contextName}} in {{ms}}ms ausgeführt",
"initialize-failed": "Initialisierung der Erweiterung \"{{pluginName}}\" fehlgeschlagen",
"load-all": "Lade alle Erweiterungen",
"load-failed": "Laden der Erweiterung \"{{pluginName}}\" fehlgeschlagen",

View File

@ -237,7 +237,8 @@
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"enable-seekbar": "Enable seekbar theming"
},
"name": "Album Color Theme"
},

View File

@ -31,6 +31,15 @@
},
"theme": {
"css-file-not-found": "CSS faili „{{cssFile}}“ pole olemas, seega eirame eelistust"
},
"unresponsive": {
"details": "Tõrge ei vasta!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Programmi vahemälu kustutamine"
},
"window": {
"tried-to-render-offscreen": "Akent prooviti renderdada väljaspool ekraani, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
}
},
"dialog": {
@ -89,9 +98,29 @@
"submenu": {
"auto-reset-app-cache": "Rakenduse käivitamisel lähtesta puhverdatud andmed",
"disable-hardware-acceleration": "Lülita raudvaraline kiirendamine välja",
"edit-config-json": "Muuda config.json faili"
"edit-config-json": "Muuda config.json faili",
"override-user-agent": "Jõudlusta User-Agent",
"restart-on-config-changes": "Taaskäivita pärast konfiguratsiooni muutmist",
"set-proxy": {
"label": "Määra proxy",
"prompt": {
"label": "Sisesta proxy aadress: (jäta täitmata, et välja lülitada)",
"placeholder": "Näide: SOCKS5://127.0.0.1:9999",
"title": "Määra proxy"
}
},
"toggle-dev-tools": "Lülita sisse arendaja tööriistad"
}
},
"always-on-top": "Alati esiplaanil",
"auto-update": "Automaatsed uuendused",
"hide-menu": {
"dialog": {
"message": "Järgmisel käivitamisel jääb menüü peidetuks, kasutage [Alt] klahvi, et näidata (või [`], kui kasutate rakendusesisest menüüd)",
"title": "Menüü peitmine on sisse lülitatud"
},
"label": "Peida menüü"
},
"language": {
"dialog": {
"message": "Keele muutmine jõustub peale uuesti käivitamist",
@ -102,15 +131,69 @@
"to-help-translate": "Soovid aidata tõlkimisel? Klõpsi siin"
}
},
"resume-on-start": "Rakenduse käivitamisel jätka viimatiesitatud loo esitamist"
"resume-on-start": "Rakenduse käivitamisel jätka viimatiesitatud loo esitamist",
"single-instance-lock": "Ühe instantsi lukk",
"start-at-login": "Käivita sisselogimisel",
"starting-page": {
"label": "Avaleht",
"unset": "Määramata"
},
"tray": {
"label": "Trey",
"submenu": {
"disabled": "Välja lülitatud",
"enabled-and-hide-app": "Sisse lülitatud ja rakendus peidetud",
"enabled-and-show-app": "Sisse lülitatud ja rakendus nähtav",
"play-pause-on-click": "Mängi/Peata klõpsates"
}
},
"visual-tweaks": {
"label": "Visuaalsed muudatused",
"submenu": {
"custom-window-title": {
"label": "Kohandatud akna tiitel",
"prompt": {
"label": "Sisesta kohandatud akna tiitel: (jäta täitmata, et välja lülitada)",
"placeholder": "Näide: Pear Desktop"
}
},
"like-buttons": {
"default": "Vaikimisi",
"force-show": "Sunni näitama",
"hide": "Peida",
"label": "Meeldib nupud"
},
"remove-upgrade-button": "Eemalda upgrade nupp",
"theme": {
"dialog": {
"button": {
"cancel": "Katkesta",
"remove": "Eemalda"
},
"remove-theme": "Kas oled kindel, et soovid enda loodud kujunduse eemaldada?",
"remove-theme-message": "Sellega saab sinu loodud kujundus eemdladatud"
},
"label": "Kujundus",
"submenu": {
"import-css-file": "Impordi kohandatud CSS fail",
"no-theme": "Ilma kujunduseta"
}
}
}
}
}
},
"plugins": {
"enabled": "Kasutusel",
"label": "Lisamoodulid",
"new": "UUS"
},
"view": {
"label": "Vaata",
"submenu": {
"force-reload": "Laadi sundkorras uuesti",
"reload": "Laadi uuesti",
"reset-zoom": "Tegelik suurus",
"toggle-fullscreen": "Lülita täisekraanivaade sisse/välja",
"zoom-in": "Suumi sisse",
"zoom-out": "Suumi välja"
@ -142,8 +225,28 @@
},
"name": "Reklaamiblokeerija"
},
"ambient-mode": {
"album-actions": {
"description": "Lisab Undislike, Ebameeldiv, Meeldiv ja Unlike nupud selle rakendamiseks kõikidele loendisse või albumisse kuuluvatele lauludele.",
"name": "Albumi aktsioonid"
},
"album-color-theme": {
"description": "Rakendab dünaamilist teemat ja visuaalseid efekte, mis põhinevad albumi värvipalettil",
"menu": {
"color-mix-ratio": {
"label": "Värvide segamissuhe",
"submenu": {
"percent": "{{suhe}}%"
}
}
},
"name": "Albumi värviteema"
},
"ambient-mode": {
"description": "Rakendab valgusefekti, projitseerides videost õrnad värvid ekraani taustale",
"menu": {
"blur-amount": {
"label": "Hägusus"
},
"opacity": {
"submenu": {
"percent": "{{opacity}}%"

View File

@ -53,8 +53,158 @@
"later": "Despois",
"restart-now": "Reiniciar Agora"
},
"detail": "O plugin \"{{pluginName}}\" precisa dun reinicio para tomar efecto"
"detail": "O plugin \"{{pluginName}}\" precisa dun reinicio para tomar efecto",
"message": "\"{{pluginName}}\" precisa reiniciar",
"title": "Requírese reinicio"
},
"unresponsive": {
"buttons": {
"quit": "Saír",
"relaunch": "Lanzar de novo",
"wait": "Agardar"
},
"detail": "Desculpa o inconveniente! Por favor escolle que facer:",
"message": "A aplicación non responde",
"title": "A xanela non responde"
},
"update-available": {
"buttons": {
"disable": "Desactivar actualizacións",
"download": "Descarregar",
"ok": "OK"
},
"detail": "Está dispoñíbel unha nova versión que se pode descarregar de {{downloadLink}}",
"message": "Hai una nova versión dispoñíbel",
"title": "Actualización dispoñíbel"
}
},
"menu": {
"about": "Sobre",
"navigation": {
"label": "Navegación",
"submenu": {
"copy-current-url": "Copiar o URL actual",
"go-back": "Atrás",
"go-forward": "Adiante",
"quit": "Saír",
"restart": "Reiniciar a aplicación"
}
},
"options": {
"label": "Opcións",
"submenu": {
"advanced-options": {
"label": "Opcións avanzadas",
"submenu": {
"auto-reset-app-cache": "Reiniciar a caché cando a aplicación arrinque",
"disable-hardware-acceleration": "Desactivar a aceleración hardware",
"edit-config-json": "Editar config.json",
"override-user-agent": "Substituír o User-Agent",
"restart-on-config-changes": "Reiniciar ao alterar a configuración",
"set-proxy": {
"label": "Configurar o proxy",
"prompt": {
"label": "Introducir o enderezo do proxy (deixar baleiro para desactivalo)",
"placeholder": "Exemplo: SOCKS5://127.0.0.1:9999",
"title": "Configurar o proxy"
}
},
"toggle-dev-tools": "Activar ou desactivar as DevTools"
}
},
"always-on-top": "Sempre en primeiro plano",
"auto-update": "Actualización automática",
"hide-menu": {
"dialog": {
"message": "O menú ocultarase no próximo inicio; use [Alt] para mostralo (ou a tecla [`] se emprega o menú integrado)",
"title": "Ocultar Menú activado"
},
"label": "Ocultar Menú"
},
"language": {
"dialog": {
"message": "A lingua hase mudar despois do reinicio",
"title": "Mudouse a lingua"
},
"label": "Lingua",
"submenu": {
"to-help-translate": "Quere axudar a traducir? Prema aquí"
}
},
"resume-on-start": "Retomar a última canción ao iniciar a aplicación",
"single-instance-lock": "Bloqueo de instancia única",
"start-at-login": "Iniciar co inicio de sesión",
"starting-page": {
"label": "Páxina de inicio",
"unset": "Sen definir"
},
"tray": {
"label": "Bandexa",
"submenu": {
"disabled": "Desactivado",
"enabled-and-hide-app": "Activado e ocultar a aplicación",
"enabled-and-show-app": "Activado e mostrar a aplicación",
"play-pause-on-click": "Reproducir/Pausar ao premer"
}
},
"visual-tweaks": {
"label": "Axustes visuais",
"submenu": {
"custom-window-title": {
"label": "Título de xanela personalizado",
"prompt": {
"label": "Introduza o título personalizado da xanela (deixe baleiro para desactivala)",
"placeholder": "Exemplo: Pear Desktop"
}
},
"like-buttons": {
"default": "Predeterminado",
"force-show": "Forzar a visualización",
"hide": "Agochar",
"label": "Botóns de Gústame"
},
"remove-upgrade-button": "Retirar o botón de anovación",
"theme": {
"dialog": {
"button": {
"cancel": "Cancelar",
"remove": "Retirar"
},
"remove-theme": "Estás certo que queres retirar o tema personalizado?",
"remove-theme-message": "Isto ha retirar o tema personalizado"
},
"label": "Tema",
"submenu": {
"import-css-file": "Importar arquivo CSS personalizado",
"no-theme": "Sen tema"
}
}
}
}
}
},
"plugins": {
"enabled": "Activado",
"label": "Complementos",
"new": "NOVO"
},
"view": {
"label": "Vista",
"submenu": {
"force-reload": "Forzar recarga",
"reload": "Recargar",
"reset-zoom": "Tamaño real",
"toggle-fullscreen": "Alternar Pantalla Completa",
"zoom-in": "Achegarse",
"zoom-out": "Afastarse"
}
}
},
"tray": {
"next": "Seguinte",
"play-pause": "Reproducir/Pausar",
"previous": "Anterior",
"quit": "Saír"
}
}
}

View File

@ -150,6 +150,11 @@
"visual-tweaks": {
"label": "תיקונים חזותיים",
"submenu": {
"custom-window-title": {
"prompt": {
"placeholder": "לדוגמה: שולחן כתיבה אגסי"
}
},
"like-buttons": {
"default": "ברירת מחדל",
"force-show": "הפעל בכוח",
@ -201,8 +206,8 @@
"restart": "הפעל מחדש",
"show": "הראה חלון",
"tooltip": {
"default": "יוטיוב מיוזיק",
"with-song-info": "יוטיוב מיוזיק: {{artist}} - {{title}}"
"default": "שולחן כתיבה אגסי",
"with-song-info": "שולחן כתיב אגסי: {{יוצר}} - {{כותרת}}"
}
}
},
@ -212,7 +217,7 @@
"name": "הגבר מהירות פרסומת"
},
"adblocker": {
"description": "חסום את כל המודעות והמעקב מחוץ לקופסה",
"description": "חסום את כל המודעות והמעקבים",
"menu": {
"blocker": "חוסם"
},
@ -244,6 +249,7 @@
}
},
"buffer": {
"label": "חוצץ",
"submenu": {
"buffer": "{{buffer}}"
}
@ -380,6 +386,11 @@
},
"templates": {
"title": "פתח בחירת כתוביות"
},
"toast": {
"caption-changed": "תרגום שונה ל {{שפה}}",
"caption-disabled": "תרגום בוטל",
"no-captions": "אין תרגום זמין לשיר הזה"
}
},
"compact-sidebar": {
@ -391,9 +402,11 @@
"menu": {
"advanced": "מתקדם"
},
"name": "התפיידות צלב[בית]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "תתפייד בזמן[מילישניות]",
"fade-scaling": {
"linear": "לינארי",
"logarithmic": "לוגריתמי"

View File

@ -154,7 +154,7 @@
"label": "कस्टम विंडो टाइटल",
"prompt": {
"label": "कस्टम विंडो टाइटल डालें: (डिसएबल करने के लिए खाली छोड़ें)",
"placeholder": "उदाहरण: यूट्यूब संगीत"
"placeholder": "उदाहरण: पियर डेस्कटॉप"
}
},
"like-buttons": {
@ -208,8 +208,8 @@
"restart": "ऐप पुनः प्रारंभ करें",
"show": "ऐप दिखाए",
"tooltip": {
"default": "यूट्यूब म्यूजिक",
"with-song-info": "यूट्यूब म्यूजिक: {{artist}} - {{title}}"
"default": "पियर डेस्कटॉप",
"with-song-info": "पियर डेस्कटॉप: {{artist}} - {{title}}"
}
}
},
@ -426,7 +426,13 @@
"menu": {
"device-selector": "डिवाइस चुनें"
},
"name": "अपनी पसंद का आउटपुट डिवाइस"
"name": "अपनी पसंद का आउटपुट डिवाइस",
"prompt": {
"device-selector": {
"label": "उपयोग किए जाने वाला आउटपुट मीडिया चुने",
"title": "आउटपुट डिवाइस चुनें"
}
}
},
"disable-autoplay": {
"description": "गीत को \"रुके हुए \" मोड में शुरू करता है",
@ -451,7 +457,15 @@
"hide-duration-left": "शेष अवधि छिपाएँ",
"hide-github-button": "GitHub लिंक के बटन को छिपाएँ",
"play-on-pear-desktop": "Pear Desktop म्यूज़िक पर चलाएँ",
"set-inactivity-timeout": "निष्क्रियता समय समाप्ति सेट करें"
"set-inactivity-timeout": "निष्क्रियता समय समाप्ति सेट करें",
"set-status-display-type": {
"label": "स्टेटस टेक्स्ट",
"submenu": {
"artist": "{artist} को सुन रहे है",
"pear-desktop": "Pear Desktop सुन रहे है",
"title": "{song title} सुन रहे है"
}
}
},
"name": "डिस्कॉर्ड रिच प्रेजेंस",
"prompt": {
@ -743,6 +757,7 @@
"listenbrainz": {
"token": "listenbrainz उपयोगकर्ता टोकन दर्ज करें"
},
"scrobble-alternative-artist": "वैकल्पिक आर्टिस्ट का उपयोग करें",
"scrobble-alternative-title": "वैकल्पिक शीर्षक का उपयोग करें",
"scrobble-other-media": "अन्य मीडिया स्क्रोबल करें"
},
@ -788,9 +803,12 @@
"name": "साइलेंस स्किप करें"
},
"sponsorblock": {
"description": "Intro/Outro जैसे गैर-संगीत भागों को स्किप करता है",
"description": "गाने के वीडियो में जहाँ म्यूजिक नहीं चलता, जैसे शुरुआत या अंत के हिस्से, उन्हें अपने आप स्किप कर देता है",
"name": "SponsorBlock"
},
"synced-lyrics": {
"description": "LRClib जैसे सोर्सेज के उपयोग से, गानों के लिए सिंक किए गए लिरिक्स देता है।"
},
"video-toggle": {
"menu": {
"align": {

View File

@ -2,7 +2,7 @@
"common": {
"console": {
"plugins": {
"execute-failed": "პლაგინის დაყენების შეცდომა {{pluginName}}::{{contextName}}",
"execute-failed": "დამატების შესრულების შეცდომა {{pluginName}}::{{contextName}}",
"executed-at-ms": "პლაგინი {{pluginName}}::{{contextName}} გაეშვა {{ms}} მილიწამში",
"initialize-failed": "პლაგინის ინიციალიზაცია ვერ მოხდა\"{{pluginName}}\"",
"load-all": "იტვირთება ყველა პლაგინი",
@ -37,9 +37,15 @@
},
"when-ready": {
"clearing-cache-after-20s": "აპლიკაციის ქეშის გაწმენდვა"
},
"window": {
"tried-to-render-offscreen": "ფანჯარამ სცადა, ეკრანსმიღმა გახსნილიყო, ფანჯრის ზომა={{windowSize}}, ეკრანის ზომა={{displaySize}}, მდებარეობა={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "მენიუ დამალულია, გამოიყენეთ 'Alt', რათა გამოაჩინოთ ის (ან 'Escape' თუ იყენებთ აპლიკაციის შიგნითა მენიუს)"
},
"need-to-restart": {
"buttons": {
"later": "მოგვიანებით"

View File

@ -208,8 +208,8 @@
"restart": "앱 재시작",
"show": "창 표시",
"tooltip": {
"default": "유튜브 뮤직",
"with-song-info": "유튜브 뮤직: {{artist}} - {{title}}"
"default": "피어 데스크톱",
"with-song-info": "피어 데스크톱: {{artist}} - {{title}}"
}
}
},
@ -237,7 +237,8 @@
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"enable-seekbar": "재생바 색조 변경 활성화"
},
"name": "앨범 컬러 기반 테마"
},
@ -369,7 +370,7 @@
"name": "탐색 바 흐림 효과"
},
"bypass-age-restrictions": {
"description": "유튜브의 나이 제한을 우회합니다",
"description": "음악 플레이어의 연령 확인 우회합니다",
"name": "나이 제한 우회"
},
"captions-selector": {

View File

@ -53,7 +53,7 @@
"later": "Nanti",
"restart-now": "Restart Sekarang"
},
"detail": "Plugin {{pluginName}} perlu dimulakan semula untuk berkuatkuasa",
"detail": "\"{{pluginName}}\" plugin memerlukan mula semula untuk ambil keberkesanan",
"message": "\"{{pluginName}}\" perlu dimulakan semula",
"title": "Mulakan Semula Diperlukan"
},
@ -74,7 +74,7 @@
"ok": "OK"
},
"detail": "Versi baharu kini tersedia dan boleh dimuat turun di {{downloadLink}}",
"message": "Versi baharu tersedia",
"message": "Versi baharu kini tersedia",
"title": "Kemas Kini Tersedia"
}
},
@ -462,8 +462,8 @@
"label": "Teks status",
"submenu": {
"artist": "Sedang mendengar {artist}",
"title": "Sedang mendengar {tajuk lagu}",
"pear-desktop": "Mendengar Pear Desktop"
"pear-desktop": "Mendengar Pear Desktop",
"title": "Sedang mendengar {tajuk lagu}"
}
}
},
@ -499,7 +499,7 @@
"converting": "Menukarkan…",
"done": "Selesai: {{filePath}}",
"download-info": "Memuat turun {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Muat turun: {{peratus}}%",
"download-progress": "Muat turun: {{percent}}%",
"downloading": "Memuat turun…",
"downloading-counter": "Memuat turun {{current}}/{{total}}…",
"downloading-playlist": "Memuat turun senarai main \"{{playlistTitle}}\" - {{playlistSize}} lagu ({{playlistId}})",
@ -510,7 +510,7 @@
"playlist-has-only-one-song": "Senarai main hanya mempunyai satu item, memuat turunnya terus",
"playlist-id-not-found": "ID senarai main tidak dijumpai",
"playlist-is-empty": "Senarai main kosong",
"playlist-is-mix-or-private": "Ralat dalam mendapatkan senarai info main: pastikan ia tidak peribadi atau di dalam senarai main \"Campuran untuk anda\"\n\n{{ralat}}",
"playlist-is-mix-or-private": "Ralat dalam mendapatkan senarai info main: pastikan ia tidak peribadi atau di dalam senarai main \"Campuran untuk anda\"\n\n{{error}}",
"preparing-file": "Menyediakan fail…",
"saving": "Menyimpan…",
"trying-to-get-playlist-id": "Mencuba untuk mendapatkan ID senarai main: {{playlistId}}",
@ -622,7 +622,31 @@
"id-copy-failed": "Gagal menyalin ID Hos ke papan keratan"
}
},
"navigation": {
"name": "Navigasi"
},
"notifications": {
"name": "Notifikasi"
},
"scrobbler": {
"dialog": {
"lastfm": {
"auth-failed": {
"title": "Atuntikasi Gagal"
}
}
},
"prompt": {
"lastfm": {
"api-key": "kunci API Last.fm",
"api-secret": "rahasia API Last.fm"
}
}
},
"synced-lyrics": {
"errors": {
"not-found": "⚠️ Tak ada liriks untuk lagu ini."
},
"menu": {
"show-lyrics-even-if-inexact": {
"label": "Tunjukkan lirik walaupun tidak tepat",

View File

@ -33,25 +33,25 @@
"css-file-not-found": "Arquivo CSS \"{{cssFile}}\" não existe, ignorando"
},
"unresponsive": {
"details": "Erro de falta de resposta!\n{{error}}"
"details": "Erro por falta de resposta!\n{{error}}"
},
"when-ready": {
"clearing-cache-after-20s": "Limpando cache do aplicativo"
},
"window": {
"tried-to-render-offscreen": "A janela tentou renderizar fora da tela, tamanho da janela={{windowSize}}, tamanho da tela={{displaySize}}, posição={{position}}"
"tried-to-render-offscreen": "A janela tentou renderizar fora dos parâmetros da tela, tamanho da janela={{windowSize}}, tamanho da tela={{displaySize}}, posição={{position}}"
}
},
"dialog": {
"hide-menu-enabled": {
"detail": "O menu está oculto, use 'Alt' para mostrá-lo (ou 'Esc' ao usar o menu dentro do aplicativo)",
"message": "Ocultar menu está ativado",
"title": "Ocultar menu ativado"
"message": "Ocultar Menu está ativado",
"title": "Ocultar Menu ativado"
},
"need-to-restart": {
"buttons": {
"later": "Depois",
"restart-now": "Reiniciar agora"
"restart-now": "Reiniciar Agora"
},
"detail": "O plugin \"{{pluginName}}\" requer uma reinicialização para entrar em vigor",
"message": "\"{{pluginName}}\" precisa reiniciar",
@ -84,7 +84,7 @@
"label": "Navegação",
"submenu": {
"copy-current-url": "Copiar URL atual",
"go-back": "Voltar",
"go-back": "Retornar",
"go-forward": "Avançar",
"quit": "Sair",
"restart": "Reiniciar aplicativo"
@ -462,8 +462,8 @@
"label": "Texto de status",
"submenu": {
"artist": "Ouvindo {artist}",
"title": "Ouvindo {song title}",
"pear-desktop": "Ouvindo Pear Desktop"
"pear-desktop": "Ouvindo Pear Desktop",
"title": "Ouvindo {song title}"
}
}
},

View File

@ -59,7 +59,7 @@
},
"unresponsive": {
"buttons": {
"quit": "Skončiť",
"quit": "Ukončiť",
"relaunch": "Spustiť znova",
"wait": "Počkajte"
},
@ -70,7 +70,7 @@
"update-available": {
"buttons": {
"disable": "Vypnúť aktualizácie",
"download": "Sťiahnuť",
"download": "Stiahnuť",
"ok": "OK"
},
"detail": "Nová verzia je k dispozícii a je možné ju stiahnuť na {{downloadLink}}",
@ -141,9 +141,9 @@
"tray": {
"label": "Panel oznámení",
"submenu": {
"disabled": "Vypnuý",
"enabled-and-hide-app": "Zapnutý , a skryť okno aplikácie",
"enabled-and-show-app": "Spustené a ukáž aplikáciu",
"disabled": "Vypnutý",
"enabled-and-hide-app": "Povolené a skry aplikáciu",
"enabled-and-show-app": "Povolené a ukáž aplikáciu",
"play-pause-on-click": "Prehrať/Pozastaviť na stlačenie"
}
},
@ -185,11 +185,13 @@
},
"plugins": {
"enabled": "Zapnuté",
"label": "Rozšírenia",
"new": "NOVÝ"
},
"view": {
"label": "Náhľad",
"submenu": {
"force-reload": "Natvrdo obnoviť",
"force-reload": "Nasilu obnoviť",
"reload": "Obnoviť",
"reset-zoom": "Ozajstná veľkosť",
"toggle-fullscreen": "Prepnúť režim Celej Obrazovky",
@ -210,5 +212,660 @@
"with-song-info": "Pear Desktop: {{artist}} - {{title}}"
}
}
},
"plugins": {
"ad-speedup": {
"description": "Ak sa spustí reklama, stlmí sa zvuk a nastaví sa rýchlosť prehrávania na 16x",
"name": "Zrýchľovač reklám"
},
"adblocker": {
"description": "Blokovať všetky reklamy a sledovania hneď od začiatku",
"menu": {
"blocker": "Blokovač"
},
"name": "Blokovač reklám"
},
"album-actions": {
"description": "Pridáva Undislike, Dislike, Like, a Unlike tlačítka k aplikovaniu tohto ku všetkým pesničkám v zozname pesničiek alebo albume",
"name": "Možnosti albumu"
},
"album-color-theme": {
"description": "Aplikuje dynamický motív a vizuálne efekty na základe palety farieb albumu",
"menu": {
"color-mix-ratio": {
"label": "Pomer miešania farieb",
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"name": "Farebná téma albumu"
},
"ambient-mode": {
"description": "Aplikuje svetelné efekty pomocou vrhania jemných farieb z videa, do vášho pozadia obrazovky",
"menu": {
"blur-amount": {
"label": "Hodnota rozmazania",
"submenu": {
"pixels": "{{blurAmount}} pixelov"
}
},
"buffer": {
"label": "Vyrovnávacia pamäť",
"submenu": {
"buffer": "{{buffer}}"
}
},
"opacity": {
"label": "Nepriehľadnosť",
"submenu": {
"percent": "{{opacity}}%"
}
},
"quality": {
"label": "Kvalita",
"submenu": {
"pixels": "{{quality}} pixelov"
}
},
"size": {
"label": "Veľkosť",
"submenu": {
"percent": "{{size}}%"
}
},
"smoothness-transition": {
"label": "Plynulý prechod",
"submenu": {
"during": "Počas {{interpolationTime}} s"
}
},
"use-fullscreen": {
"label": "Používanie režimu celej obrazovky"
}
},
"name": "Ambientný mód"
},
"amuse": {
"description": "Pridáva Pear Desktop podporu pre Amuse práve prehráva widget od 6K Labs",
"name": "Amuse",
"response": {
"query": "Amuse API server beží. GET /query to get song info."
}
},
"api-server": {
"description": "Pridáva API server na ovládanie prehrávača",
"dialog": {
"request": {
"buttons": {
"allow": "Povoliť",
"deny": "Zakázať"
},
"message": "Povoliť {{ID}} ({{origin}}) prístup cez API?",
"title": "Žiadosť o autorizáciu API"
}
},
"menu": {
"auth-strategy": {
"label": "Stratégia autorizácie",
"submenu": {
"auth-at-first": {
"label": "Overiť pri prvom dotaze"
},
"none": {
"label": "Žiadna autorizácia"
}
}
},
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
}
},
"name": "API Server [Beta]",
"prompt": {
"hostname": {
"label": "Zadajte názov hostname(napr. 0.0.0.0) pre server API:",
"title": "Hostname"
},
"port": {
"label": "Zadajte port pre server API:",
"title": "Port"
}
}
},
"audio-compressor": {
"description": "Aplikovať kompresiu k audiu (znižuje hlasitosť najhlasnejších častí signálu a zvyšuje hlasitosť najjemnejších častí)",
"name": "Audio kompresor"
},
"auth-proxy-adapter": {
"description": "Podpora používania autentifikačných proxy služieb",
"menu": {
"disable": "Vypnúť Proxy Adaptér",
"enable": "Zapnúť Proxy Adaptér",
"hostname": {
"label": "Hostname"
},
"port": {
"label": "Port"
}
},
"name": "Adaptér autentifikačného proxy servera",
"prompt": {
"hostname": {
"label": "Zadajte hostname pre lokálny proxy server (vyžaduje reštart):",
"title": "Proxy Hostname"
},
"port": {
"label": "Zadajte port pre lokálny proxy server (vyžaduje reštart):",
"title": "Proxy Port"
}
}
},
"blur-nav-bar": {
"description": "Navigačnú lištu nastaví ako priehľadnú a rozmazanú",
"name": "Rozmazať navigačnú lištu"
},
"bypass-age-restrictions": {
"description": "Obísť overenie veku v hudobnom prehrávači",
"name": "Obísť vekové obmedzenia"
},
"captions-selector": {
"description": "Selektor titulkov pre zvukové stopy Pear Desktop",
"menu": {
"autoload": "Automatický výber naposledy použitých titulkov",
"disable-captions": "Žiadne titulky"
},
"name": "Selektor titulkov",
"prompt": {
"selector": {
"label": "Aktuálny jazyk titulkov: {{language}}",
"none": "Žiadne",
"title": "Výber jazyka titulkov"
}
},
"templates": {
"title": "Otvoriť selektor titulkov"
},
"toast": {
"caption-changed": "Titulky zmenené na {{language}}",
"caption-disabled": "Deaktivované titulky",
"no-captions": "Pre túto skladbu nie sú dostupné žiadne titulky"
}
},
"compact-sidebar": {
"description": "Vždy nastaviť bočný panel do kompaktného režimu",
"name": "Kompaktný bočný panel"
},
"crossfade": {
"description": "Prelínanie medzi skladbami",
"menu": {
"advanced": "Pokročilé"
},
"name": "Prelínanie [Beta]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "Trvanie nábehu (ms)",
"fade-out-duration": "Trvanie doznievania (ms)",
"fade-scaling": {
"label": "Škálovanie prelínania",
"linear": "Lineárny",
"logarithmic": "Logaritmický"
},
"seconds-before-end": "Prechod N sekúnd pred koncom"
},
"title": "Možnosti prelínania"
}
}
},
"custom-output-device": {
"description": "Nastavte vlastné výstupné médium pre skladby",
"menu": {
"device-selector": "Výber Zariadenia"
},
"name": "Vlastné výstupné zariadenie",
"prompt": {
"device-selector": {
"label": "Vyberte výstupné médium, ktoré chcete použiť",
"title": "Výber výstupného zariadenia"
}
}
},
"disable-autoplay": {
"description": "Spustí skladbu v režime „pozastavené“",
"menu": {
"apply-once": "Platí len pri spustení"
},
"name": "Zakázať automatické prehrávanie"
},
"discord": {
"backend": {
"already-connected": "Pokus o pripojenie s aktívnym pripojením",
"connected": "Pripojené k Discordu",
"disconnected": "Odpojené od Discordu"
},
"description": "Ukážte svojim priateľom, čo počúvate, s funkciou Rich Presence",
"menu": {
"auto-reconnect": "Automatické opätovné pripojenie",
"clear-activity": "Zmazať aktivitu",
"clear-activity-after-timeout": "Zmazať aktivitu po uplynutí časového limitu",
"connected": "Pripojené",
"disconnected": "Odpojené",
"hide-duration-left": "Skryť zostávajúcu dobu trvania",
"hide-github-button": "Skryť tlačidlo s odkazom na GitHub",
"play-on-pear-desktop": "Spustiť na Pear Desktop",
"set-inactivity-timeout": "Nastaviť časový limit nečinnosti",
"set-status-display-type": {
"label": "Text stavu",
"submenu": {
"artist": "Aktuálne si prehráva {artist}",
"pear-desktop": "Počúvať Pear Desktop",
"title": "Aktuálne si prehráva {song title}"
}
}
},
"name": "Discord Rich Presence",
"prompt": {
"set-inactivity-timeout": {
"label": "Zadajte časový limit nečinnosti v sekundách:",
"title": "Nastaviť časový limit nečinnosti"
}
}
},
"downloader": {
"backend": {
"dialog": {
"error": {
"buttons": {
"ok": "OK"
},
"message": "Ach! Ospravedlňujeme sa, sťahovanie sa nepodarilo…",
"title": "Chyba pri sťahovaní!"
},
"start-download-playlist": {
"buttons": {
"ok": "OK"
},
"detail": "({{playlistSize}} skladieb)",
"message": "Sťahovanie zoznamu {{playlistTitle}}",
"title": "Sťahovanie začalo"
}
},
"feedback": {
"conversion-progress": "Konverzia: {{percent}}%",
"converting": "Konvertujem…",
"done": "Hotovo: {{filePath}}",
"download-info": "Sťahujem {{artist}} - {{title}} [{{videoId}}",
"download-progress": "Sťahovanie: {{percent}}%",
"downloading": "Sťahujem…",
"downloading-counter": "Sťahujem {{current}}/{{total}}…",
"downloading-playlist": "Sťahujem zoznam „{{playlistTitle}}“ - {{playlistSize}} skladieb ({{playlistId}})",
"error-while-downloading": "Chyba pri sťahovaní „{{author}} - {{title}}“: {{error}}",
"folder-already-exists": "Priečinok {{playlistFolder}} už existuje",
"getting-playlist-info": "Získavanie informácií o zozname…",
"loading": "Načítavam…",
"playlist-has-only-one-song": "Zoznam obsahuje len jednu položku, ktorá sa stiahne priamo",
"playlist-id-not-found": "Nebolo nájdené žiadne ID zoznamu",
"playlist-is-empty": "Zoznam je prázdny",
"playlist-is-mix-or-private": "Chyba pri získavaní informácií o zozname: uistite sa, že nejde o súkromný zoznam alebo zoznam „Pre Vás“\n\n{{error}}",
"preparing-file": "Pripravujem súbor…",
"saving": "Ukladám…",
"trying-to-get-playlist-id": "Snažím sa získať ID zoznam: {{playlistId}}",
"video-id-not-found": "Video nebolo nájdené",
"writing-id3": "Zapisujem ID3 značky…"
}
},
"description": "Sťahuje MP3 / zdrojový zvuk priamo z rozhrania",
"menu": {
"choose-download-folder": "Vyberte priečinok na sťahovanie",
"download-finish-settings": {
"label": "Stiahnuť po skončení",
"prompt": {
"last-percent": "Po x percentách",
"last-seconds": "Posledných x sekúnd",
"title": "Nastavte, kedy sa má stiahnuť"
},
"submenu": {
"advanced": "Rozšírené",
"enabled": "Povolené",
"mode": "Časový režim",
"percent": "Percento",
"seconds": "Sekundy"
}
},
"download-playlist": "Stiahnuť zoznam",
"presets": "Predvoľby",
"skip-existing": "Preskočiť už existujúce súbory"
},
"name": "Sťahovač",
"renderer": {
"can-not-update-progress": "Nie je možné aktualizovať priebeh"
},
"templates": {
"button": "Stiahnuť"
}
},
"equalizer": {
"description": "Pridáva ekvalizér do prehrávača",
"menu": {
"presets": {
"label": "Predvoľby",
"list": {
"bass-booster": "Zosilňovač basov"
}
}
},
"name": "Ekvalizér"
},
"exponential-volume": {
"description": "Zmení slider hlasitosti na exponenciálny, aby bolo ľahšie vybrať nižšiu hlasitosť.",
"name": "Exponenciálna hlasitosť"
},
"in-app-menu": {
"description": "Dodáva lištám ponúk elegantný, tmavý alebo farebný vzhľad albumu",
"menu": {
"hide-dom-window-controls": "Skryť ovládacie prvky DOM"
},
"name": "Aplikačné menu"
},
"lumiastream": {
"description": "Pridáva Lumia Stream podporu",
"name": "Lumia Stream [Beta]"
},
"lyrics-genius": {
"description": "Pridáva podporu textov pre väčšinu piesní",
"menu": {
"romanized-lyrics": "Romanizované texty piesní"
},
"name": "Texty Genius",
"renderer": {
"fetched-lyrics": "Načítané texty piesní pre Genius"
}
},
"music-together": {
"description": "Zdieľajte zoznam s ostatnými. Keď hostiteľ prehrá skladbu, všetci ostatní budú počuť tú istú skladbu",
"dialog": {
"enter-host": "Zadajte Host ID"
},
"internal": {
"save": "Uložiť",
"track-source": "Sledovať zdroj",
"unknown-user": "Neznámy užívateľ"
},
"menu": {
"click-to-copy-id": "Kopírovať Host ID",
"close": "Zatvoriť Music Together",
"connected-users": "Pripojení užívatelia",
"disconnect": "Odpojiť Music Together",
"empty-user": "Žiadni pripojení užívatelia",
"host": "Music Together Host",
"join": "Pripojiť sa k Music Together",
"permission": {
"all": "Umožniť hosťom ovládať zoznam a prehrávač",
"host-only": "Len hostiteľ môže ovládať zoznam skladieb a prehrávač",
"playlist": "Umožniť hosťom ovládať zoznam"
},
"set-permission": "Povolenie na kontrolu zmien",
"status": {
"disconnected": "Odpojené",
"guest": "Pripojený ako hosť",
"host": "Pripojený ako hostiteľ"
}
},
"name": "Music Together [Beta]",
"toast": {
"add-song-failed": "Nepodarilo sa pridať skladbu",
"closed": "Music Together ukončené",
"disconnected": "Music Together odpojené",
"host-failed": "Nepodarilo sa hosťovať Music Together",
"id-copied": "Host ID bolo skopírované do schránky",
"id-copy-failed": "Nepodarilo sa skopírovať Host ID do schránky",
"join-failed": "Nepodarilo sa pripojiť k Music Together",
"joined": "Pripojený k Music Together",
"permission-changed": "Povolenie Music Together zmenené na „{{permission}}“",
"remove-song-failed": "Nepodarilo sa odstrániť skladbu",
"user-connected": "{{name}} sa pripojil k Music Together",
"user-disconnected": "{{name}} opustil Music Together"
}
},
"navigation": {
"description": "Šípky pre navigáciu vpred/vzad sú priamo integrované do rozhrania, rovnako ako vo vašom obľúbenom prehliadači",
"name": "Navigácia",
"templates": {
"back": {
"title": "Prejsť na predchádzajúcu stránku"
},
"forward": {
"title": "Prejsť na nasledujúcu stránku"
}
}
},
"no-google-login": {
"description": "Odstrániť tlačidlá a odkazy na prihlásenie do služby Google z rozhrania",
"name": "Žiadne prihlásenie do Google"
},
"notifications": {
"description": "Zobraziť upozornenie pri spustení prehrávania skladby (interaktívne upozornenia sú k dispozícii v systéme Windows)",
"menu": {
"interactive": "Interaktívne oznámenia",
"interactive-settings": {
"label": "Interaktívne nastavenia",
"submenu": {
"hide-button-text": "Skryť text tlačidla",
"refresh-on-play-pause": "Obnoviť pri prehrávaní/pozastavení",
"tray-controls": "Otvoriť/Zatvoriť kliknutím na lištu"
}
},
"priority": "Priorita oznámenia",
"toast-style": "Štýl toastu",
"unpause-notification": "Zobraziť upozornenie pri obnovení"
},
"name": "Upozornenia"
},
"performance-improvement": {
"description": "Zlepšite výkon povolením experimentálnych skriptov",
"name": "Zlepšenie výkonu [Beta]"
},
"picture-in-picture": {
"description": "Umožňuje prepnúť aplikáciu do režimu obraz v obraze",
"menu": {
"always-on-top": "Vždy na vrchu",
"hotkey": {
"label": "Klávesová skratka",
"prompt": {
"keybind-options": {
"hotkey": "Klávesová skratka"
},
"label": "Vyberte klávesovú skratku pre prepínanie obraz v obraze",
"title": "Obraz v obraze klávesová skratka"
}
},
"save-window-position": "Uložiť pozíciu okna",
"save-window-size": "Uložiť veľkosť okna",
"use-native-pip": "Použiť natívne PiP prehliadača"
},
"name": "Obraz v obraze",
"templates": {
"button": "Obraz v obraze"
}
},
"playback-speed": {
"description": "Počúvajte rýchlo, počúvajte pomaly! Pridáva slider, ktorý ovláda rýchlosť skladby",
"name": "Rýchlosť prehrávania",
"templates": {
"button": "Rýchlosť"
}
},
"precise-volume": {
"description": "Presne ovládajte hlasitosť pomocou kolieska myši/klávesových skratiek, s vlastným HUD a prispôsobiteľnými krokmi hlasitosti",
"menu": {
"arrows-shortcuts": "Ovládanie pomocou šípok",
"custom-volume-steps": "Nastavenie vlastných krokov hlasitosti",
"global-shortcuts": "Globálne klávesové skratky"
},
"name": "Presná hlasitosť",
"prompt": {
"global-shortcuts": {
"keybind-options": {
"decrease": "Znížiť hlasitosť",
"increase": "Zvýšiť hlasitosť"
},
"label": "Vybrať globálne klávesové skratky:",
"title": "Globálne klávesové skratky pre hlasitosť"
},
"volume-steps": {
"label": "Vybrať kroky zvýšenia/zníženia hlasitosti",
"title": "Kroky hlasitosti"
}
}
},
"quality-changer": {
"backend": {
"dialog": {
"quality-changer": {
"detail": "Aktuálna kvalita: {{quality}}",
"message": "Výber kvality videa:",
"title": "Výber kvality videa"
}
}
},
"description": "Umožňuje zmeniť kvalitu videa pomocou tlačidla v prekrytí videa",
"name": "Zmena kvality videa",
"renderer": {
"quality-settings-button": {
"label": "Otvoriť nastavenia kvality prehrávača"
}
}
},
"scrobbler": {
"description": "Pridať podporu scrobbling (napr. last.fm, Listenbrainz)",
"dialog": {
"lastfm": {
"auth-failed": {
"message": "Nepodarilo sa autentifikovať s Last.fm\nSkryť vyskakovacie okno do ďalšieho reštartu.",
"title": "Autentifikácia zlyhala"
}
}
},
"menu": {
"lastfm": {
"api-settings": "Last.fm API Nastavenia"
},
"listenbrainz": {
"token": "Vložiť ListenBrainz používateľský token"
},
"scrobble-alternative-artist": "Použiť alternatívnych umelcov",
"scrobble-alternative-title": "Použiť alternatívne názvy",
"scrobble-other-media": "Scrobble iných médií"
},
"name": "Scrobbler",
"prompt": {
"lastfm": {
"api-key": "Last.fm API kľúč",
"api-secret": "Last.fm API tajomstvo"
},
"listenbrainz": {
"token": {
"label": "Vlož svoj ListenBrainz používateľský token:",
"title": "ListenBrainz token"
}
}
}
},
"shortcuts": {
"description": "Povoľuje nastaviť globálne klávesové skratky pre prehrávanie (Prehrať/Pozastaviť/Ďalšie/Predošlé) a vypínať media OSD prepisovaním media kľúčov, zapne Ctrl/CMD + F pre vyhľadávanie, zapne Linux MPRIS podporu pre media kľúče a vlastné klávesové skratky pre pokročilých používateľov.",
"menu": {
"override-media-keys": "Prepísať Media Kľúče",
"set-keybinds": "Globálne ovládanie skladieb"
},
"name": "Skratky (& MPRIS)",
"prompt": {
"keybind": {
"keybind-options": {
"next": "Ďalšia",
"play-pause": "Prehrať / Pauza",
"previous": "Predošlá"
},
"label": "Zvoliť globálne klávesové skratky na ovládanie skladieb:",
"title": "Globálne klávesové skratky"
}
}
},
"skip-disliked-songs": {
"description": "Preskakuje skladby označené Nepáči sa",
"name": "Preskakovať skladby označené Nepáči sa"
},
"skip-silences": {
"description": "Automaticky preskakovať tiché časti v hudbe",
"name": "Preskakuj tiché časti"
},
"sponsorblock": {
"description": "Automaticky preskakuje nehudbné časti ako intro/outro, alebo tie časti videoklipov v ktorých nehrá hudba",
"name": "Sponzorský blok"
},
"synced-lyrics": {
"description": "Poskytuje synchronizované texty k skladbám, pričom používa poskytovateľov ako LRClib.",
"errors": {
"fetch": "⚠️\t\tPri získavaní textu sa vyskytla chyba. \n\tSkúste znova neskôr.",
"not-found": "⚠Pre túto skladbu nebol nájdený žiadny text."
},
"menu": {
"line-effect": {
"submenu": {
"offset": {
"label": "Offset"
}
}
},
"precise-timing": {
"label": "Dokonale synchronizovať text piesne"
},
"preferred-provider": {
"label": "Preferovaný Poskytovateľ",
"none": {
"label": "Žiadne",
"tooltip": "Žiadny preferovaný poskytovateľ"
}
}
}
},
"touchbar": {
"name": "Dotykový Panel"
},
"transparent-player": {
"description": "Nastaví okno aplikácie ako priehľadné"
},
"video-toggle": {
"menu": {
"align": {
"submenu": {
"left": "Vľavo",
"middle": "Stred",
"right": "Vpravo"
}
},
"mode": {
"submenu": {
"disabled": "Vypnuté",
"native": "Natívny prepínač"
}
}
},
"name": "Prepínač Videa",
"templates": {
"button-song": "Skladba",
"button-video": "Video"
}
},
"visualizer": {
"description": "Pridá do prehrávača vizualizér",
"menu": {
"visualizer-type": "Typ Vizualizéra"
},
"name": "Vizualizér"
}
}
}

View File

@ -388,6 +388,11 @@
},
"templates": {
"title": "Відкрити селектор субтитрів"
},
"toast": {
"caption-changed": "Субтитри змінені на {{language}}",
"caption-disabled": "Субтитри відключені",
"no-captions": "Субтитри не доступні для цієї пісні"
}
},
"compact-sidebar": {
@ -456,7 +461,9 @@
"set-status-display-type": {
"label": "Статус",
"submenu": {
"pear-desktop": "Відтворення з Pear Desktop"
"artist": "Ви слухаєте {artist}",
"pear-desktop": "Відтворення з Pear Desktop",
"title": "Ви слухаєте {song title}"
}
}
},
@ -626,7 +633,15 @@
},
"navigation": {
"description": "Стрілки навігації Вперед/Назад безпосередньо інтегровані в інтерфейс, як у вашому браузері, який ви використовуєте",
"name": "Навігація"
"name": "Навігація",
"templates": {
"back": {
"title": "Перейти на минулу сторінку"
},
"forward": {
"title": "Перейти на наступну сторінку"
}
}
},
"no-google-login": {
"description": "Видалити кнопки та посилання для входу через Google з інтерфейсу",
@ -718,7 +733,12 @@
}
},
"description": "Дозволяє змінювати якість відео за допомогою кнопки на відео оверлеї",
"name": "Зміна якості відео"
"name": "Зміна якості відео",
"renderer": {
"quality-settings-button": {
"label": "Відкрити налаштування якості плеєру"
}
}
},
"scrobbler": {
"description": "Додає підтримку скроблінгу (last.fm, Listenbrainz тощо)",
@ -737,6 +757,7 @@
"listenbrainz": {
"token": "Ввести токен користувача ListenBrainz"
},
"scrobble-alternative-artist": "Використати іншого виконавця",
"scrobble-alternative-title": "Використовувати альтернативні назви",
"scrobble-other-media": "Скробилити інші медіа"
},
@ -788,7 +809,7 @@
"synced-lyrics": {
"description": "Додає синхронізовані тексти до пісень використовуючи провайдери, такі як LRClib.",
"errors": {
"fetch": "⚠️ - При завантаженні слів пісні сталась помилка. Спробуйте пізніше.",
"fetch": "⚠️ - При завантаженні слів пісні сталась помилка.\nСпробуйте будь ласка пізніше.",
"not-found": "⚠️ До цієї пісні текст не знайдено."
},
"menu": {
@ -822,6 +843,14 @@
"label": "Зробити текст пісні ідеально синхронізованим",
"tooltip": "Обчисли до мілісекунд відображення наступного рядка (може мати невеликий вплив на продуктивність)"
},
"preferred-provider": {
"label": "Пріорітетний Провайдер",
"none": {
"label": "Жоден",
"tooltip": "Нема провайдера за замовчуванням"
},
"tooltip": "Оберіть якого провайдера використовувати за замовчуванням"
},
"romanization": {
"label": "Транслітерувати текст пісень",
"tooltip": "Якщо текст пісні іншою мовою, спробувати його відобразити латинською версією."
@ -854,6 +883,27 @@
"description": "Додає віджет TouchBar для користувачів macOS",
"name": "TouchBar"
},
"transparent-player": {
"description": "Зробити вікно програми прозорим",
"menu": {
"opacity": {
"label": "Прозорість",
"submenu": {
"percent": "{{opacity}}%"
}
},
"type": {
"label": "Тип",
"submenu": {
"acrylic": "Акриловий",
"mica": "Міка",
"none": "Жоден",
"tabbed": "З роздільниками"
}
}
},
"name": "Прозорий Плеєр"
},
"tuna-obs": {
"description": "Інтеграція з плагіном Tuna для OBS",
"name": "Tuna OBS"
@ -885,7 +935,8 @@
},
"name": "Перемикач відео",
"templates": {
"button-song": "Пісня"
"button-song": "Пісня",
"button-video": "Відео"
}
},
"visualizer": {

View File

@ -150,6 +150,13 @@
"visual-tweaks": {
"label": "بصری تبدیلیاں",
"submenu": {
"custom-window-title": {
"label": "اپنی مرضی کا ونڈو عنوان",
"prompt": {
"label": "اپنی مرضی کا ونڈو عنوان درج کریں: (بند کرنے کے لیے خالی چھوڑ دیں)",
"placeholder": "مثال: پیئر ڈیسک ٹاپ"
}
},
"like-buttons": {
"default": "پہلے سے طے شدہ",
"force-show": "زبردستی دکھائیں",
@ -198,7 +205,24 @@
"play-pause": "چلائیں/روکیں",
"previous": "پچھلا",
"quit": "باہر نکلیں",
"restart": "ایپ دوبارہ شروع کریں"
"restart": "ایپ دوبارہ شروع کریں",
"show": "ونڈو دکھائیں",
"tooltip": {
"default": "پیئر ڈیسک ٹاپ"
}
}
},
"plugins": {
"ad-speedup": {
"description": "اگر کوئی اشتہار چلے تو آواز بند کرکے پلے بیک کی رفتار 16 گناہ کردیں",
"name": "اشتہار کی رفتار"
},
"adblocker": {
"description": "شروغ سے تمام اشتہارات اور ٹریکنگ بلاک کردیں",
"menu": {
"blocker": "بلاکر"
},
"name": "ایڈ بلاکر"
}
}
}

View File

@ -237,7 +237,8 @@
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"enable-seekbar": "启用进度条主题"
},
"name": "专辑配色主题"
},
@ -462,8 +463,8 @@
"label": "状态文本",
"submenu": {
"artist": "在听 {artist}",
"title": "在听 {song title}",
"pear-desktop": "在听 Pear Desktop"
"pear-desktop": "在听 Pear Desktop",
"title": "在听 {song title}"
}
}
},

View File

@ -369,7 +369,7 @@
"name": "模糊導覽列"
},
"bypass-age-restrictions": {
"description": "繞過 Music Player 年齡驗證",
"description": "繞過年齡驗證",
"name": "繞過年齡驗證"
},
"captions-selector": {
@ -462,8 +462,8 @@
"label": "狀態樣式",
"submenu": {
"artist": "正在聆聽 {artist} 的歌曲",
"title": "正在聆聽 {song title}",
"pear-desktop": "正在聆聽 Pear Desktop"
"pear-desktop": "正在聆聽 Pear Desktop",
"title": "正在聆聽 {song title}"
}
}
},

View File

@ -10,41 +10,32 @@ const COLOR_KEY = '--ytmusic-album-color';
const DARK_COLOR_KEY = '--ytmusic-album-color-dark';
const RATIO_KEY = '--ytmusic-album-color-ratio';
export default createPlugin<
unknown,
unknown,
{
color?: ColorInstance;
darkColor?: ColorInstance;
type Config = {
enabled: boolean;
ratio: number;
enableSeekbar: boolean;
};
playerPage: HTMLElement | null;
navBarBackground: HTMLElement | null;
ytmusicPlayerBar: HTMLElement | null;
playerBarBackground: HTMLElement | null;
sidebarBig: HTMLElement | null;
sidebarSmall: HTMLElement | null;
ytmusicAppLayout: HTMLElement | null;
type Renderer = {
getMixedColor(
color: string,
key: string,
alpha?: number,
ratioMultiply?: number,
): string;
updateColor(alpha: number): void;
onConfigChange(newConfig: Config): void;
};
getMixedColor(
color: string,
key: string,
alpha?: number,
ratioMultiply?: number,
): string;
updateColor(alpha: number): void;
},
{
enabled: boolean;
ratio: number;
}
>({
export default createPlugin({
name: () => t('plugins.album-color-theme.name'),
description: () => t('plugins.album-color-theme.description'),
restartNeeded: false,
config: {
enabled: false,
ratio: 0.5,
},
enableSeekbar: true,
} satisfies Config as Config,
stylesheets: [style],
menu: async ({ getConfig, setConfig }) => {
const ratioList = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
@ -68,18 +59,28 @@ export default createPlugin<
},
})),
},
{
label: t('plugins.album-color-theme.menu.enable-seekbar'),
type: 'checkbox',
checked: config.enableSeekbar,
click(item) {
setConfig({ enableSeekbar: item.checked });
},
},
];
},
renderer: {
playerPage: null,
navBarBackground: null,
ytmusicPlayerBar: null,
playerBarBackground: null,
sidebarBig: null,
sidebarSmall: null,
ytmusicAppLayout: null,
playerPage: null as HTMLElement | null,
navBarBackground: null as HTMLElement | null,
ytmusicPlayerBar: null as HTMLElement | null,
playerBarBackground: null as HTMLElement | null,
sidebarBig: null as HTMLElement | null,
sidebarSmall: null as HTMLElement | null,
ytmusicAppLayout: null as HTMLElement | null,
color: null as ColorInstance | null,
darkColor: null as ColorInstance | null,
async start({ getConfig }) {
start() {
this.playerPage = document.querySelector<HTMLElement>('#player-page');
this.navBarBackground = document.querySelector<HTMLElement>(
'#nav-bar-background',
@ -94,14 +95,11 @@ export default createPlugin<
'#mini-guide-background',
);
this.ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
const config = await getConfig();
document.documentElement.style.setProperty(
RATIO_KEY,
`${~~(config.ratio * 100)}%`,
);
},
onPlayerApiReady(playerApi) {
async onPlayerApiReady(playerApi, { getConfig }) {
const config = await getConfig();
(this as Renderer).onConfigChange(config);
const fastAverageColor = new FastAverageColor();
document.addEventListener('videodatachange', async (event) => {
@ -152,7 +150,7 @@ export default createPlugin<
alpha = value;
}
}
this.updateColor(alpha ?? 1);
(this as Renderer).updateColor(alpha ?? 1);
});
},
onConfigChange(config) {
@ -160,8 +158,15 @@ export default createPlugin<
RATIO_KEY,
`${~~(config.ratio * 100)}%`,
);
if (config.enableSeekbar) document.body.classList.add('seekbar-theme');
else document.body.classList.remove('seekbar-theme');
},
getMixedColor(color: string, key: string, alpha = 1, ratioMultiply) {
getMixedColor(
color: string,
key: string,
alpha = 1,
ratioMultiply?: number,
) {
const keyColor = `rgba(var(${key}), ${alpha})`;
let colorRatio = `var(${RATIO_KEY}, 50%)`;
@ -207,26 +212,39 @@ export default createPlugin<
'--yt-spec-black-pure-alpha-80': 'rgba(0,0,0,0.8)',
'--yt-spec-black-1-alpha-98': 'rgba(40,40,40,0.98)',
'--yt-spec-black-1-alpha-95': 'rgba(40,40,40,0.95)',
'--paper-toast-background-color': '#323232',
'--ytmusic-search-background': '#030303',
'--paper-slider-knob-color': '#f03',
'--paper-dialog-background-color': '#212121',
'--paper-progress-active-color-1': '#f03',
'--paper-progress-active-color-2': '#ff2791',
'--yt-spec-inverted-background': '#f3f3f3',
'background': 'rgba(3, 3, 3)',
'--ytmusic-background': 'rgba(3, 3, 3)',
};
const colorKeyMap: Record<string, string> = {
'background': DARK_COLOR_KEY,
'--ytmusic-background': DARK_COLOR_KEY,
};
const ratioMap: Record<string, number> = {
'--paper-progress-active-color-1': 1.75,
'--paper-progress-active-color-2': 1.75,
'--yt-spec-inverted-background': 1.75,
};
const getMixedColor = (this as Renderer).getMixedColor.bind(this);
Object.entries(variableMap).map(([variable, color]) => {
const key = colorKeyMap[variable] ?? COLOR_KEY;
const ratio = ratioMap[variable] ?? undefined;
document.documentElement.style.setProperty(
variable,
this.getMixedColor(color, COLOR_KEY, alpha),
getMixedColor(color, key, alpha, ratio),
'important',
);
});
document.body.style.setProperty(
'background',
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
document.documentElement.style.setProperty(
'--ytmusic-background',
// #030303
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
},
},
});

View File

@ -81,3 +81,14 @@ ytmusic-browse-response[has-background]:not([disable-gradient]) .background-grad
#background.immersive-background.style-scope.ytmusic-browse-response {
opacity: 0.6;
}
ytmusic-search-box[is-bauhaus-sidenav-enabled] {
--ytmusic-search-background: var(--ytmusic-color-black3) !important;
}
.seekbar-theme #progress-bar.ytmusic-player-bar {
--paper-slider-active-color: linear-gradient(to right, var(--paper-progress-active-color-1) 80%, var(--paper-progress-active-color-2) 100%) !important;
--paper-slider-knob-color: var(--paper-progress-active-color-1) !important;
--paper-slider-knob-start-color: var(--paper-progress-active-color-2) !important;
}

View File

@ -8,6 +8,7 @@ import {
UniversalCache,
Utils,
YTNodes,
Platform,
} from '\u0079\u006f\u0075\u0074\u0075\u0062\u0065i.js';
import is from 'electron-is';
import filenamify from 'filenamify';
@ -57,6 +58,22 @@ const ffmpeg = lazy(async () =>
);
const ffmpegMutex = new Mutex();
Platform.shim.eval = async (data: Types.BuildScriptResult, env: Record<string, Types.VMPrimative>) => {
const properties = [];
if(env.n) {
properties.push(`n: exportedVars.nFunction("${env.n}")`)
}
if (env.sig) {
properties.push(`sig: exportedVars.sigFunction("${env.sig}")`)
}
const code = `${data.output}\nreturn { ${properties.join(', ')} }`;
return new Function(code)();
}
let yt: Innertube;
let win: BrowserWindow;
let playingUrl: string;
@ -131,7 +148,6 @@ export const onMainLoad = async ({
yt = await Innertube.create({
cache: new UniversalCache(false),
player_id: '0004de42',
cookie: await getCookieFromWindow(win),
generate_session_locally: true,
fetch: getNetFetchAsFetch(),

View File

@ -77,10 +77,11 @@ export class LRCLib implements LyricProvider {
}
const filteredResults = [];
const artists = artist.split(/[&,]/g).map((i) => i.trim());
for (const item of data) {
const { artistName } = item;
const artists = artist.split(/[&,]/g).map((i) => i.trim());
const itemArtists = artistName.split(/[&,]/g).map((i) => i.trim());
// Try to match using artist name first

View File

@ -0,0 +1,340 @@
// Code adapted from https://greasyfork.org/en/scripts/548724-youtube-music-spotify-%E7%BD%91%E6%98%93%E4%BA%91%E6%AD%8C%E8%AF%8D%E6%98%BE%E7%A4%BA
// which is licenced under the MIT licence
import CryptoJS from 'crypto-js';
import { jaroWinkler } from '@skyra/jaro-winkler';
import { z } from 'zod';
import { LRC } from '../parsers/lrc';
import type { LyricProvider, LyricResult, SearchSongInfo } from '../types';
const EAPI_AES_KEY = 'e82ckenh8dichen8';
const EAPI_ENCODE_KEY = '3go8&$8*3*3h0k(2)2';
const EAPI_CHECK_TOKEN =
'9ca17ae2e6ffcda170e2e6ee8ad85dba908ca4d74da9ac8ea2d44e938f9eadc66da5a8979af572a5a9b68ac12af0feaec3b92aa69af9b1d372f6b8adccb35e968b9bb6c14f908d0099fb6ff48efdacd361f5b6ee9e';
const EAPI_BASE_HEADERS = {
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) NeteaseMusicDesktop/3.0.14.2534',
};
const EAPI_BASE_COOKIES = {
os: 'osx',
appver: '3.0.14',
requestId: 0,
osver: '15.6.1',
};
const artistSchema = z.object({ id: z.number(), name: z.string() });
const songSchema = z.object({
resourceId: z.coerce.number(),
baseInfo: z.object({
simpleSongData: z.object({
name: z.string(),
ar: z.array(artistSchema).optional(),
dt: z.number(),
}),
}),
});
const searchResponseDataSchema = z.object({
resources: z.array(songSchema).default([]),
});
const searchResponseSchema = z.object({
code: z.number(),
message: z.string(),
data: searchResponseDataSchema,
});
type Song = z.infer<typeof songSchema>;
const lyricPartSchema = z.object({ lyric: z.string().nullable() });
const lyricResponseSchema = z.object({
lrc: lyricPartSchema.optional(),
tlyric: lyricPartSchema.optional(),
romalrc: lyricPartSchema.optional(),
});
export class Netease implements LyricProvider {
name = 'Netease';
baseUrl = 'https://interface.music.163.com';
cookies: Record<string, string> = {};
initialized = false;
private encode(id: string): string {
// XOR step (unchanged)
let xoredString = '';
for (let i = 0; i < id.length; i++) {
const charCode =
id.charCodeAt(i) ^
EAPI_ENCODE_KEY.charCodeAt(i % EAPI_ENCODE_KEY.length);
xoredString += String.fromCharCode(charCode);
}
// MD5 -> Base64 using crypto-js
const hash = CryptoJS.MD5(CryptoJS.enc.Latin1.parse(xoredString)).toString(
CryptoJS.enc.Base64,
);
// Build a binary WordArray for "id hash"
const combinedWordArray = CryptoJS.enc.Latin1.parse(id + ' ' + hash);
// Convert to Base64 (replaces Buffer.from(...).toString("base64"))
return CryptoJS.enc.Base64.stringify(combinedWordArray);
}
private async register() {
const deviceId = '7B79802670C7A45DB9091976D71E0AE829E28926C6C34A1B8644';
const username = this.encode(deviceId);
try {
await this.eapi('/register/anonimous', { username }, { _nmclfl: '1' });
this.initialized = true;
} catch (e) {
throw new Error(`Registration failed: ${e}`);
}
}
private async eapi(
path: string,
data: Record<string, unknown> = {},
params: Record<string, string> = {},
) {
const header = { ...EAPI_BASE_COOKIES };
const bodyData = { ...data, header: JSON.stringify(header) };
const body = JSON.stringify(bodyData);
const sign = CryptoJS.MD5(
`nobody/api${path}use${body}md5forencrypt`,
).toString();
const payload = `/api${path}-36cd479b6b5-${body}-36cd479b6b5-${sign}`;
const key = CryptoJS.enc.Utf8.parse(EAPI_AES_KEY);
const encrypted = CryptoJS.AES.encrypt(payload, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).ciphertext.toString(CryptoJS.enc.Hex);
const cookieString = Object.entries({ ...this.cookies })
.map(([k, v]) => `${k}=${v}`)
.join('; ');
const queryStr = new URLSearchParams(params).toString();
const url = `${this.baseUrl}/eapi${path}${queryStr ? `?${queryStr}` : ''}`;
const response = await fetch(url, {
method: 'POST',
headers: {
...EAPI_BASE_HEADERS,
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': cookieString,
},
body: `params=${encodeURIComponent(encrypted.toUpperCase())}`,
});
const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) {
const cookieStrings = setCookieHeader.split(/,(?=\s*[^=;\s]+=)/);
for (const cookieStr of cookieStrings) {
const parts = cookieStr.split(';')[0].split('=');
if (parts.length === 2) {
this.cookies[parts[0].trim()] = parts[1].trim();
}
}
}
if (!response.ok) {
throw new Error(`bad HTTPStatus(${response.statusText})`);
}
const json = await response.json();
z.object({ code: z.literal(200) }).parse(json);
return json;
}
private async searchSongs(keyword: string, limit = 10): Promise<Song[]> {
const response = await this.eapi(
'/search/song/list/page',
{
offset: '0',
scene: 'NORMAL',
needCorrect: 'true',
checkToken: EAPI_CHECK_TOKEN,
keyword,
limit: limit.toString(),
verifyId: 1,
},
{
_nmclfl: '1',
},
);
const parsed = searchResponseSchema.parse(response);
return parsed.data?.resources || [];
}
private async getLyric(id: number) {
const response = await this.eapi(
'/song/lyric/v1',
{
id,
tv: '-1',
yv: '-1',
rv: '-1',
lv: '-1',
verifyId: 1,
},
{
_nmclfl: '1',
},
);
return lyricResponseSchema.parse(response);
}
private splitTitle(title: string): string[] {
const masterPattern =
/(?:[「『](?<content>.+?)[」』])|(?:【.*?】|〖.*?〗|\(.*?\)|.*?)|(?<delimiter>\s+-\s+|\s*[/|:|│]\s*)/i;
const noiseWords = /\b(MV|PV)\b|\b(?:covered by|feat?|ft?)\b.+/gi;
const parse = (str: string): string[] => {
if (!str?.trim()) return [];
const match = str.match(masterPattern);
if (!match || match.index === undefined) return [str];
const before = str.substring(0, match.index);
const after = str.substring(match.index + match[0].length);
const { delimiter, content } = match.groups || {};
if (delimiter && (before.trim().length < 2 || after.trim().length < 2)) {
const remaining = parse(after);
return [
before + match[0] + (remaining[0] || ''),
...remaining.slice(1),
];
}
return [...parse(before), ...(content ? [content] : []), ...parse(after)];
};
return [
...new Set(
parse(title)
.map((p) => p.replace(noiseWords, '').trim())
.filter((p) => p.length > 0),
),
];
}
async search({
title,
artist,
songDuration,
}: SearchSongInfo): Promise<LyricResult | null> {
if (!this.initialized) {
await this.register();
}
const parts = this.splitTitle(title);
if (parts.length === 0) {
parts.push(title);
}
const keywords = [...parts];
if (parts[0] !== artist) keywords.push(`${parts[0]} ${artist}`);
const results = await Promise.all(
keywords.map((kw) => this.searchSongs(kw, 10)),
);
const calcTitleScore = (searchTitle: string) => {
let avgScore = 0;
parts.forEach((part, idx) => {
let weight = 1 / (idx * 2 + 1); // Earlier parts have higher weight
if (searchTitle.startsWith(part)) weight *= 2;
// Bonus for prefix match
else if (searchTitle.includes(part)) weight *= 1.5; // Bonus for substring match
avgScore += (jaroWinkler(part, searchTitle) * weight) / parts.length;
});
const score = Math.max(jaroWinkler(title, searchTitle), avgScore);
return score;
};
const artists = artist.split(/[&,]/g).map((i) => i.trim());
const filteredResults = [];
for (const result of results.flat()) {
const {
baseInfo: {
simpleSongData: { name, ar: itemArtists },
},
} = result;
const permutations = [];
for (const artistA of artists) {
for (const artistB of itemArtists ?? []) {
permutations.push([
artistA.toLowerCase(),
artistB.name.toLowerCase(),
]);
}
}
for (const artistA of itemArtists ?? []) {
for (const artistB of artists) {
permutations.push([
artistA.name.toLowerCase(),
artistB.toLowerCase(),
]);
}
}
const ratio =
calcTitleScore(name) +
Math.max(...permutations.map(([x, y]) => jaroWinkler(x, y)));
if (ratio < 1.8) continue;
filteredResults.push(result);
}
const closestResult = filteredResults[0];
if (!closestResult) {
return null;
}
if (
Math.abs(closestResult.baseInfo.simpleSongData.dt / 1000 - songDuration) >
15
) {
return null;
}
const lyric = await this.getLyric(closestResult.resourceId);
if (!lyric || !lyric.lrc?.lyric) return null;
const lyrics = stripMetadata(lyric.lrc.lyric);
const lines = LRC.parse(lyrics).lines.map((l) => ({
...l,
status: 'upcoming' as const,
}));
if (lines.length === 0 && !lyrics.trim()) return null;
return {
title: closestResult.baseInfo.simpleSongData.name,
artists:
closestResult.baseInfo.simpleSongData.ar?.map((a) => a.name) ?? [],
lines,
lyrics: lyrics,
};
}
}
const stripMetadata = (lyrics: string) => {
return lyrics
.split('\n')
.filter((line) => {
if (!line.includes('{')) return true;
try {
JSON.parse(line);
return false;
} catch {}
return true;
})
.join('\n');
};

View File

@ -7,6 +7,7 @@ export enum ProviderNames {
LRCLib = 'LRCLib',
MusixMatch = 'MusixMatch',
LyricsGenius = 'LyricsGenius',
NetEase = 'NetEase',
// Megalobiz = 'Megalobiz',
}

View File

@ -3,11 +3,13 @@ import { YTMusic } from './YTMusic';
import { LRCLib } from './LRCLib';
import { MusixMatch } from './MusixMatch';
import { LyricsGenius } from './LyricsGenius';
import { Netease } from './NetEase';
export const providers = {
[ProviderNames.YTMusic]: new YTMusic(),
[ProviderNames.LRCLib]: new LRCLib(),
[ProviderNames.MusixMatch]: new MusixMatch(),
[ProviderNames.LyricsGenius]: new LyricsGenius(),
[ProviderNames.NetEase]: new Netease(),
// [ProviderNames.Megalobiz]: new Megalobiz(), // Disabled because it is too unstable and slow
} as const;