mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
Compare commits
141 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2e33bc8f96 | |||
| 0d6da0681a | |||
| 1c76415846 | |||
| a3d620ba52 | |||
| 82bf407323 | |||
| d83556e9fa | |||
| f70ae4f7c4 | |||
| 268e7be15d | |||
| accd2bf350 | |||
| 58cf1a543d | |||
| 183461a968 | |||
| 4fe0fb9845 | |||
| 0e5e1b8700 | |||
| 1ab1c86909 | |||
| 5e0f03dcd3 | |||
| d4b5778fdd | |||
| 943b806bbb | |||
| a5d6c32f77 | |||
| 4efa243ed0 | |||
| 8d09f27c59 | |||
| 47a2cde673 | |||
| 67051bb5ce | |||
| 233f6dbdea | |||
| 2c7a46240d | |||
| e0edc0c1dd | |||
| 2001fb9254 | |||
| 206efaa7f7 | |||
| 8bb1d63cb0 | |||
| 841de026ce | |||
| 6fac8b409e | |||
| b5ce1f566d | |||
| 8bb4f4426f | |||
| c962d60c6d | |||
| 1d29e6be1a | |||
| 970205954b | |||
| 89fe072c0e | |||
| 93d68a94a3 | |||
| f7afe1b994 | |||
| 5507f1acee | |||
| d513302a9a | |||
| f31351be9c | |||
| 99fdd027c3 | |||
| 0b143ec3a2 | |||
| 588992f84b | |||
| 7306b0bc4e | |||
| 9365f6edbc | |||
| 2c94cc760a | |||
| 53193cda98 | |||
| 5853523074 | |||
| 3a18eb8097 | |||
| 042a7df771 | |||
| 5c2a6598b9 | |||
| 2e4e9faf53 | |||
| a581ddf80d | |||
| 500f770da8 | |||
| 7cfe93312f | |||
| f4bc90bf2d | |||
| 587fcdf23a | |||
| c375e73781 | |||
| 8cf045b450 | |||
| e91f2d386d | |||
| 505465e745 | |||
| 662d3af81b | |||
| fef3b63581 | |||
| 0d3311ff5d | |||
| 7370b56767 | |||
| c0f3f136bb | |||
| 62c2dcba95 | |||
| 3e1abd984f | |||
| b689ba272b | |||
| 2775063cc8 | |||
| d557d1cbf0 | |||
| e965ac2004 | |||
| a1a0705c07 | |||
| 29dfef1518 | |||
| 2c5b09e488 | |||
| 5a2b5ae522 | |||
| 5dc3b09b7b | |||
| 1a1a764d64 | |||
| fc47c9f590 | |||
| 470bc761ef | |||
| a60dde2bdb | |||
| 8b1332ee38 | |||
| 12eb7c7d9b | |||
| aecac6be6c | |||
| 44913173eb | |||
| 2829108e32 | |||
| 0eb10017c9 | |||
| c36745e79b | |||
| e33269bce6 | |||
| 7c4894a5f3 | |||
| 84e3cf895f | |||
| 9d7281179b | |||
| 85c0995323 | |||
| 21990e71db | |||
| 9d99ff4095 | |||
| 075fcde92a | |||
| e654b7e695 | |||
| df78d13076 | |||
| 7bc24116da | |||
| 3225cfe5dd | |||
| 9de8bfcdc4 | |||
| ab01c80a13 | |||
| b6fb3d6316 | |||
| 6287d10a82 | |||
| ed79631d66 | |||
| b7f607bdbd | |||
| 546c89e175 | |||
| 486a43f4b7 | |||
| 8d51137a18 | |||
| cf67540a1f | |||
| edad53e989 | |||
| cc6c0bdff1 | |||
| dbdc3c60a5 | |||
| db4134f40d | |||
| 21c3e6a5f2 | |||
| e5b4ba9f15 | |||
| 8a51468671 | |||
| 083403bf80 | |||
| 886f3203e0 | |||
| 253fe0055f | |||
| 6637f6a0da | |||
| f7e359a740 | |||
| 3c88d171ab | |||
| 8e27be48c6 | |||
| 700b2a3669 | |||
| 329327d491 | |||
| 829a06db5a | |||
| 98b4053a3a | |||
| d340828da7 | |||
| fb18f26964 | |||
| b37fee1e1b | |||
| fb2c4f0a09 | |||
| d58897ba4c | |||
| c30fbe41a6 | |||
| 5a7daaf2f6 | |||
| 61c0217b8f | |||
| d5ea182a50 | |||
| 33133de7c7 | |||
| b544e18cea | |||
| 808f802efd |
@ -3,7 +3,7 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/eslint.config.mjs)
|
[](https://github.com/th-ch/youtube-music/blob/master/eslint.config.mjs)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇫🇷](./docs/readme/README-fr.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md), [🇷🇺](./docs/readme/README-ru.md), [🇭🇺](./docs/readme/README-hu.md)
|
Read this in other languages: [🇰🇷](./docs/readme/README-ko.md), [🇫🇷](./docs/readme/README-fr.md), [🇮🇸](./docs/readme/README-is.md), [🇨🇱 🇪🇸](./docs/readme/README-es.md), [🇷🇺](./docs/readme/README-ru.md), [🇭🇺](./docs/readme/README-hu.md), [🇧🇷](./docs/readme/README-pt.md), [🇯🇵](./docs/readme/README-ja.md)
|
||||||
|
|
||||||
**Electron wrapper around YouTube Music featuring:**
|
**Electron wrapper around YouTube Music featuring:**
|
||||||
|
|
||||||
|
|||||||
130
changelog.md
130
changelog.md
@ -2,8 +2,138 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||||
|
|
||||||
|
#### [v3.8.1](https://github.com/th-ch/youtube-music/compare/v3.8.0...v3.8.1)
|
||||||
|
|
||||||
|
- chore(deps): update dependency glob to v11.0.2 [`#3283`](https://github.com/th-ch/youtube-music/pull/3283)
|
||||||
|
- fix(deps): update dependency i18next to v25.0.1 [`#3284`](https://github.com/th-ch/youtube-music/pull/3284)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.31.0 [`#3286`](https://github.com/th-ch/youtube-music/pull/3286)
|
||||||
|
- chore(deps): update dependency discord-api-types to v0.38.1 [`#3285`](https://github.com/th-ch/youtube-music/pull/3285)
|
||||||
|
- fix(deps): update dependency youtubei.js to v13.4.0 [`#3287`](https://github.com/th-ch/youtube-music/pull/3287)
|
||||||
|
- fix(deps): update dependency zod to v3.24.3 [`#3250`](https://github.com/th-ch/youtube-music/pull/3250)
|
||||||
|
- chore(deps): update dependency vite to v6.3.3 [`#3251`](https://github.com/th-ch/youtube-music/pull/3251)
|
||||||
|
- fix(deps): update dependency @hono/zod-openapi to v0.19.5 [`#3258`](https://github.com/th-ch/youtube-music/pull/3258)
|
||||||
|
- chore(deps): update dependency vite-plugin-inspect to v11.0.1 [`#3259`](https://github.com/th-ch/youtube-music/pull/3259)
|
||||||
|
- chore(deps): update dependency esbuild to v0.25.3 [`#3282`](https://github.com/th-ch/youtube-music/pull/3282)
|
||||||
|
- chore(deps): update eslint monorepo to v9.25.1 [`#3260`](https://github.com/th-ch/youtube-music/pull/3260)
|
||||||
|
- chore(deps): update dependency electron to v35.2.1 [`#3281`](https://github.com/th-ch/youtube-music/pull/3281)
|
||||||
|
- chore(deps): update playwright monorepo to v1.52.0 [`#3256`](https://github.com/th-ch/youtube-music/pull/3256)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.3.4 [`#3273`](https://github.com/th-ch/youtube-music/pull/3273)
|
||||||
|
- fix: fix cuted "j" and glow in lyrics [`#3277`](https://github.com/th-ch/youtube-music/pull/3277)
|
||||||
|
- chore(deps): update dependency electron to v35.2.0 [`#3263`](https://github.com/th-ch/youtube-music/pull/3263)
|
||||||
|
- fix(unobtrusive-player): handle shuffle play [`#3247`](https://github.com/th-ch/youtube-music/pull/3247)
|
||||||
|
- fix(deps): update dependency @ghostery/adblocker-electron to v2.5.1 [`#3238`](https://github.com/th-ch/youtube-music/pull/3238)
|
||||||
|
- chore(deps): update dependency vite to v6.3.0 [`#3248`](https://github.com/th-ch/youtube-music/pull/3248)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.30.1 [`#3234`](https://github.com/th-ch/youtube-music/pull/3234)
|
||||||
|
- fix(deps): update dependency @ghostery/adblocker-electron-preload to v2.5.1 [`#3239`](https://github.com/th-ch/youtube-music/pull/3239)
|
||||||
|
- fix(deps): update dependency i18next to v25 [`#3243`](https://github.com/th-ch/youtube-music/pull/3243)
|
||||||
|
- fix(deps): update dependency hono to v4.7.7 [`#3245`](https://github.com/th-ch/youtube-music/pull/3245)
|
||||||
|
- chore(deps): update dependency vite to v6.2.6 [`#3189`](https://github.com/th-ch/youtube-music/pull/3189)
|
||||||
|
- feat(Synced-Lyrics): Also search for lyrics with the original title language [`#3206`](https://github.com/th-ch/youtube-music/pull/3206)
|
||||||
|
- chore(deps): update dependency eslint-config-prettier to v10.1.2 [`#3219`](https://github.com/th-ch/youtube-music/pull/3219)
|
||||||
|
- chore(deps): update dependency discord-api-types to v0.37.120 [`#3221`](https://github.com/th-ch/youtube-music/pull/3221)
|
||||||
|
- fix(deps): update dependency @hono/node-server to v1.14.1 [`#3223`](https://github.com/th-ch/youtube-music/pull/3223)
|
||||||
|
- chore(deps): update dependency vite to v6.2.6 [security] [`#3224`](https://github.com/th-ch/youtube-music/pull/3224)
|
||||||
|
- chore(deps): update dependency rollup to v4.40.0 [`#3227`](https://github.com/th-ch/youtube-music/pull/3227)
|
||||||
|
- fix(mpris): keep MPRIS volume in sync with the actual volume [`#3226`](https://github.com/th-ch/youtube-music/pull/3226)
|
||||||
|
- fix(deps): update dependency @hono/zod-openapi to v0.19.4 [`#3215`](https://github.com/th-ch/youtube-music/pull/3215)
|
||||||
|
- chore(deps): update dependency electron to v35.1.5 [`#3218`](https://github.com/th-ch/youtube-music/pull/3218)
|
||||||
|
- fix(deps): update dependency hono to v4.7.6 [`#3217`](https://github.com/th-ch/youtube-music/pull/3217)
|
||||||
|
- docs: add Portuguese README translation and update language shortcuts [`#3192`](https://github.com/th-ch/youtube-music/pull/3192)
|
||||||
|
- fix: custom Video/Audio switcher in Plugins menu [`#3174`](https://github.com/th-ch/youtube-music/pull/3174)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.29.1 [`#3214`](https://github.com/th-ch/youtube-music/pull/3214)
|
||||||
|
- chore(deps): update eslint monorepo to v9.24.0 [`#3195`](https://github.com/th-ch/youtube-music/pull/3195)
|
||||||
|
- chore(deps): update dependency typescript to v5.8.3 [`#3196`](https://github.com/th-ch/youtube-music/pull/3196)
|
||||||
|
- chore(deps): update dependency vite to v6.2.5 [security] [`#3194`](https://github.com/th-ch/youtube-music/pull/3194)
|
||||||
|
- fix(deps): update dependency node-id3 to v0.2.9 [`#3191`](https://github.com/th-ch/youtube-music/pull/3191)
|
||||||
|
- chore(deps): update dependency electron to v35.1.4 [`#3184`](https://github.com/th-ch/youtube-music/pull/3184)
|
||||||
|
- chore(deps): update dependency eslint-plugin-prettier to v5.2.6 [`#3182`](https://github.com/th-ch/youtube-music/pull/3182)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.3.2 [`#3208`](https://github.com/th-ch/youtube-music/pull/3208)
|
||||||
|
- docs: add Japanese README [`#3180`](https://github.com/th-ch/youtube-music/pull/3180)
|
||||||
|
- chore(deps): update dependency node-gyp to v11.2.0 [`#3177`](https://github.com/th-ch/youtube-music/pull/3177)
|
||||||
|
- chore(deps): update dependency rollup to v4.39.0 [`#3179`](https://github.com/th-ch/youtube-music/pull/3179)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.29.0 [`#3169`](https://github.com/th-ch/youtube-music/pull/3169)
|
||||||
|
- fix(downloader): allow downloads for signed out users [`#3145`](https://github.com/th-ch/youtube-music/pull/3145)
|
||||||
|
- fix(README): Fixed typos in some hyperlinks [`#3158`](https://github.com/th-ch/youtube-music/pull/3158)
|
||||||
|
- chore(deps): update dependency vite to v6.2.4 [`#3124`](https://github.com/th-ch/youtube-music/pull/3124)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.3.1 [`#3151`](https://github.com/th-ch/youtube-music/pull/3151)
|
||||||
|
- chore(deps): update dependency rollup to v4.38.0 [`#3154`](https://github.com/th-ch/youtube-music/pull/3154)
|
||||||
|
- chore(deps): update dependency esbuild to v0.25.2 [`#3160`](https://github.com/th-ch/youtube-music/pull/3160)
|
||||||
|
- chore(deps): update dependency electron to v35.1.2 [`#3147`](https://github.com/th-ch/youtube-music/pull/3147)
|
||||||
|
- chore(deps): update dependency electron to v35.1.1 [`#3143`](https://github.com/th-ch/youtube-music/pull/3143)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.2.5 [`#3144`](https://github.com/th-ch/youtube-music/pull/3144)
|
||||||
|
- chore(deps): update dependency @types/semver to v7.7.0 [`#3141`](https://github.com/th-ch/youtube-music/pull/3141)
|
||||||
|
- fix(deps): update dependency electron-updater to v6.6.2 [`#3142`](https://github.com/th-ch/youtube-music/pull/3142)
|
||||||
|
- chore(i18n): Translated using Weblate (Greek) [`8bb4f44`](https://github.com/th-ch/youtube-music/commit/8bb4f4426f6a82b1b5c13a385a6e2b94c25f88a2)
|
||||||
|
- chore(i18n): Translated using Weblate (Bulgarian) [`89fe072`](https://github.com/th-ch/youtube-music/commit/89fe072c0e719026212bb506bb66baf37b31ceb4)
|
||||||
|
- chore(i18n): Translated using Weblate (Greek) [`5a7daaf`](https://github.com/th-ch/youtube-music/commit/5a7daaf2f6d1211c4b9461facf4de1962714bacf)
|
||||||
|
|
||||||
|
#### [v3.8.0](https://github.com/th-ch/youtube-music/compare/v3.7.5...v3.8.0)
|
||||||
|
|
||||||
|
> 26 March 2025
|
||||||
|
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.28.0 [`#3128`](https://github.com/th-ch/youtube-music/pull/3128)
|
||||||
|
- chore(deps): update dependency eslint-plugin-prettier to v5.2.5 [`#3123`](https://github.com/th-ch/youtube-music/pull/3123)
|
||||||
|
- fix(deps): update dependency @hono/node-server to v1.14.0 [`#3131`](https://github.com/th-ch/youtube-music/pull/3131)
|
||||||
|
- chore(deps): update dependency electron to v35.1.0 [`#3136`](https://github.com/th-ch/youtube-music/pull/3136)
|
||||||
|
- fix(deps): update dependency es-hangul to v2.3.2 [`#3138`](https://github.com/th-ch/youtube-music/pull/3138)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.2.4 [`#3135`](https://github.com/th-ch/youtube-music/pull/3135)
|
||||||
|
- chore(deps): update eslint monorepo to v9.23.0 [`#3130`](https://github.com/th-ch/youtube-music/pull/3130)
|
||||||
|
- chore(deps): update dependency electron-vite to v3.1.0 [`#3137`](https://github.com/th-ch/youtube-music/pull/3137)
|
||||||
|
- chore(deps): update dependency @babel/runtime to v7.27.0 [`#3127`](https://github.com/th-ch/youtube-music/pull/3127)
|
||||||
|
- feat(synced-lyrics): romanization [`#2790`](https://github.com/th-ch/youtube-music/pull/2790)
|
||||||
|
- feat(plugin): add unobtrusive player plugin [`#3104`](https://github.com/th-ch/youtube-music/pull/3104)
|
||||||
|
- chore(deps): update dependency vite to v6.2.3 [security] [`#3134`](https://github.com/th-ch/youtube-music/pull/3134)
|
||||||
|
- fix(deps): update dependency youtubei.js to v13.3.0 [`#3133`](https://github.com/th-ch/youtube-music/pull/3133)
|
||||||
|
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.12 [`#3122`](https://github.com/th-ch/youtube-music/pull/3122)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4.2.2 [`#3106`](https://github.com/th-ch/youtube-music/pull/3106)
|
||||||
|
- chore(deps): update dependency electron-builder to v26.0.12 [`#3121`](https://github.com/th-ch/youtube-music/pull/3121)
|
||||||
|
- fix: Discord Rich Presence Fix [`#3074`](https://github.com/th-ch/youtube-music/pull/3074)
|
||||||
|
- fix(deps): update dependency @xhayper/discord-rpc to v1.2.1 [`#3107`](https://github.com/th-ch/youtube-music/pull/3107)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.27.0 [`#3111`](https://github.com/th-ch/youtube-music/pull/3111)
|
||||||
|
- chore(deps): update dependency electron to v35.0.3 [`#3112`](https://github.com/th-ch/youtube-music/pull/3112)
|
||||||
|
- fix(deps): update dependency hono to v4.7.5 [`#3113`](https://github.com/th-ch/youtube-music/pull/3113)
|
||||||
|
- fix(deps): update dependency fast-average-color to v9.5.0 [`#3114`](https://github.com/th-ch/youtube-music/pull/3114)
|
||||||
|
- chore(deps): update dependency rollup to v4.37.0 [`#3103`](https://github.com/th-ch/youtube-music/pull/3103)
|
||||||
|
- chore(deps): update playwright monorepo to v1.51.1 [`#3105`](https://github.com/th-ch/youtube-music/pull/3105)
|
||||||
|
- chore(deps): update dependency eslint-import-resolver-typescript to v4 [`#3102`](https://github.com/th-ch/youtube-music/pull/3102)
|
||||||
|
- chore(deps): update dependency electron to v35.0.2 [`#3099`](https://github.com/th-ch/youtube-music/pull/3099)
|
||||||
|
- fix(deps): update dependency i18next to v24.2.3 [`#3100`](https://github.com/th-ch/youtube-music/pull/3100)
|
||||||
|
- chore(deps): update dependency electron-builder to v26.0.11 [`#3095`](https://github.com/th-ch/youtube-music/pull/3095)
|
||||||
|
- chore(deps): update dependency @babel/runtime to v7.26.10 [security] [`#3094`](https://github.com/th-ch/youtube-music/pull/3094)
|
||||||
|
- chore(deps): update dependency eslint-config-prettier to v10.1.1 [`#3069`](https://github.com/th-ch/youtube-music/pull/3069)
|
||||||
|
- chore(deps): update playwright monorepo to v1.51.0 [`#3065`](https://github.com/th-ch/youtube-music/pull/3065)
|
||||||
|
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.11 [`#3096`](https://github.com/th-ch/youtube-music/pull/3096)
|
||||||
|
- chore(deps): update dependency esbuild to v0.25.1 [`#3097`](https://github.com/th-ch/youtube-music/pull/3097)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.26.1 [`#3098`](https://github.com/th-ch/youtube-music/pull/3098)
|
||||||
|
- chore(deps): update eslint monorepo to v9.22.0 [`#3070`](https://github.com/th-ch/youtube-music/pull/3070)
|
||||||
|
- chore(deps): update dependency rollup to v4.35.0 [`#3071`](https://github.com/th-ch/youtube-music/pull/3071)
|
||||||
|
- chore(deps): update dependency electron to v35.0.1 [`#3075`](https://github.com/th-ch/youtube-music/pull/3075)
|
||||||
|
- fix(deps): update dependency happy-dom to v17.4.4 [`#3068`](https://github.com/th-ch/youtube-music/pull/3068)
|
||||||
|
- chore(deps): update dependency vite to v6.2.2 [`#3067`](https://github.com/th-ch/youtube-music/pull/3067)
|
||||||
|
- fix: Update winget-releaser version to main [`#3091`](https://github.com/th-ch/youtube-music/pull/3091)
|
||||||
|
- feat: Allow scrobbling using alternative song titles [`#3093`](https://github.com/th-ch/youtube-music/pull/3093)
|
||||||
|
- chore(deps): update dependency electron-builder-squirrel-windows to v26.0.10 [`#3054`](https://github.com/th-ch/youtube-music/pull/3054)
|
||||||
|
- chore(deps): update dependency typescript-eslint to v8.26.0 [`#3056`](https://github.com/th-ch/youtube-music/pull/3056)
|
||||||
|
- fix(deps): update dependency hono to v4.7.4 [`#3062`](https://github.com/th-ch/youtube-music/pull/3062)
|
||||||
|
- chore(deps): update dependency electron-builder to v26.0.10 [`#3053`](https://github.com/th-ch/youtube-music/pull/3053)
|
||||||
|
- chore(deps): update dependency electron to v35 [`#3058`](https://github.com/th-ch/youtube-music/pull/3058)
|
||||||
|
- fix(deps): update dependency happy-dom to v17.2.2 [`#3060`](https://github.com/th-ch/youtube-music/pull/3060)
|
||||||
|
- fix(deps): update dependency happy-dom to v17.1.13 [`#3057`](https://github.com/th-ch/youtube-music/pull/3057)
|
||||||
|
- chore(deps): update dependency typescript to v5.8.2 [`#3040`](https://github.com/th-ch/youtube-music/pull/3040)
|
||||||
|
- chore(deps): update dependency rollup to v4.34.9 [`#3043`](https://github.com/th-ch/youtube-music/pull/3043)
|
||||||
|
- fix(deps): update dependency @hono/swagger-ui to v0.5.1 [`#3045`](https://github.com/th-ch/youtube-music/pull/3045)
|
||||||
|
- fix: added French link in general README file [`#3047`](https://github.com/th-ch/youtube-music/pull/3047)
|
||||||
|
- fix(deps): update dependency @hono/zod-openapi to v0.19.2 [`#3046`](https://github.com/th-ch/youtube-music/pull/3046)
|
||||||
|
- chore(deps): update dependency @stylistic/eslint-plugin-js to v4.2.0 [`#3050`](https://github.com/th-ch/youtube-music/pull/3050)
|
||||||
|
- fix(deps): update dependency bgutils-js to v3.2.0 [`#3049`](https://github.com/th-ch/youtube-music/pull/3049)
|
||||||
|
- chore(i18n): Translated using Weblate (Tamil) [`a3601ce`](https://github.com/th-ch/youtube-music/commit/a3601cece6a1d291f9887e1a5049fb3c6ad09eb1)
|
||||||
|
- chore(i18n): Translated using Weblate (Arabic) [`06aaba0`](https://github.com/th-ch/youtube-music/commit/06aaba0c7fe9173051701c626d44a347b1bd7574)
|
||||||
|
- chore(i18n): Translated using Weblate (Spanish) [`dbf8b1c`](https://github.com/th-ch/youtube-music/commit/dbf8b1c5c53d88f676c12b7ffca0e23b3efaa541)
|
||||||
|
|
||||||
#### [v3.7.5](https://github.com/th-ch/youtube-music/compare/v3.7.4...v3.7.5)
|
#### [v3.7.5](https://github.com/th-ch/youtube-music/compare/v3.7.4...v3.7.5)
|
||||||
|
|
||||||
|
> 1 March 2025
|
||||||
|
|
||||||
- chore(deps): update dependency builtin-modules to v5 [`#3038`](https://github.com/th-ch/youtube-music/pull/3038)
|
- chore(deps): update dependency builtin-modules to v5 [`#3038`](https://github.com/th-ch/youtube-music/pull/3038)
|
||||||
- chore(deps): update dependency typescript-eslint to v8.25.0 [`#2953`](https://github.com/th-ch/youtube-music/pull/2953)
|
- chore(deps): update dependency typescript-eslint to v8.25.0 [`#2953`](https://github.com/th-ch/youtube-music/pull/2953)
|
||||||
- fix(deps): update dependency happy-dom to v17.1.8 [`#3001`](https://github.com/th-ch/youtube-music/pull/3001)
|
- fix(deps): update dependency happy-dom to v17.1.8 [`#3001`](https://github.com/th-ch/youtube-music/pull/3001)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Lee esto en otros idiomas: [🏴 Inglés](../../README.md), [🇰🇷 Coreano](./README-ko.md), [🇫🇷 Francés](./README-fr.md), [🇮🇸 Islandés](./README-is.md), [🇪🇸 Español](./README-es.md), [🇷🇺 Ruso](./README-ru.md)
|
Lee esto en otros idiomas: [🏴 Inglés](../../README.md), [🇰🇷 Coreano](./README-ko.md), [🇫🇷 Francés](./README-fr.md), [🇮🇸 Islandés](./README-is.md), [🇪🇸 Español](./README-es.md), [🇷🇺 Ruso](./README-ru.md), [🇧🇷 Portugués](./README-pt.md), [🇯🇵 Japonés](./README-ja.md)
|
||||||
|
|
||||||
**Electron wrapper de YouTube Music con las siguientes características:**
|
**Electron wrapper de YouTube Music con las siguientes características:**
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Lisez ceci dans d'autres langues: [🏴 Anglais](../../README.md), [🇰🇷 Coréen](./README-ko.md), [🇫🇷 Français](./README-fr.md), [🇮🇸 Islandais](./README-is.md), [🇪🇸 Espagnol](./README-es.md), [🇷🇺 Russe](./README-ru.md)
|
Lisez ceci dans d'autres langues: [🏴 Anglais](../../README.md), [🇰🇷 Coréen](./README-ko.md), [🇫🇷 Français](./README-fr.md), [🇮🇸 Islandais](./README-is.md), [🇪🇸 Espagnol](./README-es.md), [🇷🇺 Russe](./README-ru.md), [🇧🇷 Portugais](./README-pt.md), [🇯🇵 Japonais](./README-ja.md)
|
||||||
|
|
||||||
**Enveloppe Electron autour de YouTube Music offrant :**
|
**Enveloppe Electron autour de YouTube Music offrant :**
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/eslint.config.mjs)
|
[](https://github.com/th-ch/youtube-music/blob/master/eslint.config.mjs)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Olvasd el más nyelveken: [🏴 Angol](../../README.md), [🇰🇷 Korea](./README-ko.md), [🇫🇷 Francia](./README-fr.md), [🇮🇸 Izland](./README-is.md), [🇪🇸 Spanyol](./README-es.md), [🇷🇺 Orosz](./README-ru.md)
|
Olvasd el más nyelveken: [🏴 Angol](../../README.md), [🇰🇷 Korea](./README-ko.md), [🇫🇷 Francia](./README-fr.md), [🇮🇸 Izland](./README-is.md), [🇪🇸 Spanyol](./README-es.md), [🇷🇺 Orosz](./README-ru.md), [🇧🇷 Portugál](./README-pt.md), [🇯🇵 Japán](./README-ja.md)
|
||||||
|
|
||||||
**Electron keretrendszerre épülő alkalmazás a YouTube Music számára, amely a következőket kínálja:**
|
**Electron keretrendszerre épülő alkalmazás a YouTube Music számára, amely a következőket kínálja:**
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
# YouTube Tónlist
|
# YouTube Tónlist
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Lestu þetta á öðrum tungumálum: [🏴 Ensku](../../README.md), [🇰🇷 Kóreska](./README-ko.md), [🇫🇷 Franska](./README-fr.md), [🇮🇸 Íslenskur](./README-is.md), [🇪🇸 Spænska](./README-es.md), [🇷🇺 Rússneska](./README-ru.md)
|
Lestu þetta á öðrum tungumálum: [🏴 Ensku](../../README.md), [🇰🇷 Kóreska](./README-ko.md), [🇫🇷 Franska](./README-fr.md), [🇮🇸 Íslenskur](./README-is.md), [🇪🇸 Spænska](./README-es.md), [🇷🇺 Rússneska](./README-ru.md), [🇧🇷 Portúgalska](./README-pt.md), [🇯🇵 Japanska](./README-ja.md)
|
||||||
|
|
||||||
**Electron umbúðir utan um YouTube Tónlist sem inniheldur:**
|
**Electron umbúðir utan um YouTube Tónlist sem inniheldur:**
|
||||||
|
|
||||||
|
|||||||
371
docs/readme/README-ja.md
Normal file
371
docs/readme/README-ja.md
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
# YouTube Music
|
||||||
|
|
||||||
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://aur.archlinux.org/packages/youtube-music-bin)
|
||||||
|
[](https://snyk.io/test/github/th-ch/youtube-music)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
他の言語で読む: [🏴 英語](../../README.md), [🇰🇷 韓国語](./README-ko.md), [🇫🇷 フランス語](./README-fr.md), [🇮🇸 アイスランド語](./README-is.md), [🇪🇸 スペイン語](./README-es.md), [🇷🇺 ロシア語](./README-ru.md)
|
||||||
|
|
||||||
|
**YouTube MusicのElectronラッパーには以下の機能があります:**
|
||||||
|
|
||||||
|
- ネイティブの外観と操作感、元のインターフェースを維持することを目指しています
|
||||||
|
- カスタムプラグインのフレームワーク: スタイル、コンテンツ、機能など、YouTube Musicをニーズに合わせて変更し、ワンクリックでプラグインを有効/無効にできます
|
||||||
|
|
||||||
|
## デモ画像
|
||||||
|
|
||||||
|
| プレーヤースクリーン (アルバムカラーテーマ & アンビエントライト) |
|
||||||
|
|:---------------------------------------------------------------------------------------------------------:|
|
||||||
|
||
|
||||||
|
|
||||||
|
## コンテンツ
|
||||||
|
|
||||||
|
- [機能](#機能)
|
||||||
|
- [利用可能なプラグイン](#利用可能なプラグイン)
|
||||||
|
- [翻訳](#翻訳)
|
||||||
|
- [ダウンロード](#ダウンロード)
|
||||||
|
- [Arch Linux](#arch-linux)
|
||||||
|
- [MacOS](#macos)
|
||||||
|
- [Windows](#windows)
|
||||||
|
- [ネットワーク接続なしでインストールする方法 (Windows)](#ネットワーク接続なしでインストールする方法-windows)
|
||||||
|
- [テーマ](#テーマ)
|
||||||
|
- [開発](#開発)
|
||||||
|
- [独自のプラグインを作成する](#独自のプラグインを作成する)
|
||||||
|
- [プラグインの作成](#プラグインの作成)
|
||||||
|
- [一般的な使用例](#一般的な使用例)
|
||||||
|
- [ビルド](#ビルド)
|
||||||
|
- [プロダクションプレビュー](#プロダクションプレビュー)
|
||||||
|
- [テスト](#テスト)
|
||||||
|
- [ライセンス](#ライセンス)
|
||||||
|
- [FAQ](#faq)
|
||||||
|
|
||||||
|
## 機能:
|
||||||
|
|
||||||
|
- **一時停止時の自動確認** (常に有効): 一定時間後に音楽を一時停止する["視聴を続けますか?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png)ポップアップを無効にします
|
||||||
|
|
||||||
|
- その他の機能...
|
||||||
|
|
||||||
|
## 利用可能なプラグイン:
|
||||||
|
|
||||||
|
- **広告ブロッカー**: すべての広告とトラッキングをブロックします
|
||||||
|
|
||||||
|
- **アルバムアクション**: プレイリストやアルバム内のすべての曲に「嫌いではない」「嫌い」「好き」「好きではない」ボタンを追加します
|
||||||
|
|
||||||
|
- **アルバムカラーテーマ**: アルバムのカラーパレットに基づいて動的なテーマと視覚効果を適用します
|
||||||
|
|
||||||
|
- **アンビエントモード**: 動画から柔らかい色を画面の背景に投影するライティング効果を適用します
|
||||||
|
|
||||||
|
- **<2A><><EFBFBD>ーディオコンプレッサー**: オーディオにコンプレッションを適用します(信号の最も大きな部分の音量を下げ、最も小さな部分の音量を上げます)
|
||||||
|
|
||||||
|
- **ナビゲーションバーのぼかし**: ナビゲーションバーを透明でぼやけたものにします
|
||||||
|
|
||||||
|
- **年齢制限の回避**: YouTubeの年齢確認を回避します
|
||||||
|
|
||||||
|
- **字幕選択**: 字幕を有効にします
|
||||||
|
|
||||||
|
- **コンパクトサイドバー**: サイドバーを常にコンパクトモードに設定します
|
||||||
|
|
||||||
|
- **クロスフェード**: 曲間にクロスフェードを適用します
|
||||||
|
|
||||||
|
- **自動再生の無効化**: すべての曲を「一時停止」モードで開始します
|
||||||
|
|
||||||
|
- **[Discord](https://discord.com/) リッチプレゼンス**: [リッチプレゼンス](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)を使用して、友達にあなたが聴いている曲を表示します
|
||||||
|
|
||||||
|
- **ダウンローダー**: UIから直接MP3/ソースオーディオをダウンロードします
|
||||||
|
|
||||||
|
- **イコライザー**: 特定の周波数範囲をブーストまたはカットするフィルターを追加します(例: ベースブースター)
|
||||||
|
|
||||||
|
- **指数音量**: 音量スライダーを[指数関数的](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**: プレイリストを他の人と共有します。ホストが曲を再生すると、他の全員が同じ曲を聴くことができます
|
||||||
|
|
||||||
|
- **ナビゲーション**: お気に入りのブラウザのように、UIに直接統合された次/前のナビゲーション矢印を追加します
|
||||||
|
|
||||||
|
- **Googleログインなし**: インターフェースからGoogleログインボタンとリンクを削除します
|
||||||
|
|
||||||
|
- **通知**: 曲の再生が開始されると通知を表示します(Windowsでは[インタラクティブ通知](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png)が利用可能です)
|
||||||
|
|
||||||
|
- **ピクチャーインピクチャー**: アプリをピクチャーインピクチャーモードに切り替えることができます
|
||||||
|
|
||||||
|
- **再生速度**: 速く聴いたり、遅く聴いたりできます!曲の速度を制御するスライダーを追加します
|
||||||
|
|
||||||
|
- **正確な音量**: カスタムHUDとカスタマイズ可能な音量ステップを使用して、マウスホイール/ホットキーで音量を正確に制御します
|
||||||
|
|
||||||
|
- **ショートカット (& MPRIS)**: 再生用のグローバルホットキー(再生/一時停止/次/前)を設定し、メディアキーをオーバーライドしてメディアOSDを無効にし、Ctrl/CMD + Fで検索を有効にし、LinuxのMPRISサポートを有効にし、[上級ユーザー](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)向けの[カスタムホットキー](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50)を追加します
|
||||||
|
|
||||||
|
- **嫌いな曲をスキップ**: 嫌いな曲をスキップします
|
||||||
|
|
||||||
|
- **無音部分をスキップ**: 無音部分を自動的にスキップします
|
||||||
|
|
||||||
|
- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): イントロ/アウトロなどの音楽以外の部分や、曲が再生されていないミュージックビデオの部分を自動的にスキップします
|
||||||
|
|
||||||
|
- **同期歌詞**: [LRClib](https://lrclib.net)のようなプロバイダーを使用して、曲に同期した歌詞を提供します
|
||||||
|
|
||||||
|
- **タスクバーメディアコントロール**: [Windowsタスクバー](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)から再生を制御します
|
||||||
|
|
||||||
|
- **TouchBar**: macOS用のカスタムTouchBarレイアウト
|
||||||
|
|
||||||
|
- **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)を追加します。オプションでビデオタブ全体を削除することもできます
|
||||||
|
|
||||||
|
- **ビジュアライザー**: プレイヤーにさまざまな音楽ビジュアライザーを追加します
|
||||||
|
|
||||||
|
## 翻訳
|
||||||
|
|
||||||
|
[Hosted Weblate](https://hosted.weblate.org/projects/youtube-music/)で翻訳を手伝うことができます。
|
||||||
|
|
||||||
|
<a href="https://hosted.weblate.org/engage/youtube-music/">
|
||||||
|
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/multi-auto.svg" alt="翻訳状況" />
|
||||||
|
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="翻訳状況 2" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## ダウンロード
|
||||||
|
|
||||||
|
[最新リリース](https://github.com/th-ch/youtube-music/releases/latest)を確認して、最新バージョンをすばやく見つけることができます。
|
||||||
|
|
||||||
|
### Arch Linux
|
||||||
|
|
||||||
|
AURから[`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin)パッケージをインストールします。AURのインストール手順については、この[wikiページ](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages)を参照してください。
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
Homebrewを使用してアプリをインストールできます([cask定義](https://github.com/th-ch/homebrew-youtube-music)を参照)。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install th-ch/youtube-music/youtube-music
|
||||||
|
```
|
||||||
|
|
||||||
|
アプリを手動でインストールし、アプリの起動時に「破損しているため開けません」というエラーが表示される場合は、ターミナルで次のコマンドを実行します。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/usr/bin/xattr -cr /Applications/YouTube\ Music.app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
[Scoopパッケージマネージャー](https://scoop.sh)を使用して、[`extras`バケット](https://github.com/ScoopInstaller/Extras)から`youtube-music`パッケージをインストールできます。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scoop bucket add extras
|
||||||
|
scoop install extras/youtube-music
|
||||||
|
```
|
||||||
|
|
||||||
|
または、Windows 11の公式CLIパッケージマネージャーである[Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)を使用して、`th-ch.YouTubeMusic`パッケージをインストールできます。
|
||||||
|
|
||||||
|
*注: 「不明な発行元」からのものであるため、Microsoft Defender SmartScreenがインストールをブロックする場合があります。これは、GitHubで手動でダウンロードした後に実行ファイル(.exe)を実行しようとする場合にも当てはまります。*
|
||||||
|
|
||||||
|
```bash
|
||||||
|
winget install th-ch.YouTubeMusic
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ネットワーク接続なしでインストールする方法 (Windows)
|
||||||
|
|
||||||
|
- [リリースページ](https://github.com/th-ch/youtube-music/releases/latest)で_デバイスのアーキテクチャ_に対応する`*.nsis.7z`ファイルをダウンロードします。
|
||||||
|
- `x64`は64ビットWindows用
|
||||||
|
- `ia32`は32ビットWindows用
|
||||||
|
- `arm64`はARM64 Windows用
|
||||||
|
- リリースページでインストーラーをダウンロードします。(`*-Setup.exe`)
|
||||||
|
- それらを**同じディレクトリ**に配置します。
|
||||||
|
- インストーラーを実行します。
|
||||||
|
|
||||||
|
## テーマ
|
||||||
|
|
||||||
|
CSSファイルを読み込んでアプリケーションの外観を変更できます(オプション > 視覚的調整 > テーマ)。
|
||||||
|
|
||||||
|
いくつかの事前定義されたテーマは、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
|
||||||
|
```
|
||||||
|
|
||||||
|
## 独自のプラグインを作成する
|
||||||
|
|
||||||
|
プラグインを使用すると、次のことができます。
|
||||||
|
|
||||||
|
- アプリを操作する - Electronの`BrowserWindow`がプラグインハンドラーに渡されます
|
||||||
|
- HTML/CSSを操作してフロントエンドを変更する
|
||||||
|
|
||||||
|
### プラグインの作成
|
||||||
|
|
||||||
|
`src/plugins/YOUR-PLUGIN-NAME`にフォルダーを作成します。
|
||||||
|
|
||||||
|
- `index.ts`: プラグインのメインファイル
|
||||||
|
```typescript
|
||||||
|
import style from './style.css?inline'; // スタイルをインラインとしてインポート
|
||||||
|
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: 'プラグインラベル',
|
||||||
|
restartNeeded: true, // 値がtrueの場合、ytmusicは再起動ダイアログを表示します
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // カスタム設定
|
||||||
|
stylesheets: [style], // カスタムスタイル
|
||||||
|
menu: async ({ getConfig, setConfig }) => {
|
||||||
|
// すべての*ConfigメソッドはPromise<T>でラップされています
|
||||||
|
const config = await getConfig();
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'メニュー',
|
||||||
|
submenu: [1, 2, 3].map((value) => ({
|
||||||
|
label: `値 ${value}`,
|
||||||
|
type: 'radio',
|
||||||
|
checked: config.value === value,
|
||||||
|
click() {
|
||||||
|
setConfig({ value });
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
backend: {
|
||||||
|
start({ window, ipc }) {
|
||||||
|
window.maximize();
|
||||||
|
|
||||||
|
// レンダラープラグインと通信できます
|
||||||
|
ipc.handle('some-event', () => {
|
||||||
|
return 'hello';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 設定が変更されたときに発生します
|
||||||
|
onConfigChange(newConfig) { /* ... */ },
|
||||||
|
// プラグインが無効になったときに発生します
|
||||||
|
stop(context) { /* ... */ },
|
||||||
|
},
|
||||||
|
renderer: {
|
||||||
|
async start(context) {
|
||||||
|
console.log(await context.ipc.invoke('some-event'));
|
||||||
|
},
|
||||||
|
// レンダラーでのみ使用可能なフック
|
||||||
|
onPlayerApiReady(api: YoutubePlayer, context: RendererContext) {
|
||||||
|
// プラグイン設定を簡単に設定
|
||||||
|
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 { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: 'プラグインラベル',
|
||||||
|
restartNeeded: true, // 値がtrueの場合、ytmusicは再起動ダイアログを表示します
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // カスタム設定
|
||||||
|
stylesheets: [style], // カスタムスタイル
|
||||||
|
renderer() {} // レンダラーフックを定義
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- HTMLを変更したい場合:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: 'プラグインラベル',
|
||||||
|
restartNeeded: true, // 値がtrueの場合、ytmusicは再起動ダイアログを表示します
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // カスタム設定
|
||||||
|
renderer() {
|
||||||
|
// ログインボタンを削除
|
||||||
|
document.querySelector(".sign-in-link.ytmusic-nav-bar").remove();
|
||||||
|
} // レンダラーフックを定義
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- フロントエンドとバックエンドの通信: ElectronのipcMainモジュールを使用して行うことができます。`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 (Debian用arm64)
|
||||||
|
- `pnpm dist:linux:rpm-arm64` - Linux (Fedora用arm64)
|
||||||
|
- `pnpm dist:mac` - macOS (amd64)
|
||||||
|
- `pnpm dist:mac:arm64` - macOS (arm64)
|
||||||
|
|
||||||
|
[electron-builder](https://github.com/electron-userland/electron-builder)を使用して、macOS、Linux、およびWindows用のアプリをビルドします。
|
||||||
|
|
||||||
|
## プロダクションプレビュー
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm start
|
||||||
|
```
|
||||||
|
|
||||||
|
## テスト
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm test
|
||||||
|
```
|
||||||
|
|
||||||
|
[Playwright](https://playwright.dev/)を使用してアプリをテストします。
|
||||||
|
|
||||||
|
## ライセンス
|
||||||
|
|
||||||
|
MIT © [th-ch](https://github.com/th-ch/youtube-music)
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### アプリのメニューが表示されないのはなぜですか?
|
||||||
|
|
||||||
|
`メニューを非表示`オプションがオンの場合 - <kbd>alt</kbd>キー(またはアプリ内メニュープラグインを使用している場合は<kbd>\`</kbd> [バックティック]キー)でメニューを表示できます
|
||||||
@ -3,7 +3,7 @@
|
|||||||
# 유튜브 뮤직 (YouTube Music)
|
# 유튜브 뮤직 (YouTube Music)
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -20,7 +20,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
다른 언어로 읽어보세요: [🏴 영어](../../README.md), [🇰🇷 한국인](./README-ko.md), [🇫🇷 프랑스 국민](./README-fr.md), [🇮🇸 아이슬란드어](./README-is.md), [🇪🇸 스페인 사람](./README-es.md), [🇷🇺 러시아인](./README-ru.md)
|
다른 언어로 읽어보세요: [🏴 영어](../../README.md), [🇰🇷 한국인](./README-ko.md), [🇫🇷 프랑스 국민](./README-fr.md), [🇮🇸 아이슬란드어](./README-is.md), [🇪🇸 스페인 사람](./README-es.md), [🇷🇺 러시아인](./README-ru.md), [🇧🇷 포르투갈어](./README-pt.md), [🇯🇵 일본어](./README-ja.md)
|
||||||
|
|
||||||
**유튜브 뮤직의 Electron 래퍼; 기능:**
|
**유튜브 뮤직의 Electron 래퍼; 기능:**
|
||||||
|
|
||||||
|
|||||||
375
docs/readme/README-pt.md
Normal file
375
docs/readme/README-pt.md
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
<div align="center">
|
||||||
|
|
||||||
|
# YouTube Music
|
||||||
|
|
||||||
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://aur.archlinux.org/packages/youtube-music-bin)
|
||||||
|
[](https://snyk.io/test/github/th-ch/youtube-music)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
Leia em outros idiomas: [🏴 Inglês](../../README.md), [🇰🇷 Coreano](./README-ko.md), [🇫🇷 Francês](./README-fr.md), [🇮🇸 Islandês](./README-is.md), [🇪🇸 Espanhol](./README-es.md), [🇷🇺 Russo](./README-ru.md), [🇧🇷 Português](./README-pt.md)
|
||||||
|
|
||||||
|
**Wrapper do Electron para o YouTube Music com os seguintes recursos:**
|
||||||
|
|
||||||
|
- Visual e comportamento nativos: Mantém a interface original do YouTube Music.
|
||||||
|
- Estrutura para plugins personalizados: Adapte o YouTube Music às suas necessidades (estilo, conteúdo, funcionalidades). Ative/desative plugins com um clique.
|
||||||
|
|
||||||
|
## Imagem de demonstração
|
||||||
|
|
||||||
|
| Tela do Player (tema de cores do álbum e luz ambiente) |
|
||||||
|
|:---------------------------------------------------------------------------------------------------------:|
|
||||||
|
||
|
||||||
|
|
||||||
|
## Conteúdo
|
||||||
|
|
||||||
|
- [Recursos](#recursos)
|
||||||
|
- [Plugins disponíveis](#plugins-disponíveis)
|
||||||
|
- [Tradução](#tradução)
|
||||||
|
- [Download](#download)
|
||||||
|
- [Arch Linux](#arch-linux)
|
||||||
|
- [MacOS](#macos)
|
||||||
|
- [Windows](#windows)
|
||||||
|
- [Como instalar sem conexão à internet? (no Windows)](#como-instalar-sem-conexão-à-internet-no-windows)
|
||||||
|
- [Temas](#temas)
|
||||||
|
- [Dev](#dev)
|
||||||
|
- [Crie seus próprios plugins](#crie-seus-próprios-plugins)
|
||||||
|
- [Criando um plugin](#criando-um-plugin)
|
||||||
|
- [Casos de uso comuns](#casos-de-uso-comuns)
|
||||||
|
- [Compilar](#compilar)
|
||||||
|
- [Prévia de produção](#prévia-de-produção)
|
||||||
|
- [Testes](#testes)
|
||||||
|
- [Licença](#licença)
|
||||||
|
- [Perguntas Frequentes](#perguntas-frequentes)
|
||||||
|
|
||||||
|
## Recursos:
|
||||||
|
|
||||||
|
- **Confirmação automática quando pausado** (Sempre ativado): desativa
|
||||||
|
o popup ["Continuar assistindo?"](https://user-images.githubusercontent.com/61631665/129977894-01c60740-7ec6-4bf0-9a2c-25da24491b0e.png)
|
||||||
|
que pausa a música após um certo tempo
|
||||||
|
|
||||||
|
- E mais...
|
||||||
|
|
||||||
|
## Plugins disponíveis:
|
||||||
|
|
||||||
|
- **Bloqueador de anúncios**: Bloqueia todos os anúncios e rastreamentos automaticamente
|
||||||
|
|
||||||
|
- **Ações de Álbum**: Adiciona botões para Remover dislike, Dar dislike, Curtir e Remover curtida em todas as músicas de uma playlist ou álbum
|
||||||
|
|
||||||
|
- **Tema de cores do álbum**: Aplica um tema dinâmico e efeitos visuais baseados na paleta de cores do álbum
|
||||||
|
|
||||||
|
- **Modo ambiente**: Cria um efeito de iluminação projetando cores suaves do vídeo no fundo da tela
|
||||||
|
|
||||||
|
- **Compressor de áudio**: Aplica compressão ao áudio (reduz o volume das partes mais altas e aumenta o das mais baixas)
|
||||||
|
|
||||||
|
- **Barra de navegação desfocada**: Torna a barra de navegação transparente e desfocada
|
||||||
|
|
||||||
|
- **Contornar restrições de idade**: Ignora a verificação de idade do YouTube
|
||||||
|
|
||||||
|
- **Seletor de legendas**: Ativa legendas
|
||||||
|
|
||||||
|
- **Barra lateral compacta**: Mantém a barra lateral sempre no modo compacto
|
||||||
|
|
||||||
|
- **Crossfade**: Transição suave entre músicas
|
||||||
|
|
||||||
|
- **Desativar reprodução automática**: Faz com que todas as músicas iniciem no modo "pausado"
|
||||||
|
|
||||||
|
- **[Discord](https://discord.com/) Rich Presence**: Mostra para seus amigos o que você está ouvindo com [Rich Presence](https://user-images.githubusercontent.com/28219076/104362104-a7a0b980-5513-11eb-9744-bb89eabe0016.png)
|
||||||
|
|
||||||
|
- **Downloader**: Baixa MP3 [diretamente da interface](https://user-images.githubusercontent.com/61631665/129977677-83a7d067-c192-45e1-98ae-b5a4927393be.png) [(youtube-dl)](https://github.com/ytdl-org/youtube-dl)
|
||||||
|
|
||||||
|
- **Equalizador**: Adiciona filtros para aumentar ou reduzir faixas específicas de frequência (ex: reforço de graves)
|
||||||
|
|
||||||
|
- **Volume exponencial**: Torna o controle de volume [exponencial](https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/) para facilitar a seleção de volumes mais baixos
|
||||||
|
|
||||||
|
- **Menu integrado**: [Dá às barras um visual elegante e escuro](https://user-images.githubusercontent.com/78568641/112215894-923dbf00-8c29-11eb-95c3-3ce15db27eca.png)
|
||||||
|
|
||||||
|
> (veja [este post](https://github.com/th-ch/youtube-music/issues/410#issuecomment-952060709) se tiver problemas para acessar o menu após ativar este plugin e a opção de ocultar menu)
|
||||||
|
|
||||||
|
- **Scrobbler**: Adiciona suporte para scrobbling no [Last.fm](https://www.last.fm/) e [ListenBrainz](https://listenbrainz.org/)
|
||||||
|
|
||||||
|
- **Lumia Stream**: Adiciona suporte para [Lumia Stream](https://lumiastream.com/)
|
||||||
|
|
||||||
|
- **Letras Genius**: Adiciona suporte a letras para a maioria das músicas
|
||||||
|
|
||||||
|
- **Música Juntos**: Compartilhe uma playlist com outros. Quando o host toca uma música, todos ouvem a mesma música
|
||||||
|
|
||||||
|
- **Navegação**: Botões de avançar/voltar integrados diretamente na interface, como no seu navegador favorito
|
||||||
|
|
||||||
|
- **Sem login do Google**: Remove botões e links de login do Google da interface
|
||||||
|
|
||||||
|
- **Notificações**: Exibe uma notificação quando uma música começa a tocar ([notificações interativas](https://user-images.githubusercontent.com/78568641/114102651-63ce0e00-98d0-11eb-9dfe-c5a02bb54f9c.png) disponíveis no Windows)
|
||||||
|
|
||||||
|
- **Picture-in-picture**: Permite alternar o aplicativo para o modo picture-in-picture
|
||||||
|
|
||||||
|
- **Velocidade de reprodução**: Ouça rápido, ouça devagar! [Adiciona um controle deslizante para ajustar a velocidade](https://user-images.githubusercontent.com/61631665/129976003-e55db5ba-bf42-448c-a059-26a009775e68.png)
|
||||||
|
|
||||||
|
- **Volume preciso**: Controle o volume com precisão usando roda do mouse/atalhos, com HUD personalizado e níveis de volume customizáveis
|
||||||
|
|
||||||
|
- **Atalhos (& MPRIS)**: Permite configurar teclas de atalho globais para controle (play/pause/próxima/anterior) + desativa [OSD de mídia](https://user-images.githubusercontent.com/84923831/128601225-afa38c1f-dea8-4209-9f72-0f84c1dd8b54.png) sobrescrevendo teclas de mídia + ativa Ctrl/CMD + F para busca + suporte a MPRIS no Linux para teclas de mídia + [atalhos personalizados](https://github.com/Araxeus/youtube-music/blob/1e591d6a3df98449bcda6e63baab249b28026148/providers/song-controls.js#L13-L50) para [usuários avançados](https://github.com/th-ch/youtube-music/issues/106#issuecomment-952156902)
|
||||||
|
|
||||||
|
- **Pular músicas marcadas com "não gostei"**: Ignora automaticamente músicas que você deu dislike
|
||||||
|
|
||||||
|
- **Pular silêncios**: Ignora automaticamente seções silenciosas
|
||||||
|
|
||||||
|
- [**SponsorBlock**](https://github.com/ajayyy/SponsorBlock): Ignora automaticamente partes não musicais como introduções/outros ou partes de clipes onde a música não está tocando
|
||||||
|
|
||||||
|
- **Letras sincronizadas**: Fornece letras sincronizadas para músicas, usando serviços como [LRClib](https://lrclib.net)
|
||||||
|
|
||||||
|
- **Controle de mídia na barra de tarefas**: Controle a reprodução pela [barra de tarefas do Windows](https://user-images.githubusercontent.com/78568641/111916130-24a35e80-8a82-11eb-80c8-5021c1aa27f4.png)
|
||||||
|
|
||||||
|
- **TouchBar**: Layout personalizado para a TouchBar do macOS
|
||||||
|
|
||||||
|
- **Tuna OBS**: Integração com o plugin [Tuna](https://obsproject.com/forum/resources/tuna.843/) do [OBS](https://obsproject.com/)
|
||||||
|
|
||||||
|
- **Seletor de qualidade de vídeo**: Permite alterar a qualidade do vídeo com um [botão](https://user-images.githubusercontent.com/78568641/138574366-70324a5e-2d64-4f6a-acdd-dc2a2b9cecc5.png) na sobreposição do vídeo
|
||||||
|
|
||||||
|
- **Alternar vídeo**: Adiciona um [botão](https://user-images.githubusercontent.com/28893833/173663950-63e6610e-a532-49b7-9afa-54cb57ddfc15.png) para alternar entre modos Vídeo/Música. Pode também remover completamente a aba de vídeo
|
||||||
|
|
||||||
|
- **Visualizador**: Diferentes visualizadores de música
|
||||||
|
|
||||||
|
## Tradução
|
||||||
|
|
||||||
|
Você pode ajudar com as traduções no [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="status da tradução" />
|
||||||
|
<img src="https://hosted.weblate.org/widget/youtube-music/i18n/287x66-black.png" alt="status da tradução 2" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Download
|
||||||
|
|
||||||
|
Você pode verificar o [último lançamento](https://github.com/th-ch/youtube-music/releases/latest) para encontrar rapidamente a versão mais recente.
|
||||||
|
|
||||||
|
### Arch Linux
|
||||||
|
|
||||||
|
Instale o pacote [`youtube-music-bin`](https://aur.archlinux.org/packages/youtube-music-bin) do AUR. Para instruções de instalação do AUR, consulte esta [página da wiki](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
Você pode instalar o aplicativo usando Homebrew (veja a [definição do cask](https://github.com/th-ch/homebrew-youtube-music)):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install th-ch/youtube-music/youtube-music
|
||||||
|
```
|
||||||
|
|
||||||
|
Se você instalar o aplicativo manualmente e receber o erro "is damaged and can’t be opened." ao abrir o app, execute o seguinte no Terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/usr/bin/xattr -cr /Applications/YouTube\ Music.app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
Você pode usar o [gerenciador de pacotes Scoop](https://scoop.sh) para instalar o pacote `youtube-music` do [`extras bucket`](https://github.com/ScoopInstaller/Extras).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scoop bucket add extras
|
||||||
|
scoop install extras/youtube-music
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternativamente, você pode usar o [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), o gerenciador de pacotes CLI oficial do Windows 11, para instalar o pacote `th-ch.YouTubeMusic`.
|
||||||
|
|
||||||
|
*Nota: O Microsoft Defender SmartScreen pode bloquear a instalação por ser de um "publicador desconhecido". Isso também acontece na instalação manual ao tentar executar o arquivo .exe após download manual aqui no GitHub (mesmo arquivo).*
|
||||||
|
|
||||||
|
```bash
|
||||||
|
winget install th-ch.YouTubeMusic
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Como instalar sem conexão à internet? (no Windows)
|
||||||
|
|
||||||
|
- Baixe o arquivo `*.nsis.7z` para _sua arquitetura de dispositivo_ na [página de lançamentos](https://github.com/th-ch/youtube-music/releases/latest).
|
||||||
|
- `x64` para Windows 64-bit
|
||||||
|
- `ia32` para Windows 32-bit
|
||||||
|
- `arm64` para Windows ARM64
|
||||||
|
- Baixe o instalador na página de lançamentos (`*-Setup.exe`)
|
||||||
|
- Coloque os arquivos no **mesmo diretório**
|
||||||
|
- Execute o instalador
|
||||||
|
|
||||||
|
## Temas
|
||||||
|
|
||||||
|
Você pode carregar arquivos CSS para alterar a aparência do aplicativo (Opções > Ajustes Visuais > Temas).
|
||||||
|
|
||||||
|
Alguns temas pré-definidos estão disponíveis em https://github.com/kerichdev/themes-for-ytmdesktop-player.
|
||||||
|
|
||||||
|
## Dev
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/th-ch/youtube-music
|
||||||
|
cd youtube-music
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Crie seus próprios plugins
|
||||||
|
|
||||||
|
Usando plugins, você pode:
|
||||||
|
|
||||||
|
- Manipular o aplicativo - o `BrowserWindow` do electron é passado para o manipulador de plugins
|
||||||
|
- Alterar a interface manipulando o HTML/CSS
|
||||||
|
|
||||||
|
### Criando um plugin
|
||||||
|
|
||||||
|
Crie uma pasta em `src/plugins/NOMBRE-DEL-PLUGIN`:
|
||||||
|
|
||||||
|
- `index.ts`: o arquivo principal do plugin
|
||||||
|
```typescript
|
||||||
|
import style from './style.css?inline'; // importar estilo como inline
|
||||||
|
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: "Plugin Label",
|
||||||
|
restartNeeded: true, // se true, o ytmusic mostra diálogo de reinício
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // sua configuração personalizada
|
||||||
|
stylesheets: [style], // seu estilo personalizado
|
||||||
|
menu: async ({ getConfig, setConfig }) => {
|
||||||
|
// Todos os métodos *Config são wrappers 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();
|
||||||
|
|
||||||
|
// você pode se comunicar com o plugin renderer
|
||||||
|
ipc.handle("some-event", () => {
|
||||||
|
return "hello";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// disparado quando a configuração muda
|
||||||
|
onConfigChange(newConfig) { /* ... */ },
|
||||||
|
// disparado quando o plugin é desativado
|
||||||
|
stop(context) { /* ... */ },
|
||||||
|
},
|
||||||
|
renderer: {
|
||||||
|
async start(context) {
|
||||||
|
console.log(await context.ipc.invoke("some-event"));
|
||||||
|
},
|
||||||
|
// Hook disponível apenas no renderer
|
||||||
|
onPlayerApiReady(api: YoutubePlayer, context: RendererContext) {
|
||||||
|
// establecer la configuración del plugin fácilmente
|
||||||
|
context.setConfig({ myConfig: api.getVolume() });
|
||||||
|
},
|
||||||
|
onConfigChange(newConfig) { /* ... */ },
|
||||||
|
stop(_context) { /* ... */ },
|
||||||
|
},
|
||||||
|
preload: {
|
||||||
|
async start({ getConfig }) {
|
||||||
|
const config = await getConfig();
|
||||||
|
},
|
||||||
|
onConfigChange(newConfig) {},
|
||||||
|
stop(_context) {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Casos de uso comuns
|
||||||
|
|
||||||
|
- **Injetar CSS personalizado**: crie um arquivo `style.css` na mesma pasta e então:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// index.ts
|
||||||
|
import style from './style.css?inline'; // importa estilo como inline
|
||||||
|
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: 'Plugin Label',
|
||||||
|
restartNeeded: true, // se true, o ytmusic mostrará um diálogo de reinício
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // sua configuração personalizada
|
||||||
|
stylesheets: [style], // seu estilo personalizado
|
||||||
|
renderer() {} // define o hook renderer
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Se quiser alterar o HTML:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: 'Plugin Label',
|
||||||
|
restartNeeded: true, // se true, o ytmusic mostrará o diálogo de reinício
|
||||||
|
config: {
|
||||||
|
enabled: false,
|
||||||
|
}, // sua configuração personalizada
|
||||||
|
renderer() {
|
||||||
|
// Remove o botão de login
|
||||||
|
document.querySelector(".sign-in-link.ytmusic-nav-bar").remove();
|
||||||
|
} // define o hook renderer
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- Comunicação entre front-end e back-end: pode ser feita usando o módulo ipcMain do Electron. Consulte o arquivo `index.ts` e o exemplo no plugin `sponsorblock`.
|
||||||
|
|
||||||
|
## Compilar
|
||||||
|
|
||||||
|
1. Clone o repositório
|
||||||
|
2. Siga [este guia](https://pnpm.io/installation) para instalar o `pnpm`
|
||||||
|
3. Execute `pnpm install --frozen-lockfile` para instalar as dependências
|
||||||
|
4. Execute `pnpm build:OS`
|
||||||
|
|
||||||
|
- `pnpm dist:win` - Windows
|
||||||
|
- `pnpm dist:linux` - Linux (amd64)
|
||||||
|
- `pnpm dist:linux:deb-arm64` - Linux (arm64 para Debian)
|
||||||
|
- `pnpm dist:linux:rpm-arm64` - Linux (arm64 para Fedora)
|
||||||
|
- `pnpm dist:mac` - macOS (amd64)
|
||||||
|
- `pnpm dist:mac:arm64` - macOS (arm64)
|
||||||
|
|
||||||
|
Compila o aplicativo para macOS, Linux e Windows,
|
||||||
|
usando [electron-builder](https://github.com/electron-userland/electron-builder).
|
||||||
|
|
||||||
|
## Prévia de Produção
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm test
|
||||||
|
```
|
||||||
|
|
||||||
|
Utiliza [Playwright](https://playwright.dev/) para testar o aplicativo.
|
||||||
|
|
||||||
|
## Licença
|
||||||
|
|
||||||
|
MIT © [th-ch](https://github.com/th-ch/youtube-music)
|
||||||
|
|
||||||
|
## Perguntas Frequentes
|
||||||
|
|
||||||
|
### Por que o menu do aplicativo não aparece?
|
||||||
|
|
||||||
|
Se a opção `Ocultar menu` estiver ativada - você pode exibir o menu com a tecla <kbd>alt</kbd> (ou <kbd>\`</kbd> [acento grave] se estiver usando o plugin in-app-menu)
|
||||||
@ -3,7 +3,7 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://github.com/th-ch/youtube-music/releases/)
|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
[](https://github.com/th-ch/youtube-music/blob/master/license)
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
[](https://github.com/th-ch/youtube-music/blob/master/.eslintrc.js)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
@ -21,7 +21,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Прочтите это на других языках: [🏴 Английский](../../README.md), [🇰🇷 корейский](./README-ko.md), [🇫🇷 Французский](./README-fr.md), [🇮🇸 исландский](./README-is.md), [🇪🇸 испанский](./README-es.md), [🇷🇺 Русский](./README-ru.md)
|
Прочтите это на других языках: [🏴 Английский](../../README.md), [🇰🇷 корейский](./README-ko.md), [🇫🇷 Французский](./README-fr.md), [🇮🇸 исландский](./README-is.md), [🇪🇸 испанский](./README-es.md), [🇷🇺 Русский](./README-ru.md), [🇧🇷 Португальский](./README-pt.md)
|
||||||
|
|
||||||
**Клиент для YouTube Music основанный на Electron с поддержкой:**
|
**Клиент для YouTube Music основанный на Electron с поддержкой:**
|
||||||
|
|
||||||
|
|||||||
63
package.json
63
package.json
@ -2,7 +2,7 @@
|
|||||||
"name": "youtube-music",
|
"name": "youtube-music",
|
||||||
"desktopName": "com.github.th_ch.youtube_music",
|
"desktopName": "com.github.th_ch.youtube_music",
|
||||||
"productName": "YouTube Music",
|
"productName": "YouTube Music",
|
||||||
"version": "3.8.0",
|
"version": "3.9.0",
|
||||||
"description": "YouTube Music Desktop App - including custom plugins",
|
"description": "YouTube Music Desktop App - including custom plugins",
|
||||||
"main": "./dist/main/index.js",
|
"main": "./dist/main/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -222,8 +222,8 @@
|
|||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"vite": "6.2.3",
|
"vite": "6.3.3",
|
||||||
"node-gyp": "11.1.0",
|
"node-gyp": "11.2.0",
|
||||||
"xml2js": "0.6.2",
|
"xml2js": "0.6.2",
|
||||||
"node-fetch": "3.3.2",
|
"node-fetch": "3.3.2",
|
||||||
"@electron/universal": "2.0.2",
|
"@electron/universal": "2.0.2",
|
||||||
@ -243,11 +243,11 @@
|
|||||||
"@ffmpeg.wasm/main": "0.12.0",
|
"@ffmpeg.wasm/main": "0.12.0",
|
||||||
"@floating-ui/dom": "1.6.13",
|
"@floating-ui/dom": "1.6.13",
|
||||||
"@foobar404/wave": "2.0.5",
|
"@foobar404/wave": "2.0.5",
|
||||||
"@ghostery/adblocker-electron": "2.5.0",
|
"@ghostery/adblocker-electron": "2.5.1",
|
||||||
"@ghostery/adblocker-electron-preload": "2.5.0",
|
"@ghostery/adblocker-electron-preload": "2.5.1",
|
||||||
"@hono/node-server": "1.14.0",
|
"@hono/node-server": "1.14.1",
|
||||||
"@hono/swagger-ui": "0.5.1",
|
"@hono/swagger-ui": "0.5.1",
|
||||||
"@hono/zod-openapi": "0.19.2",
|
"@hono/zod-openapi": "0.19.5",
|
||||||
"@hono/zod-validator": "0.4.3",
|
"@hono/zod-validator": "0.4.3",
|
||||||
"@jellybrick/dbus-next": "0.10.3",
|
"@jellybrick/dbus-next": "0.10.3",
|
||||||
"@jellybrick/electron-better-web-request": "1.0.4",
|
"@jellybrick/electron-better-web-request": "1.0.4",
|
||||||
@ -263,22 +263,23 @@
|
|||||||
"conf": "13.1.0",
|
"conf": "13.1.0",
|
||||||
"custom-electron-prompt": "1.5.8",
|
"custom-electron-prompt": "1.5.8",
|
||||||
"deepmerge-ts": "7.1.5",
|
"deepmerge-ts": "7.1.5",
|
||||||
|
"delay": "6.0.0",
|
||||||
"electron-debug": "4.1.0",
|
"electron-debug": "4.1.0",
|
||||||
"electron-is": "3.0.0",
|
"electron-is": "3.0.0",
|
||||||
"electron-localshortcut": "3.2.1",
|
"electron-localshortcut": "3.2.1",
|
||||||
"electron-store": "10.0.1",
|
"electron-store": "10.0.1",
|
||||||
"electron-unhandled": "4.0.1",
|
"electron-unhandled": "4.0.1",
|
||||||
"electron-updater": "6.3.9",
|
"electron-updater": "6.6.2",
|
||||||
"es-hangul": "2.3.2",
|
"es-hangul": "2.3.2",
|
||||||
"fast-average-color": "9.5.0",
|
"fast-average-color": "9.5.0",
|
||||||
"fast-equals": "5.2.2",
|
"fast-equals": "5.2.2",
|
||||||
"filenamify": "6.0.0",
|
"filenamify": "6.0.0",
|
||||||
"hanja": "1.1.4",
|
"hanja": "1.1.4",
|
||||||
"happy-dom": "17.4.4",
|
"happy-dom": "17.4.4",
|
||||||
"hono": "4.7.5",
|
"hono": "4.7.7",
|
||||||
"howler": "2.2.4",
|
"howler": "2.2.4",
|
||||||
"html-to-text": "9.0.5",
|
"html-to-text": "9.0.5",
|
||||||
"i18next": "24.2.3",
|
"i18next": "25.0.1",
|
||||||
"jimp": "1.6.0",
|
"jimp": "1.6.0",
|
||||||
"keyboardevent-from-electron-accelerator": "2.0.0",
|
"keyboardevent-from-electron-accelerator": "2.0.0",
|
||||||
"keyboardevents-areequal": "0.2.2",
|
"keyboardevents-areequal": "0.2.2",
|
||||||
@ -287,7 +288,7 @@
|
|||||||
"kuroshiro-analyzer-kuromoji": "1.1.0",
|
"kuroshiro-analyzer-kuromoji": "1.1.0",
|
||||||
"lazy-var": "2.2.2",
|
"lazy-var": "2.2.2",
|
||||||
"node-html-parser": "7.0.1",
|
"node-html-parser": "7.0.1",
|
||||||
"node-id3": "0.2.8",
|
"node-id3": "0.2.9",
|
||||||
"peerjs": "1.5.4",
|
"peerjs": "1.5.4",
|
||||||
"pinyin": "4.0.0-alpha.2",
|
"pinyin": "4.0.0-alpha.2",
|
||||||
"segmentit": "2.0.3",
|
"segmentit": "2.0.3",
|
||||||
@ -301,46 +302,46 @@
|
|||||||
"ts-morph": "25.0.1",
|
"ts-morph": "25.0.1",
|
||||||
"vudio": "2.1.1",
|
"vudio": "2.1.1",
|
||||||
"x11": "2.3.0",
|
"x11": "2.3.0",
|
||||||
"youtubei.js": "13.3.0",
|
"youtubei.js": "13.4.0",
|
||||||
"zod": "3.24.2"
|
"zod": "3.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.23.0",
|
"@eslint/js": "9.25.1",
|
||||||
"@malept/flatpak-bundler": "0.4.0",
|
"@malept/flatpak-bundler": "0.4.0",
|
||||||
"@playwright/test": "1.51.1",
|
"@playwright/test": "1.52.0",
|
||||||
"@stylistic/eslint-plugin-js": "4.2.0",
|
"@stylistic/eslint-plugin-js": "4.2.0",
|
||||||
"@total-typescript/ts-reset": "0.6.1",
|
"@total-typescript/ts-reset": "0.6.1",
|
||||||
"@types/electron-localshortcut": "3.1.3",
|
"@types/electron-localshortcut": "3.1.3",
|
||||||
"@types/howler": "2.2.12",
|
"@types/howler": "2.2.12",
|
||||||
"@types/html-to-text": "9.0.4",
|
"@types/html-to-text": "9.0.4",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.7.0",
|
||||||
"@types/trusted-types": "2.0.7",
|
"@types/trusted-types": "2.0.7",
|
||||||
"bufferutil": "4.0.9",
|
"bufferutil": "4.0.9",
|
||||||
"builtin-modules": "5.0.0",
|
"builtin-modules": "5.0.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"del-cli": "6.0.0",
|
"del-cli": "6.0.0",
|
||||||
"discord-api-types": "0.37.119",
|
"discord-api-types": "0.38.1",
|
||||||
"electron": "35.1.0",
|
"electron": "34.5.3",
|
||||||
"electron-builder": "26.0.12",
|
"electron-builder": "26.0.12",
|
||||||
"electron-builder-squirrel-windows": "26.0.12",
|
"electron-builder-squirrel-windows": "26.0.12",
|
||||||
"electron-devtools-installer": "4.0.0",
|
"electron-devtools-installer": "4.0.0",
|
||||||
"electron-vite": "3.1.0",
|
"electron-vite": "3.1.0",
|
||||||
"esbuild": "0.25.1",
|
"esbuild": "0.25.3",
|
||||||
"eslint": "9.23.0",
|
"eslint": "9.25.1",
|
||||||
"eslint-config-prettier": "10.1.1",
|
"eslint-config-prettier": "10.1.2",
|
||||||
"eslint-import-resolver-exports": "1.0.0-beta.5",
|
"eslint-import-resolver-exports": "1.0.0-beta.5",
|
||||||
"eslint-import-resolver-typescript": "4.2.4",
|
"eslint-import-resolver-typescript": "4.3.4",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-prettier": "5.2.5",
|
"eslint-plugin-prettier": "5.2.6",
|
||||||
"glob": "11.0.1",
|
"glob": "11.0.2",
|
||||||
"node-gyp": "11.1.0",
|
"node-gyp": "11.2.0",
|
||||||
"playwright": "1.51.1",
|
"playwright": "1.52.0",
|
||||||
"rollup": "4.37.0",
|
"rollup": "4.40.0",
|
||||||
"typescript": "5.8.2",
|
"typescript": "5.8.3",
|
||||||
"typescript-eslint": "8.28.0",
|
"typescript-eslint": "8.31.0",
|
||||||
"utf-8-validate": "6.0.5",
|
"utf-8-validate": "6.0.5",
|
||||||
"vite": "6.2.3",
|
"vite": "6.3.3",
|
||||||
"vite-plugin-inspect": "11.0.0",
|
"vite-plugin-inspect": "11.0.1",
|
||||||
"vite-plugin-resolve": "2.5.2",
|
"vite-plugin-resolve": "2.5.2",
|
||||||
"vite-plugin-solid": "2.11.6",
|
"vite-plugin-solid": "2.11.6",
|
||||||
"ws": "8.18.1"
|
"ws": "8.18.1"
|
||||||
|
|||||||
1355
pnpm-lock.yaml
generated
1355
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "أدخل رمز مستخدم ListenBrainz"
|
"token": "أدخل رمز مستخدم ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "استخدم عناوين بديلة",
|
||||||
"scrobble-other-media": "Scrobble الوسائط الأخرى"
|
"scrobble-other-media": "Scrobble الوسائط الأخرى"
|
||||||
},
|
},
|
||||||
"name": "أداة تتبع الاستماع",
|
"name": "أداة تتبع الاستماع",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "اجعل كلمات الأغنية متزامنة بشكل مثالي",
|
"label": "اجعل كلمات الأغنية متزامنة بشكل مثالي",
|
||||||
"tooltip": "احسب بدقة الملي ثانية عرض السطر التالي (قد يكون له تأثير طفيف على الأداء)"
|
"tooltip": "احسب بدقة الملي ثانية عرض السطر التالي (قد يكون له تأثير طفيف على الأداء)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "اجعل الكلمات رومانية",
|
||||||
|
"tooltip": "إذا كانت كلمات الأغنية بلغة مختلفة، حاول عرض نسخة بالحروف اللاتينية."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "أظهر كلمات الأغنية حتى لو كانت غير دقيقة",
|
"label": "أظهر كلمات الأغنية حتى لو كانت غير دقيقة",
|
||||||
"tooltip": "إذا لم يتم العثور على الأغنية، سوف يتم البحث مرة أخرى باستخدام استعلام بحث مختلف.\nقد لا تكون النتيجة من المحاولة الثانية دقيقة."
|
"tooltip": "إذا لم يتم العثور على الأغنية، سوف يتم البحث مرة أخرى باستخدام استعلام بحث مختلف.\nقد لا تكون النتيجة من المحاولة الثانية دقيقة."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "التكامل مع الإضافة\" Tuna\" الخاصة بـ OBS",
|
"description": "التكامل مع الإضافة\" Tuna\" الخاصة بـ OBS",
|
||||||
"name": "إضافة Tuna OBS"
|
"name": "إضافة Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "يمنع المشغل من الظهور عند تشغيل أغنية",
|
||||||
|
"name": "مشغل غير مزعج"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "يضيف زرًا للتبديل بين وضع الفيديو/الأغنية. يمكن أيضًا اختياريًا إزالة علامة الفيديو بالكامل",
|
"description": "يضيف زرًا للتبديل بين وضع الفيديو/الأغنية. يمكن أيضًا اختياريًا إزالة علامة الفيديو بالكامل",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -160,7 +160,7 @@
|
|||||||
"theme": {
|
"theme": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"button": {
|
"button": {
|
||||||
"cancel": "Откажи",
|
"cancel": "Отказ",
|
||||||
"remove": "Премахни"
|
"remove": "Премахни"
|
||||||
},
|
},
|
||||||
"remove-theme": "Сигурни ли сте, че искате да премахнете персонализираната тема?",
|
"remove-theme": "Сигурни ли сте, че искате да премахнете персонализираната тема?",
|
||||||
@ -182,24 +182,664 @@
|
|||||||
"new": "НОВО"
|
"new": "НОВО"
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"label": "Изглед",
|
"label": "Преглед",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"force-reload": "Презареди принудително",
|
"force-reload": "Принудително презареждане",
|
||||||
"reload": "Презареди",
|
"reload": "Презареди",
|
||||||
"reset-zoom": "Истински размер",
|
"reset-zoom": "Действителен размер",
|
||||||
"toggle-fullscreen": "Превключи на пълен екран",
|
"toggle-fullscreen": "Превключване на цял екран",
|
||||||
"zoom-in": "Увеличи",
|
"zoom-in": "Увеличаване",
|
||||||
"zoom-out": "Намали"
|
"zoom-out": "Намаляване"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tray": {
|
"tray": {
|
||||||
"next": "Следващ",
|
"next": "Следващ",
|
||||||
"play-pause": "Пусни/Паузирай",
|
"play-pause": "Възпроизвеждане/Пауза",
|
||||||
"previous": "Предишен",
|
"previous": "Предишен",
|
||||||
"quit": "Изход",
|
"quit": "Изход",
|
||||||
"restart": "Рестартирай приложението",
|
"restart": "Рестартирай приложението",
|
||||||
"show": "Покажи прозорец"
|
"show": "Покажи прозорец",
|
||||||
|
"tooltip": {
|
||||||
|
"default": "YouTube Музика",
|
||||||
|
"with-song-info": "YouTube Музика: {{artist}} - {{title}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"ad-speedup": {
|
||||||
|
"description": "Ако се пусне реклама, заглушава аудиото и задава скорост на възпроизвеждане 16x",
|
||||||
|
"name": "Ускоряване на рекламите"
|
||||||
|
},
|
||||||
|
"adblocker": {
|
||||||
|
"description": "Блокиране на всички реклами и проследяване по подразбиране",
|
||||||
|
"menu": {
|
||||||
|
"blocker": "Блокировач"
|
||||||
|
},
|
||||||
|
"name": "Блокировач на реклами"
|
||||||
|
},
|
||||||
|
"album-actions": {
|
||||||
|
"description": "Добавя бутони „Не харесвам“, „Харесвам“, „Харесано“ и „Премахване на харесване“, за да приложите това към всички песни в плейлист или албум",
|
||||||
|
"name": "Действия за албум"
|
||||||
|
},
|
||||||
|
"album-color-theme": {
|
||||||
|
"description": "Прилага динамична тема и визуални ефекти въз основа на цветовата палитра на албума",
|
||||||
|
"menu": {
|
||||||
|
"color-mix-ratio": {
|
||||||
|
"label": "Съотношение на смесване на цветовете",
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{ratio}}%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Цветова тема на албума"
|
||||||
|
},
|
||||||
|
"ambient-mode": {
|
||||||
|
"description": "Прилага светлинен ефект, като проектира нежни цветове от видеото върху фона на екрана",
|
||||||
|
"menu": {
|
||||||
|
"blur-amount": {
|
||||||
|
"label": "Степен на замъгляване",
|
||||||
|
"submenu": {
|
||||||
|
"pixels": "{{blurAmount}} пиксела"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer": {
|
||||||
|
"label": "Буферизация",
|
||||||
|
"submenu": {
|
||||||
|
"buffer": "{{buffer}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"opacity": {
|
||||||
|
"label": "Непрозрачност",
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{opacity}}%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quality": {
|
||||||
|
"label": "Качество",
|
||||||
|
"submenu": {
|
||||||
|
"pixels": "{{quality}} пиксела"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"label": "Размер",
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{size}}%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"smoothness-transition": {
|
||||||
|
"label": "Плавен преход",
|
||||||
|
"submenu": {
|
||||||
|
"during": "{{interpolationTime}} секунди"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"use-fullscreen": {
|
||||||
|
"label": "Използване на цял екран"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Атмосферен режим"
|
||||||
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "Добавя поддръжка на YouTube Music за джаджата Amuse Now Play от 6K Labs",
|
||||||
|
"name": "Забавление",
|
||||||
|
"response": {
|
||||||
|
"query": "Сървърът на Amuse API работи. Изпратете GET /query за информация за песента."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"api-server": {
|
||||||
|
"description": "Добавя API сървър за контрол на плейъра",
|
||||||
|
"dialog": {
|
||||||
|
"request": {
|
||||||
|
"buttons": {
|
||||||
|
"allow": "Разрешавам",
|
||||||
|
"deny": "Отказвам"
|
||||||
|
},
|
||||||
|
"message": "Позволяваш ли {{ID}} {{origin}} да достъпва API-то?",
|
||||||
|
"title": "Заявка за авторизация на API"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"auth-strategy": {
|
||||||
|
"label": "Стратегия за авторизация",
|
||||||
|
"submenu": {
|
||||||
|
"auth-at-first": {
|
||||||
|
"label": "Авторизиране при първата заявка"
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
"label": "Без авторизация"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hostname": {
|
||||||
|
"label": "Име на хост"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"label": "Порт"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "API сървър [Бета]",
|
||||||
|
"prompt": {
|
||||||
|
"hostname": {
|
||||||
|
"label": "Въведете името на хоста (като 0.0.0.0) за API сървъра:",
|
||||||
|
"title": "Име на хост"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"label": "Въведете порта за API сървъра:",
|
||||||
|
"title": "Порт"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"audio-compressor": {
|
||||||
|
"description": "Прилага компресия на аудиото (намалява обема на най-силните части от сигнала и увеличава обема на най-тихите части)",
|
||||||
|
"name": "Аудио компресор"
|
||||||
|
},
|
||||||
|
"blur-nav-bar": {
|
||||||
|
"description": "Прави навигационната лента прозрачна и размазана",
|
||||||
|
"name": "Размазанa навигационна лента"
|
||||||
|
},
|
||||||
|
"bypass-age-restrictions": {
|
||||||
|
"description": "Избягване на възрастова верификация на YouTube",
|
||||||
|
"name": "Избягване на възрастови ограничения"
|
||||||
|
},
|
||||||
|
"captions-selector": {
|
||||||
|
"description": "Избор на надписи за аудио тракове в YouTube Music",
|
||||||
|
"menu": {
|
||||||
|
"autoload": "Автоматично избиране на последно използвания надпис",
|
||||||
|
"disable-captions": "Без надписи по подразбиране"
|
||||||
|
},
|
||||||
|
"name": "Избор на надписи",
|
||||||
|
"prompt": {
|
||||||
|
"selector": {
|
||||||
|
"label": "Език на надписи: {{language}}",
|
||||||
|
"none": "Нищо",
|
||||||
|
"title": "Избери език на надписите"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"templates": {
|
||||||
|
"title": "Отвори избора на надписи"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compact-sidebar": {
|
||||||
|
"description": "Винаги настройвай страничната лента в компактен режим",
|
||||||
|
"name": "Компактна странична лента"
|
||||||
|
},
|
||||||
|
"crossfade": {
|
||||||
|
"description": "Плавно преминаване през песните",
|
||||||
|
"menu": {
|
||||||
|
"advanced": "Разширено"
|
||||||
|
},
|
||||||
|
"name": "Плавно преминаване [Beta]",
|
||||||
|
"prompt": {
|
||||||
|
"options": {
|
||||||
|
"multi-input": {
|
||||||
|
"fade-in-duration": "Продължителност на преливането (милисекунди)",
|
||||||
|
"fade-out-duration": "Продължителност на затихването (милисекунди)",
|
||||||
|
"fade-scaling": {
|
||||||
|
"label": "Скалиране на избледняването",
|
||||||
|
"linear": "Линейно",
|
||||||
|
"logarithmic": "Логаритмично"
|
||||||
|
},
|
||||||
|
"seconds-before-end": "Преливане N секунди преди края"
|
||||||
|
},
|
||||||
|
"title": "Опции за преливане"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"disable-autoplay": {
|
||||||
|
"description": "Започва песента в паузиран режим",
|
||||||
|
"menu": {
|
||||||
|
"apply-once": "Важи само на стартиране"
|
||||||
|
},
|
||||||
|
"name": "Изключи автоматичното пускане"
|
||||||
|
},
|
||||||
|
"discord": {
|
||||||
|
"backend": {
|
||||||
|
"already-connected": "Опит за свързване с активна връзка",
|
||||||
|
"connected": "Свързано с Discord",
|
||||||
|
"disconnected": "Прекъсната връзка с Discord"
|
||||||
|
},
|
||||||
|
"description": "Покажи на приятелите си какво слушате с Rich Presence",
|
||||||
|
"menu": {
|
||||||
|
"auto-reconnect": "Автоматично повторно свързване",
|
||||||
|
"clear-activity": "Изчистване на активността",
|
||||||
|
"clear-activity-after-timeout": "Изчистване на активността след изтичане на времето",
|
||||||
|
"connected": "Свързано",
|
||||||
|
"disconnected": "Прекъснато",
|
||||||
|
"hide-duration-left": "Скрий оставащото време",
|
||||||
|
"hide-github-button": "Скрий бутона за линк към GitHub",
|
||||||
|
"play-on-youtube-music": "Възпроизведи в YouTube Music",
|
||||||
|
"set-inactivity-timeout": "Задай таймаут за неактивност"
|
||||||
|
},
|
||||||
|
"name": "Дискорд Разширен статус",
|
||||||
|
"prompt": {
|
||||||
|
"set-inactivity-timeout": {
|
||||||
|
"label": "Въведете таймаута за неактивност в секунди:",
|
||||||
|
"title": "Задайте таймаут за неактивност"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"downloader": {
|
||||||
|
"backend": {
|
||||||
|
"dialog": {
|
||||||
|
"error": {
|
||||||
|
"buttons": {
|
||||||
|
"ok": "ОК"
|
||||||
|
},
|
||||||
|
"message": "Ох! Извинявайте, изтеглянето не успя…",
|
||||||
|
"title": "Грешка при изтегляне!"
|
||||||
|
},
|
||||||
|
"start-download-playlist": {
|
||||||
|
"buttons": {
|
||||||
|
"ok": "ОК"
|
||||||
|
},
|
||||||
|
"detail": "({{playlistSize}} песни)",
|
||||||
|
"message": "Изтегляне на плейлист {{playlistTitle}}",
|
||||||
|
"title": "Изтеглянето започна"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"feedback": {
|
||||||
|
"conversion-progress": "Конвертиране: {{percent}}%",
|
||||||
|
"converting": "Превръщане…",
|
||||||
|
"done": "Готово: {{filePath}}",
|
||||||
|
"download-info": "Изтегляне на {{artist}} - {{title}} [{{videoId}}",
|
||||||
|
"download-progress": "Изтегляне: {{percent}}%",
|
||||||
|
"downloading": "Изтегляне…",
|
||||||
|
"downloading-counter": "Изтегляне {{current}}/{{total}}…",
|
||||||
|
"downloading-playlist": "Изтегляне на плейлист \"{{playlistTitle}}\" - {{playlistSize}} песни ({{playlistId}})",
|
||||||
|
"error-while-downloading": "Грешка при изтегляне на \"{{author}} - {{title}}\": {{error}}",
|
||||||
|
"folder-already-exists": "Папката {{playlistFolder}} вече съществува",
|
||||||
|
"getting-playlist-info": "Получаване на информация за плейлист…",
|
||||||
|
"loading": "Зареждане…",
|
||||||
|
"playlist-has-only-one-song": "Плейлистът съдържа само един елемент, изтегля се директно",
|
||||||
|
"playlist-id-not-found": "Не е намерен ID на плейлист",
|
||||||
|
"playlist-is-empty": "Плейлистът е празен",
|
||||||
|
"playlist-is-mix-or-private": "Грешка при получаване на информация за плейлист: уверете се, че не е частен или \"Смесено за вас\" плейлист\n\n{{error}}",
|
||||||
|
"preparing-file": "Подготвяне на файла…",
|
||||||
|
"saving": "Записване…",
|
||||||
|
"trying-to-get-playlist-id": "Опитвам се да получа ID на плейлист: {{playlistId}}",
|
||||||
|
"video-id-not-found": "Видео не е намерено",
|
||||||
|
"writing-id3": "Записване на ID3 тагове…"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Изтегля MP3 / източниково аудио директно от интерфейса",
|
||||||
|
"menu": {
|
||||||
|
"choose-download-folder": "Изберете папка за изтегляне",
|
||||||
|
"download-finish-settings": {
|
||||||
|
"label": "Изтегляне при завършване",
|
||||||
|
"prompt": {
|
||||||
|
"last-percent": "След x процента",
|
||||||
|
"last-seconds": "Последни x секунди",
|
||||||
|
"title": "Конфигурирайте кога да изтеглите"
|
||||||
|
},
|
||||||
|
"submenu": {
|
||||||
|
"advanced": "Разширени настройки",
|
||||||
|
"enabled": "Активирано",
|
||||||
|
"mode": "Режим на време",
|
||||||
|
"percent": "Процент",
|
||||||
|
"seconds": "Секунди"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"download-playlist": "Изтегляне на плейлист",
|
||||||
|
"presets": "Предварително зададени настройки",
|
||||||
|
"skip-existing": "Пропусни съществуващите файлове"
|
||||||
|
},
|
||||||
|
"name": "Изтегляч",
|
||||||
|
"renderer": {
|
||||||
|
"can-not-update-progress": "Не може да се актуализира напредъкът"
|
||||||
|
},
|
||||||
|
"templates": {
|
||||||
|
"button": "Изтегляне"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"equalizer": {
|
||||||
|
"description": "Добавя еквалайзер към плеъра",
|
||||||
|
"menu": {
|
||||||
|
"presets": {
|
||||||
|
"label": "Предварителни настройки",
|
||||||
|
"list": {
|
||||||
|
"bass-booster": "Усилвател на басове"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Еквалайзер"
|
||||||
|
},
|
||||||
|
"exponential-volume": {
|
||||||
|
"description": "Прави плъзгача за сила на звука експоненциален, така че да е по-лесно да се избират по-ниски нива на звук.",
|
||||||
|
"name": "Експоненциален звук"
|
||||||
|
},
|
||||||
|
"in-app-menu": {
|
||||||
|
"description": "Придава на меню баровете стилен, тъмен или с цвят на албума вид",
|
||||||
|
"menu": {
|
||||||
|
"hide-dom-window-controls": "Скрий контролните елементи на DOM прозореца"
|
||||||
|
},
|
||||||
|
"name": "Меню в приложението"
|
||||||
|
},
|
||||||
|
"lumiastream": {
|
||||||
|
"description": "Добавя поддръжка за Lumia Stream",
|
||||||
|
"name": "Lumia Stream [Бета]"
|
||||||
|
},
|
||||||
|
"lyrics-genius": {
|
||||||
|
"description": "Добавя поддръжка за текстове за повечето песни",
|
||||||
|
"menu": {
|
||||||
|
"romanized-lyrics": "Романизирани текстове"
|
||||||
|
},
|
||||||
|
"name": "Текстове от Genius",
|
||||||
|
"renderer": {
|
||||||
|
"fetched-lyrics": "Изтеглени текстове от Genius"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"music-together": {
|
||||||
|
"description": "Сподели плейлист с други. Когато хостът пусне песен, всички останали ще чуят същата песен",
|
||||||
|
"dialog": {
|
||||||
|
"enter-host": "Въведи ID на хоста"
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"save": "Запазване",
|
||||||
|
"track-source": "Източник на трак",
|
||||||
|
"unknown-user": "Неизвестен потребител"
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"click-to-copy-id": "Копирай ID на хост",
|
||||||
|
"close": "Затвори Music Together",
|
||||||
|
"connected-users": "Свързани потребители",
|
||||||
|
"disconnect": "Прекъсни Music Together",
|
||||||
|
"empty-user": "Няма свързани потребители",
|
||||||
|
"host": "Хост на Music Together",
|
||||||
|
"join": "Присъедини се към Music Together",
|
||||||
|
"permission": {
|
||||||
|
"all": "Позволи на гостите да управляват плейлист и плеър",
|
||||||
|
"host-only": "Само хостът може да управлява плейлист и плеър",
|
||||||
|
"playlist": "Позволи на гостите да управляват плейлист"
|
||||||
|
},
|
||||||
|
"set-permission": "Промени разрешението за управление",
|
||||||
|
"status": {
|
||||||
|
"disconnected": "Прекъснато",
|
||||||
|
"guest": "Свързан като гост",
|
||||||
|
"host": "Свързан като хост"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Music Together [Бета]",
|
||||||
|
"toast": {
|
||||||
|
"add-song-failed": "Неуспешно добавяне на песен",
|
||||||
|
"closed": "Music Together е затворена",
|
||||||
|
"disconnected": "Music Together е прекъсната",
|
||||||
|
"host-failed": "Неуспешно хостване на Music Together",
|
||||||
|
"id-copied": "ID на хоста е копиран в клипборда",
|
||||||
|
"id-copy-failed": "Неуспешно копиране на ID на хоста в клипборда",
|
||||||
|
"join-failed": "Неуспешно присъединяване към Music Together",
|
||||||
|
"joined": "Присъединен към Music Together",
|
||||||
|
"permission-changed": "Разрешението за Music Together е променено на \"{{permission}}\"",
|
||||||
|
"remove-song-failed": "Неуспешно премахване на песен",
|
||||||
|
"user-connected": "{{name}} се присъедини към Music Together",
|
||||||
|
"user-disconnected": "{{name}} напусна Music Together"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"navigation": {
|
||||||
|
"description": "Навигационни стрелки Напред/Назад, директно интегрирани в интерфейса, както в любимия ви браузър",
|
||||||
|
"name": "Навигация"
|
||||||
|
},
|
||||||
|
"no-google-login": {
|
||||||
|
"description": "Премахни бутоните за вход с Google и връзките от интерфейса",
|
||||||
|
"name": "Няма вход с Google"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"description": "Показване на известие при стартиране на песен (интерактивни известия са налични за Windows)",
|
||||||
|
"menu": {
|
||||||
|
"interactive": "Интерактивни известия",
|
||||||
|
"interactive-settings": {
|
||||||
|
"label": "Интерактивни настройки",
|
||||||
|
"submenu": {
|
||||||
|
"hide-button-text": "Скрий текста на бутоните",
|
||||||
|
"refresh-on-play-pause": "Обновяване при Възпроизвеждане/Пауза",
|
||||||
|
"tray-controls": "Отваряне/Затваряне при клик в тавата"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": "Приоритет на известията",
|
||||||
|
"toast-style": "Стил на toast (кратки изскачащи известия)",
|
||||||
|
"unpause-notification": "Показване на известие при възобновяване"
|
||||||
|
},
|
||||||
|
"name": "Известия"
|
||||||
|
},
|
||||||
|
"picture-in-picture": {
|
||||||
|
"description": "Позволява превключване на приложението в режим картинка във картинка",
|
||||||
|
"menu": {
|
||||||
|
"always-on-top": "Винаги на преден план",
|
||||||
|
"hotkey": {
|
||||||
|
"label": "Клавишна комбинация",
|
||||||
|
"prompt": {
|
||||||
|
"keybind-options": {
|
||||||
|
"hotkey": "Клавишна комбинация"
|
||||||
|
},
|
||||||
|
"label": "Изберете клавишна комбинация за превключване на картинка във картинка",
|
||||||
|
"title": "Клавишна комбинация за картинка във картинка"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"save-window-position": "Запомняне на позицията на прозореца",
|
||||||
|
"save-window-size": "Запомняне на размера на прозореца",
|
||||||
|
"use-native-pip": "Използвайте вградения картинка във картинка на браузера"
|
||||||
|
},
|
||||||
|
"name": "Картинка във картинка",
|
||||||
|
"templates": {
|
||||||
|
"button": "Картинка във картинка"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"playback-speed": {
|
||||||
|
"description": "Слушай бързо, слушай бавно! Добавя плъзгач, който управлява скоростта на песните",
|
||||||
|
"name": "Скорост на възпроизвеждане",
|
||||||
|
"templates": {
|
||||||
|
"button": "Скорост"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"precise-volume": {
|
||||||
|
"description": "Управлявайте прецизно силата на звука чрез колелото на мишката или бързи клавиши, с персонализиран HUD и настройвани нива на звука",
|
||||||
|
"menu": {
|
||||||
|
"arrows-shortcuts": "Локални контроли със стрелки",
|
||||||
|
"custom-volume-steps": "Задайте персонализирани нива на звука",
|
||||||
|
"global-shortcuts": "Глобални бързи клавиши"
|
||||||
|
},
|
||||||
|
"name": "Точна сила на звука",
|
||||||
|
"prompt": {
|
||||||
|
"global-shortcuts": {
|
||||||
|
"keybind-options": {
|
||||||
|
"decrease": "Намаляване на звука",
|
||||||
|
"increase": "Усилване на звука"
|
||||||
|
},
|
||||||
|
"label": "Изберете глобални клавишни комбинации за сила на звука:",
|
||||||
|
"title": "Глобални клавишни комбинации за звук"
|
||||||
|
},
|
||||||
|
"volume-steps": {
|
||||||
|
"label": "Изберете стъпки за увеличаване/намаляване на звука",
|
||||||
|
"title": "Стъпки на звука"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quality-changer": {
|
||||||
|
"backend": {
|
||||||
|
"dialog": {
|
||||||
|
"quality-changer": {
|
||||||
|
"detail": "Текущо качество: {{quality}}",
|
||||||
|
"message": "Изберете качество на видеото:",
|
||||||
|
"title": "Изберете качество на видеото"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Позволява промяна на качеството на видеото с бутон върху видеото",
|
||||||
|
"name": "Промяна на качеството на видеото"
|
||||||
|
},
|
||||||
|
"scrobbler": {
|
||||||
|
"description": "Добавяне на скробблинг поддръжка (last.fm, Listenbrainz и т.н.)",
|
||||||
|
"dialog": {
|
||||||
|
"lastfm": {
|
||||||
|
"auth-failed": {
|
||||||
|
"message": "Грешка при удостоверяване с Last.fm\nСкрий изкачащия прозорец до следващо пускане.",
|
||||||
|
"title": "Грешка при удостоверяване"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"lastfm": {
|
||||||
|
"api-settings": "Настройки за Last.fm API"
|
||||||
|
},
|
||||||
|
"listenbrainz": {
|
||||||
|
"token": "Въведете ListenBrainz потребителски токен"
|
||||||
|
},
|
||||||
|
"scrobble-alternative-title": "Използвай алтернативни заглавия",
|
||||||
|
"scrobble-other-media": "Скробъл на други медии"
|
||||||
|
},
|
||||||
|
"name": "Скробълър",
|
||||||
|
"prompt": {
|
||||||
|
"lastfm": {
|
||||||
|
"api-key": "Last.fm API ключ",
|
||||||
|
"api-secret": "Last.fm API тайна"
|
||||||
|
},
|
||||||
|
"listenbrainz": {
|
||||||
|
"token": {
|
||||||
|
"label": "Въведете вашия ListenBrainz потребителски токен:",
|
||||||
|
"title": "ListenBrainz токен"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"description": "Позволява задаване на глобални бързи клавиши за възпроизвеждане (пускане/пауза/следваща/предишна), изключване на медиен OSD чрез презаписване на медийни клавиши, включване на Ctrl/CMD + F за търсене, включване на Linux MPRIS поддръжка за медийни клавиши и персонализирани бързи клавиши за напреднали потребители",
|
||||||
|
"menu": {
|
||||||
|
"override-media-keys": "Презаписване на медийни клавиши",
|
||||||
|
"set-keybinds": "Задайте глобални контроли за песни"
|
||||||
|
},
|
||||||
|
"name": "Клавишни комбинации (& MPRIS)",
|
||||||
|
"prompt": {
|
||||||
|
"keybind": {
|
||||||
|
"keybind-options": {
|
||||||
|
"next": "Следваща",
|
||||||
|
"play-pause": "Пусни / Пауза",
|
||||||
|
"previous": "Предишна"
|
||||||
|
},
|
||||||
|
"label": "Изберете глобални клавишни комбинации за контрол на песните:",
|
||||||
|
"title": "Глобални клавишни комбинации"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skip-disliked-songs": {
|
||||||
|
"description": "Прескача нехаресаните песни",
|
||||||
|
"name": "Прескачане на нехаресани песни"
|
||||||
|
},
|
||||||
|
"skip-silences": {
|
||||||
|
"description": "Автоматично прескачане на тихи участъци в песните",
|
||||||
|
"name": "Прескачане на тишини"
|
||||||
|
},
|
||||||
|
"sponsorblock": {
|
||||||
|
"description": "Автоматично прескача не-музикални части като встъпление/изход или части от музикални клипове, където песента не се пуска",
|
||||||
|
"name": "SponsorBlock"
|
||||||
|
},
|
||||||
|
"synced-lyrics": {
|
||||||
|
"description": "Предоставя синхронизирани текстове на песни, използвайки доставчици като LRClib.",
|
||||||
|
"errors": {
|
||||||
|
"fetch": "⚠️\tВъзникна грешка при извличане на текста.\n\tМоля, опитайте по-късно.",
|
||||||
|
"not-found": "⚠️ За тази песен не са намерени текстове."
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"default-text-string": {
|
||||||
|
"label": "Подразбиращ се знак между текстовете",
|
||||||
|
"tooltip": "Изберете знака, който да се използва за интервала между текстовете"
|
||||||
|
},
|
||||||
|
"line-effect": {
|
||||||
|
"label": "Линеен ефект",
|
||||||
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "Украсено",
|
||||||
|
"tooltip": "Използвайте големи, приложно-подобни ефекти на текущия ред"
|
||||||
|
},
|
||||||
|
"focus": {
|
||||||
|
"label": "Фокус",
|
||||||
|
"tooltip": "Направете само текущия ред бял"
|
||||||
|
},
|
||||||
|
"offset": {
|
||||||
|
"label": "Отместване",
|
||||||
|
"tooltip": "Отместване на текущия ред вдясно"
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"label": "Мащаб",
|
||||||
|
"tooltip": "Мащабирайте текущия ред"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tooltip": "Изберете ефекта, който да се приложи към текущия ред"
|
||||||
|
},
|
||||||
|
"precise-timing": {
|
||||||
|
"label": "Направете текстовете перфектно синхронизирани",
|
||||||
|
"tooltip": "Изчислете до милисекунда показването на следващия ред (може да има малък ефект върху производителността)"
|
||||||
|
},
|
||||||
|
"romanization": {
|
||||||
|
"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": "Управление на медията от лентата със задачи"
|
||||||
|
},
|
||||||
|
"touchbar": {
|
||||||
|
"description": "Добавя уиджет за TouchBar за потребители на macOS",
|
||||||
|
"name": "TouchBar"
|
||||||
|
},
|
||||||
|
"tuna-obs": {
|
||||||
|
"description": "Интеграция с плъгина Tuna за OBS",
|
||||||
|
"name": "Tuna OBS"
|
||||||
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Предотвратява изскачането на плеъра при възпроизвеждане на песен",
|
||||||
|
"name": "Неназойлив плеър"
|
||||||
|
},
|
||||||
|
"video-toggle": {
|
||||||
|
"description": "Добавя бутон за превключване между видео/песен режим. Също така може по избор да премахва целия раздел за видео",
|
||||||
|
"menu": {
|
||||||
|
"align": {
|
||||||
|
"label": "Подравняване",
|
||||||
|
"submenu": {
|
||||||
|
"left": "Ляво",
|
||||||
|
"middle": "В средата",
|
||||||
|
"right": "Дясно"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"force-hide": "Принудително премахване на раздела за видео",
|
||||||
|
"mode": {
|
||||||
|
"label": "Режим",
|
||||||
|
"submenu": {
|
||||||
|
"custom": "Персонализиран превключвател",
|
||||||
|
"disabled": "Изключено",
|
||||||
|
"native": "Вграден превключвател"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Превключване на видео",
|
||||||
|
"templates": {
|
||||||
|
"button": "Песен"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"visualizer": {
|
||||||
|
"description": "Добавя визуализатор към плеъра",
|
||||||
|
"menu": {
|
||||||
|
"visualizer-type": "Тип визуализатор"
|
||||||
|
},
|
||||||
|
"name": "Визуализатор"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
133
src/i18n/resources/bs.json
Normal file
133
src/i18n/resources/bs.json
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"console": {
|
||||||
|
"plugins": {
|
||||||
|
"execute-failed": "Greška u izvršavanju dodatka {{pluginName}}::{{contextName}}",
|
||||||
|
"executed-at-ms": "Dodatak {{pluginName}}::{{contextName}} se izvršio za {{ms}}ms",
|
||||||
|
"initialize-failed": "Greška prilikom inicijalizacije dodatka \"{{pluginName}}\"",
|
||||||
|
"load-all": "Učitavanje svih dodataka",
|
||||||
|
"load-failed": "Greška u učitavanju dodatka \"{{pluginName}}\"",
|
||||||
|
"loaded": "Dodatak \"{{pluginName}}\" učitan",
|
||||||
|
"unload-failed": "Greška prilikom onesposobljavanja dodatka \"{{pluginName}}\"",
|
||||||
|
"unloaded": "Dodatak \"{{pluginName}}\" ugašen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "ba",
|
||||||
|
"local-name": "Bosanski",
|
||||||
|
"name": "Bosnian"
|
||||||
|
},
|
||||||
|
"main": {
|
||||||
|
"console": {
|
||||||
|
"did-finish-load": {
|
||||||
|
"dev-tools": "Završeno učitavanje. DevTools otvoren"
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"loaded": "i18n učitan"
|
||||||
|
},
|
||||||
|
"second-instance": {
|
||||||
|
"receive-command": "Comanda primljena preko protokola \"{{command}}\""
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"css-file-not-found": "CSS datoteka \"{{cssFile}}\" ne postoji, ignorišem"
|
||||||
|
},
|
||||||
|
"unresponsive": {
|
||||||
|
"details": "Greška u aplikaciji!\n{{error}}"
|
||||||
|
},
|
||||||
|
"when-ready": {
|
||||||
|
"clearing-cache-after-20s": "Čistim predmemoriju aplikacije"
|
||||||
|
},
|
||||||
|
"window": {
|
||||||
|
"tried-to-render-offscreen": "Prozor se pokušao prikazati van okvira ekrana, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"hide-menu-enabled": {
|
||||||
|
"detail": "Meni je sakriven, koristite 'Alt' da ga prikazete (ili 'ESC' ako koristite meni u aplikaciji)",
|
||||||
|
"message": "Sakrivanje menija je uključeno",
|
||||||
|
"title": "Meni sakriven"
|
||||||
|
},
|
||||||
|
"need-to-restart": {
|
||||||
|
"buttons": {
|
||||||
|
"later": "Kasnije",
|
||||||
|
"restart-now": "Pokreni ponovo odmah"
|
||||||
|
},
|
||||||
|
"detail": "\"{{pluginName}}\" dodatak zahtjeva ponovno pokretanje kako bi se uključio",
|
||||||
|
"message": "\"{{pluginName}}\" potrebno je resetovat",
|
||||||
|
"title": "Restart je potreban"
|
||||||
|
},
|
||||||
|
"unresponsive": {
|
||||||
|
"buttons": {
|
||||||
|
"quit": "Napusti",
|
||||||
|
"relaunch": "Ponovo otvori",
|
||||||
|
"wait": "Pricekajte"
|
||||||
|
},
|
||||||
|
"detail": "Izvinjavamo se zbog zabune! molimo vas da odaberete sta zelite uciniti",
|
||||||
|
"message": "Aplikacija ne reagira",
|
||||||
|
"title": "Prozor ne reagira"
|
||||||
|
},
|
||||||
|
"update-available": {
|
||||||
|
"buttons": {
|
||||||
|
"disable": "Ugasite Nadogradnje",
|
||||||
|
"download": "Skinuti",
|
||||||
|
"ok": "OK"
|
||||||
|
},
|
||||||
|
"detail": "Nova verzija je dostupna i može biti skinuta na {{downloadLink}}",
|
||||||
|
"message": "Nova verzija je dostupna",
|
||||||
|
"title": "Azuriranje dostupno"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"about": "O nama",
|
||||||
|
"navigation": {
|
||||||
|
"label": "Plejer",
|
||||||
|
"submenu": {
|
||||||
|
"copy-current-url": "Kopirajte trenutni link",
|
||||||
|
"go-back": "Idi Nazad",
|
||||||
|
"go-forward": "Idi Naprijed",
|
||||||
|
"quit": "Izadji",
|
||||||
|
"restart": "Restartujte Aplikaciju"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"label": "Opcije",
|
||||||
|
"submenu": {
|
||||||
|
"advanced-options": {
|
||||||
|
"label": "Napredne opcije",
|
||||||
|
"submenu": {
|
||||||
|
"auto-reset-app-cache": "Resetuje kes memoriju kad se aplikacija pokrene",
|
||||||
|
"disable-hardware-acceleration": "Ugasite hardversko ubrzanje",
|
||||||
|
"edit-config-json": "Uredite config.json",
|
||||||
|
"override-user-agent": "Nadjacaj User-Agent",
|
||||||
|
"restart-on-config-changes": "Ponovno pokretanje nakon promjena konfiguracije",
|
||||||
|
"set-proxy": {
|
||||||
|
"label": "Postavi proxy",
|
||||||
|
"prompt": {
|
||||||
|
"label": "Unesite adresu proxyja: (ostavite prazno za onemogućavanje)",
|
||||||
|
"placeholder": "Primjer: SOCKS5://127.0.0.1:9999",
|
||||||
|
"title": "Postavi proxy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"toggle-dev-tools": "Uključi/isključi DevTools"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"always-on-top": "Uvijek na vrhu",
|
||||||
|
"auto-update": "Automatski Update",
|
||||||
|
"hide-menu": {
|
||||||
|
"dialog": {
|
||||||
|
"message": "Meni će biti skriven pri sljedećem pokretanju, koristite [Alt] da ga prikažete (ili upotrijebite [`] ako koristite meni u aplikaciji)",
|
||||||
|
"title": "Sakrij meni omogućen"
|
||||||
|
},
|
||||||
|
"label": "Sakrij meni"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"dialog": {
|
||||||
|
"message": "Jezik će se promijeniti nakon ponovnog pokretanja"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -768,6 +768,10 @@
|
|||||||
"label": "Den Songtext perfekt synchronisieren",
|
"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)"
|
"tooltip": "Auf die Millisekunde genau berechnen, wann die nächste Zeile angezeigt werden soll (Kann Einfluss auf die Leistung haben)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Lateinische Umschrift anzeigen",
|
||||||
|
"tooltip": "Wenn der Liedtext in einer anderen Schrift ist, zeige nach Möglichkeit eine Version in lateinischer Schrift an."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Zeige die Liedtexte, auch wenn sie ungenau sind.",
|
"label": "Zeige die Liedtexte, auch wenn sie ungenau sind.",
|
||||||
"tooltip": "Die Erweiterung sucht mit anderen Suchparameter nochmals, wenn der Song nicht gefunden wurde.\nEs kann sein, dass das Ergebnis von der zweiten Anfrage nicht genau ist."
|
"tooltip": "Die Erweiterung sucht mit anderen Suchparameter nochmals, wenn der Song nicht gefunden wurde.\nEs kann sein, dass das Ergebnis von der zweiten Anfrage nicht genau ist."
|
||||||
@ -800,6 +804,10 @@
|
|||||||
"description": "Integration mit dem OBS-Plugin Tuna",
|
"description": "Integration mit dem OBS-Plugin Tuna",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Verhindert das Aufpoppen des Spielers während ein Song gespielt wird",
|
||||||
|
"name": "Unauffälliger Player"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Fügt einen Knopf hinzu, um zwischen Video-/Liedmodus zu wechseln. kann auch genutzt werden, um den ganzen Videoabschnitt zu entfernen",
|
"description": "Fügt einen Knopf hinzu, um zwischen Video-/Liedmodus zu wechseln. kann auch genutzt werden, um den ganzen Videoabschnitt zu entfernen",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -59,11 +59,11 @@
|
|||||||
},
|
},
|
||||||
"unresponsive": {
|
"unresponsive": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"quit": "Έξοδος",
|
"quit": "Παραιτηθείτε",
|
||||||
"relaunch": "Επανεκκίνηση",
|
"relaunch": "Επανεκκίνηση",
|
||||||
"wait": "Περιμένετε"
|
"wait": "Περιμένετε"
|
||||||
},
|
},
|
||||||
"detail": "Λυπούμαστε για την ταλαιπωρία! Παρακαλούμε επιλέξτε τι να κάνετε:",
|
"detail": "Λυπούμαστε για την ταλαιπωρία! Παρακαλώ επιλέξτε τι να κάνετε:",
|
||||||
"message": "Η εφαρμογή δεν ανταποκρίνεται",
|
"message": "Η εφαρμογή δεν ανταποκρίνεται",
|
||||||
"title": "Το παράθυρο δεν ανταποκρίνεται"
|
"title": "Το παράθυρο δεν ανταποκρίνεται"
|
||||||
},
|
},
|
||||||
@ -75,7 +75,7 @@
|
|||||||
},
|
},
|
||||||
"detail": "Μια νέα έκδοση είναι διαθέσιμη και μπορεί να ληφθεί από τον σύνδεσμο {{downloadLink}}",
|
"detail": "Μια νέα έκδοση είναι διαθέσιμη και μπορεί να ληφθεί από τον σύνδεσμο {{downloadLink}}",
|
||||||
"message": "Μια νέα έκδοση είναι διαθέσιμη",
|
"message": "Μια νέα έκδοση είναι διαθέσιμη",
|
||||||
"title": "Υπάρχει διαθέσιμη ενημέρωση"
|
"title": "Διατίθεται ενημέρωση"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -84,8 +84,8 @@
|
|||||||
"label": "Πλοήγηση",
|
"label": "Πλοήγηση",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"copy-current-url": "Αντιγραφή τρέχουσας διεύθυνσης URL",
|
"copy-current-url": "Αντιγραφή τρέχουσας διεύθυνσης URL",
|
||||||
"go-back": "Πήγαινε πίσω",
|
"go-back": "Πίσω",
|
||||||
"go-forward": "Πήγαινε μπροστά",
|
"go-forward": "Εμπρός",
|
||||||
"quit": "Έξοδος",
|
"quit": "Έξοδος",
|
||||||
"restart": "Επανεκκίνηση εφαρμογής"
|
"restart": "Επανεκκίνηση εφαρμογής"
|
||||||
}
|
}
|
||||||
@ -94,17 +94,17 @@
|
|||||||
"label": "Επιλογές",
|
"label": "Επιλογές",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"advanced-options": {
|
"advanced-options": {
|
||||||
"label": "Προηγμένες επιλογές",
|
"label": "Επιλογές για προχωρημένους",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"auto-reset-app-cache": "Επαναφορά της cache της εφαρμογής κατά την εκκίνηση της εφαρμογής",
|
"auto-reset-app-cache": "Επαναφορά μνήμης cache εφαρμογής όταν η εφαρμογή ξεκινά",
|
||||||
"disable-hardware-acceleration": "Απενεργοποίηση επιτάχυνσης υλικού",
|
"disable-hardware-acceleration": "Απενεργοποίηση επιτάχυνσης υλικού",
|
||||||
"edit-config-json": "Επεξεργασία του config.json",
|
"edit-config-json": "Επεξεργασία του config.json",
|
||||||
"override-user-agent": "Αντικατάσταση του User-Agent",
|
"override-user-agent": "Αντικατάσταση του User-Agent",
|
||||||
"restart-on-config-changes": "Επανεκκίνηση κατά τις αλλαγές στο config",
|
"restart-on-config-changes": "Επανεκκίνηση σε αλλαγές του config",
|
||||||
"set-proxy": {
|
"set-proxy": {
|
||||||
"label": "Ορισμός διακομιστή μεσολάβησης (proxy)",
|
"label": "Ορισμός μεσολάβησης",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"label": "Εισαγωγή διεύθυνσης διακομιστή μεσολάβησης (proxy): (αφήστε κενό για απενεργοποίηση)",
|
"label": "Εισαγωγή διεύθυνσης μεσολάβησης: (αφήστε κενό για απενεργοποίηση)",
|
||||||
"placeholder": "Παράδειγμα: SOCKS5://127.0.0.1:9999",
|
"placeholder": "Παράδειγμα: SOCKS5://127.0.0.1:9999",
|
||||||
"title": "Ορισμός μεσολάβησης"
|
"title": "Ορισμός μεσολάβησης"
|
||||||
}
|
}
|
||||||
@ -112,14 +112,14 @@
|
|||||||
"toggle-dev-tools": "Εναλλαγή DevTools"
|
"toggle-dev-tools": "Εναλλαγή DevTools"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"always-on-top": "Πάντα επάνω",
|
"always-on-top": "Πάντα σε πρώτο πλάνο",
|
||||||
"auto-update": "Αυτόματη Ενημέρωση",
|
"auto-update": "Αυτόματη ενημέρωση",
|
||||||
"hide-menu": {
|
"hide-menu": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"message": "Το μενού θα κρυφτεί στην επόμενη εκκίνηση, χρησιμοποιήστε [Alt] για να το εμφανίσετε (ή το πλήκτρο backtick [`] αν χρησιμοποιείτε το μενού εφαρμογής)",
|
"message": "Το μενού θα κρυφτεί στην επόμενη εκκίνηση, χρησιμοποιήστε [Alt] για να το εμφανίσετε (ή το πλήκτρο backtick [`] αν χρησιμοποιείτε το μενού εφαρμογής)",
|
||||||
"title": "Η Δυνατότητα Απόκρυψης του Μενού ενεργοποιήθηκε"
|
"title": "Η Δυνατότητα Απόκρυψης του Μενού ενεργοποιήθηκε"
|
||||||
},
|
},
|
||||||
"label": "Απόκρυψη Μενού"
|
"label": "Απόκρυψη μενού"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -131,7 +131,7 @@
|
|||||||
"to-help-translate": "Θέλετε να βοηθήσετε στη μετάφραση; Κάντε κλικ εδώ"
|
"to-help-translate": "Θέλετε να βοηθήσετε στη μετάφραση; Κάντε κλικ εδώ"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"resume-on-start": "Συνέχιση του τελευταίου τραγουδιού όταν η εφαρμογή ξεκινά",
|
"resume-on-start": "Συνέχιση τελευταίου τραγουδιού όταν η εφαρμογή ξεκινά",
|
||||||
"single-instance-lock": "Κλείδωμα Μοναδικής Εκδοχής",
|
"single-instance-lock": "Κλείδωμα Μοναδικής Εκδοχής",
|
||||||
"start-at-login": "Έναρξη κατά την σύνδεση",
|
"start-at-login": "Έναρξη κατά την σύνδεση",
|
||||||
"starting-page": {
|
"starting-page": {
|
||||||
@ -148,11 +148,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"visual-tweaks": {
|
"visual-tweaks": {
|
||||||
"label": "Τροποποιήσεις Εμφάνισης",
|
"label": "Τροποποιήσεις εμφάνισης",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"like-buttons": {
|
"like-buttons": {
|
||||||
"default": "Default",
|
"default": "Προεπιλογή",
|
||||||
"force-show": "Αναγκαστική Εμφάνιση",
|
"force-show": "Επιβολή εμφάνισης",
|
||||||
"hide": "Απόκρυψη",
|
"hide": "Απόκρυψη",
|
||||||
"label": "Μου αρέσει"
|
"label": "Μου αρέσει"
|
||||||
},
|
},
|
||||||
@ -169,7 +169,7 @@
|
|||||||
"label": "Θέμα",
|
"label": "Θέμα",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"import-css-file": "Εισαγωγή προσαρμοσμένου αρχείου CSS",
|
"import-css-file": "Εισαγωγή προσαρμοσμένου αρχείου CSS",
|
||||||
"no-theme": "No theme"
|
"no-theme": "Κανένα θέμα"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,10 +184,10 @@
|
|||||||
"view": {
|
"view": {
|
||||||
"label": "Προβολή",
|
"label": "Προβολή",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"force-reload": "Αναγκαστική Eπαναφόρτωση",
|
"force-reload": "Επιβολή επαναφόρτωσης",
|
||||||
"reload": "Επαναφόρτωση",
|
"reload": "Επαναφόρτωση",
|
||||||
"reset-zoom": "Πραγματικό μέγεθος",
|
"reset-zoom": "Πραγματικό μέγεθος",
|
||||||
"toggle-fullscreen": "Εναλλαγή Πλήρους Οθόνης",
|
"toggle-fullscreen": "Εναλλαγή πλήρους οθόνης",
|
||||||
"zoom-in": "Μεγέθυνση",
|
"zoom-in": "Μεγέθυνση",
|
||||||
"zoom-out": "Σμίκρυνση"
|
"zoom-out": "Σμίκρυνση"
|
||||||
}
|
}
|
||||||
@ -201,15 +201,15 @@
|
|||||||
"restart": "Επανεκκίνηση εφαρμογής",
|
"restart": "Επανεκκίνηση εφαρμογής",
|
||||||
"show": "Εμφάνιση παραθύρου",
|
"show": "Εμφάνιση παραθύρου",
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"default": "YouTube Music",
|
"default": "YouTube Μουσική",
|
||||||
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
|
"with-song-info": "YouTube Μουσική: {{artist}} - {{title}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"ad-speedup": {
|
"ad-speedup": {
|
||||||
"description": "Εαν παίξει διαφήμιση κάνει σίγαση του ήχου και θέτει την ταχύτητα αναπαραγωγής στο 16x",
|
"description": "Εάν παίξει διαφήμιση κάνει σίγαση του ήχου και θέτει την ταχύτητα αναπαραγωγής στο 16x",
|
||||||
"name": "Γρήγορη Προώθηση Διαφημίσεων"
|
"name": "Γρήγορη προώθηση διαφημίσεων"
|
||||||
},
|
},
|
||||||
"adblocker": {
|
"adblocker": {
|
||||||
"description": "Αποκλεισμός όλων των διαφημίσεων και tracker",
|
"description": "Αποκλεισμός όλων των διαφημίσεων και tracker",
|
||||||
@ -226,16 +226,16 @@
|
|||||||
"description": "Εφαρμόζει ένα δυναμικό θέμα και εφέ με βάση τη χρωματική παλέτα του άλμπουμ",
|
"description": "Εφαρμόζει ένα δυναμικό θέμα και εφέ με βάση τη χρωματική παλέτα του άλμπουμ",
|
||||||
"menu": {
|
"menu": {
|
||||||
"color-mix-ratio": {
|
"color-mix-ratio": {
|
||||||
"label": "Αναλογία μίξης χρώματος",
|
"label": "Αναλογία μίξης χρωμάτων",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"percent": "{{ratio}}%"
|
"percent": "{{ratio}}%"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Album Color Theme"
|
"name": "Θέμα χρώματος άλμπουμ"
|
||||||
},
|
},
|
||||||
"ambient-mode": {
|
"ambient-mode": {
|
||||||
"description": "Εφαρμόζει ένα εφέ φωτισμού ρίχνοντας απαλά χρώματα από το βίντεο, στο φόντο της οθόνης σας.",
|
"description": "Εφαρμόζει ένα εφέ φωτισμού ρίχνοντας απαλά χρώματα από το βίντεο στο φόντο της οθόνης σας",
|
||||||
"menu": {
|
"menu": {
|
||||||
"blur-amount": {
|
"blur-amount": {
|
||||||
"label": "Ένταση θαμπώματος",
|
"label": "Ένταση θαμπώματος",
|
||||||
@ -268,6 +268,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"smoothness-transition": {
|
"smoothness-transition": {
|
||||||
|
"label": "Ομαλή μετάβαση",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"during": "Σε {{interpolationTime}} δευτερόλεπτα"
|
"during": "Σε {{interpolationTime}} δευτερόλεπτα"
|
||||||
}
|
}
|
||||||
@ -275,39 +276,112 @@
|
|||||||
"use-fullscreen": {
|
"use-fullscreen": {
|
||||||
"label": "Χρήση πλήρους οθόνης"
|
"label": "Χρήση πλήρους οθόνης"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"name": "Λειτουργία περιβάλλοντος"
|
||||||
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "Προσθέτει υποστήριξη μουσικής YouTube για το widget Amuse now playing από την 6K Labs",
|
||||||
|
"name": "Διασκέδαση",
|
||||||
|
"response": {
|
||||||
|
"query": "Ο διακομιστής Amuse API εκτελείται. GET /query για να λάβετε πληροφορίες για το τραγούδι."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"audio-compressor": {
|
"api-server": {
|
||||||
"description": "Συμπίεση ήχου (μειώνει την ένταση των πιο δυνατών τμημάτων του κύματος και αυξάνει την ένταση των πιο μαλακών τμημάτων)"
|
"description": "Προσθέτει έναν διακομιστή API για τον έλεγχο του παίκτη",
|
||||||
},
|
"dialog": {
|
||||||
"blur-nav-bar": {
|
"request": {
|
||||||
"description": "Κάνει τη γραμμή πλοήγησης διαφανή και θολή"
|
"buttons": {
|
||||||
},
|
"allow": "Αποδοχή",
|
||||||
"bypass-age-restrictions": {
|
"deny": "Άρνηση"
|
||||||
"description": "Παράκαμψη της επαλήθευσης ηλικίας του YouTube"
|
},
|
||||||
},
|
"message": "Επιτρέψτε {{ID}} ({{origin}}) να έχει πρόσβαση στο API;",
|
||||||
"captions-selector": {
|
"title": "Αίτημα εξουσιοδότησης API"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"auth-strategy": {
|
||||||
|
"label": "Στρατηγική εξουσιοδότησης",
|
||||||
|
"submenu": {
|
||||||
|
"auth-at-first": {
|
||||||
|
"label": "Εξουσιοδότηση στο πρώτο αίτημα"
|
||||||
|
},
|
||||||
|
"none": {
|
||||||
|
"label": "Χωρίς εξουσιοδότηση"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hostname": {
|
||||||
|
"label": "Όνομα κεντρικού υπολογιστή"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"label": "Θύρα"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Διακομιστής API [Beta]",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"selector": {
|
"hostname": {
|
||||||
"none": "None"
|
"label": "Εισάγετε το όνομα κεντρικού υπολογιστή (όπως 0.0.0.0.0) για τον διακομιστή API:",
|
||||||
|
"title": "Όνομα κεντρικού υπολογιστή"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"label": "Εισάγετε τη θύρα για το διακομιστή API:",
|
||||||
|
"title": "Θύρα"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"audio-compressor": {
|
||||||
|
"description": "Συμπίεση ήχου (μειώνει την ένταση των πιο δυνατών τμημάτων του κύματος και αυξάνει την ένταση των πιο μαλακών τμημάτων)",
|
||||||
|
"name": "Συμπιεστής ήχου"
|
||||||
|
},
|
||||||
|
"blur-nav-bar": {
|
||||||
|
"description": "θέτει τη γραμμή πλοήγησης διαφανή και θολή",
|
||||||
|
"name": "Θόλωμα γραμμής πλοήγησης"
|
||||||
|
},
|
||||||
|
"bypass-age-restrictions": {
|
||||||
|
"description": "Παράκαμψη επαλήθευσης ηλικίας στο YouTube",
|
||||||
|
"name": "Παράκαμψη ηλικιακών περιορισμών"
|
||||||
|
},
|
||||||
|
"captions-selector": {
|
||||||
|
"description": "Επιλογέας λεζάντας για μουσικά κομμάτια ήχου του YouTube",
|
||||||
|
"menu": {
|
||||||
|
"autoload": "Αυτόματη επιλογή της τελευταίας χρησιμοποιούμενης λεζάντας",
|
||||||
|
"disable-captions": "Χωρίς λεζάντες από προεπιλογή"
|
||||||
|
},
|
||||||
|
"name": "Επιλογέας λεζάντες",
|
||||||
|
"prompt": {
|
||||||
|
"selector": {
|
||||||
|
"label": "Τρέχουσα γλώσσα λεζάντας: {{language}}",
|
||||||
|
"none": "None",
|
||||||
|
"title": "Επιλογή γλώσσας λεζάντας"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"templates": {
|
||||||
|
"title": "Ανοίξτε τον επιλογέα λεζάντας"
|
||||||
|
}
|
||||||
|
},
|
||||||
"compact-sidebar": {
|
"compact-sidebar": {
|
||||||
"description": "Να είναι πάντα συμπαγές το sidebar"
|
"description": "Να είναι πάντα συμπαγές το sidebar",
|
||||||
|
"name": "Συμπαγής πλευρική μπάρα"
|
||||||
},
|
},
|
||||||
"crossfade": {
|
"crossfade": {
|
||||||
|
"description": "Crossfade μεταξύ τραγουδιών",
|
||||||
"menu": {
|
"menu": {
|
||||||
"advanced": "Για προχωρημένους"
|
"advanced": "Για προχωρημένους"
|
||||||
},
|
},
|
||||||
|
"name": "Crossfade [Beta]",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"options": {
|
"options": {
|
||||||
"multi-input": {
|
"multi-input": {
|
||||||
|
"fade-in-duration": "Διάρκεια εξασθένισης (ms)",
|
||||||
|
"fade-out-duration": "Διάρκεια σβήσιμου (ms)",
|
||||||
"fade-scaling": {
|
"fade-scaling": {
|
||||||
|
"label": "Κλιμάκωση εξασθένισης",
|
||||||
"linear": "Γραμμική",
|
"linear": "Γραμμική",
|
||||||
"logarithmic": "Λογαριθμική"
|
"logarithmic": "Λογαριθμική"
|
||||||
}
|
},
|
||||||
}
|
"seconds-before-end": "Crossfade N δευτερόλεπτα πριν το τέλος"
|
||||||
|
},
|
||||||
|
"title": "Επιλογές Crossfade"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -319,13 +393,29 @@
|
|||||||
"name": "Απενεργοποίηση αυτόματης αναπαραγωγής"
|
"name": "Απενεργοποίηση αυτόματης αναπαραγωγής"
|
||||||
},
|
},
|
||||||
"discord": {
|
"discord": {
|
||||||
|
"backend": {
|
||||||
|
"already-connected": "Προσπάθεια σύνδεσης με ενεργή σύνδεση",
|
||||||
|
"connected": "Συνδεδεμένος με το Discord",
|
||||||
|
"disconnected": "Αποσυνδεδεμένος από το Discord"
|
||||||
|
},
|
||||||
"description": "Δείξτε στους φίλους σας τι ακούτε με το Rich Presence",
|
"description": "Δείξτε στους φίλους σας τι ακούτε με το Rich Presence",
|
||||||
"menu": {
|
"menu": {
|
||||||
"auto-reconnect": "Αυτόματη επανασύνδεση",
|
"auto-reconnect": "Αυτόματη επανασύνδεση",
|
||||||
"clear-activity": "Εκκαθάριση δραστηριότητας",
|
"clear-activity": "Εκκαθάριση δραστηριότητας",
|
||||||
|
"clear-activity-after-timeout": "Εκκαθάριση δραστηριότητας μετά από χρονικό όριο",
|
||||||
|
"connected": "Συνδεδεμένο",
|
||||||
|
"disconnected": "Αποσυνδεδεμένο",
|
||||||
"hide-duration-left": "Απόκρυψη της διάρκειας που απομένει",
|
"hide-duration-left": "Απόκρυψη της διάρκειας που απομένει",
|
||||||
"hide-github-button": "Απόκρυψη του συνδέσμου προς GitHub",
|
"hide-github-button": "Απόκρυψη κουμπιού συνδέσμου GitHub",
|
||||||
|
"play-on-youtube-music": "Αναπαραγωγή στο YouTube Music",
|
||||||
"set-inactivity-timeout": "Ορισμός χρονικού ορίου αδράνειας"
|
"set-inactivity-timeout": "Ορισμός χρονικού ορίου αδράνειας"
|
||||||
|
},
|
||||||
|
"name": "Discord Πλούσια παρουσία",
|
||||||
|
"prompt": {
|
||||||
|
"set-inactivity-timeout": {
|
||||||
|
"label": "Εισαγωγή χρονικού ορίου αδράνειας σε δευτερόλεπτα:",
|
||||||
|
"title": "Ορισμός χρονικού ορίου αδράνειας"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"downloader": {
|
"downloader": {
|
||||||
@ -335,7 +425,8 @@
|
|||||||
"buttons": {
|
"buttons": {
|
||||||
"ok": "OK"
|
"ok": "OK"
|
||||||
},
|
},
|
||||||
"title": "Error in download!"
|
"message": "Ωχ! Λυπούμαστε, η λήψη απέτυχε…",
|
||||||
|
"title": "Σφάλμα στη λήψη!"
|
||||||
},
|
},
|
||||||
"start-download-playlist": {
|
"start-download-playlist": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
@ -349,59 +440,168 @@
|
|||||||
"feedback": {
|
"feedback": {
|
||||||
"conversion-progress": "Μετατροπή: {{percent}}%",
|
"conversion-progress": "Μετατροπή: {{percent}}%",
|
||||||
"converting": "Μετατροπή…",
|
"converting": "Μετατροπή…",
|
||||||
|
"done": "Τέλος: {{filePath}}",
|
||||||
"download-info": "Λήψη του {{artist}} - {{title}} [{{videoId}}",
|
"download-info": "Λήψη του {{artist}} - {{title}} [{{videoId}}",
|
||||||
"download-progress": "Λήψη: {{percent}}%",
|
"download-progress": "Λήψη: {{percent}}%",
|
||||||
"downloading": "Λήψη…",
|
"downloading": "Λήψη…",
|
||||||
"downloading-counter": "Λήψη {{current}}/{{total}}…",
|
"downloading-counter": "Λήψη {{current}}/{{total}}…",
|
||||||
"downloading-playlist": "Λήψη της λίστας αναπαραγωγής \"{{playlistTitle}}\" - {{playlistSize}} τραγούδια ({{playlistId}})",
|
"downloading-playlist": "Λήψη της λίστας αναπαραγωγής \"{{playlistTitle}}\" - {{playlistSize}} τραγούδια ({{playlistId}})",
|
||||||
|
"error-while-downloading": "Σφάλμα λήψης \"{{author}} - {{title}}\": {{error}}",
|
||||||
"folder-already-exists": "Ο φάκελος {{playlistFolder}} υπάρχει ήδη",
|
"folder-already-exists": "Ο φάκελος {{playlistFolder}} υπάρχει ήδη",
|
||||||
|
"getting-playlist-info": "Λήψη πληροφοριών λίστας αναπαραγωγής…",
|
||||||
"loading": "Φόρτωση…",
|
"loading": "Φόρτωση…",
|
||||||
|
"playlist-has-only-one-song": "Η λίστα αναπαραγωγής έχει μόνο ένα στοιχείο, κατεβάζοντάς το απευθείας",
|
||||||
|
"playlist-id-not-found": "Δεν βρέθηκε ID λίστας αναπαραγωγής",
|
||||||
"playlist-is-empty": "Η λίστα αναπραγωγής είναι άδεια",
|
"playlist-is-empty": "Η λίστα αναπραγωγής είναι άδεια",
|
||||||
|
"playlist-is-mix-or-private": "Σφάλμα λήψης πληροφοριών λίστας αναπαραγωγής: βεβαιωθείτε ότι δεν είναι ιδιωτική ή «Μικτή για εσάς» λίστα αναπαραγωγής\n\n{{error}}",
|
||||||
"preparing-file": "Προετοιμασία αρχείου…",
|
"preparing-file": "Προετοιμασία αρχείου…",
|
||||||
"saving": "Αποθήκευση…",
|
"saving": "Αποθήκευση…",
|
||||||
"video-id-not-found": "Το βίντεο δεν βρέθηκε"
|
"trying-to-get-playlist-id": "Προσπαθώ να πάρω το αναγνωριστικό της λίστας αναπαραγωγής: {{playlistId}}",
|
||||||
|
"video-id-not-found": "Το βίντεο δεν βρέθηκε",
|
||||||
|
"writing-id3": "Εγγραφή ετικετών ID3…"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"description": "Λήψεις MP3 / ήχου πηγής απευθείας από τη διεπαφή",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
"choose-download-folder": "Επιλογή φακέλου λήψης",
|
||||||
"download-finish-settings": {
|
"download-finish-settings": {
|
||||||
|
"label": "Λήψη στο τέλος",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"last-seconds": "Τελευταία x δευτερόλεπτα"
|
"last-percent": "Μετά από x ποσοστό",
|
||||||
|
"last-seconds": "Τελευταία x δευτερόλεπτα",
|
||||||
|
"title": "Ρύθμιση του πότε θα γίνεται λήψη"
|
||||||
},
|
},
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"advanced": "Για προχωρημένους",
|
||||||
|
"enabled": "Ενεργοποιημένο",
|
||||||
|
"mode": "Λειτουργία χρόνου",
|
||||||
"percent": "Ποσοστό",
|
"percent": "Ποσοστό",
|
||||||
"seconds": "Δευτερόλεπτα"
|
"seconds": "Δευτερόλεπτα"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"download-playlist": "Λήψη λίστας αναπαραγωγής",
|
"download-playlist": "Λήψη λίστας αναπαραγωγής",
|
||||||
|
"presets": "Προεπιλογές",
|
||||||
"skip-existing": "Παράλειψη υπάρχοντων αρχείων"
|
"skip-existing": "Παράλειψη υπάρχοντων αρχείων"
|
||||||
},
|
},
|
||||||
|
"name": "Κατεβαστής",
|
||||||
|
"renderer": {
|
||||||
|
"can-not-update-progress": "Δεν μπορεί να ενημερωθεί η πρόοδος"
|
||||||
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
"button": "Λήψη"
|
"button": "Λήψη"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"equalizer": {
|
||||||
|
"description": "Προσθέτει έναν ισοσταθμιστή στο πρόγραμμα αναπαραγωγής",
|
||||||
|
"menu": {
|
||||||
|
"presets": {
|
||||||
|
"label": "Προεπιλογές",
|
||||||
|
"list": {
|
||||||
|
"bass-booster": "Ενίσχυση μπάσου"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Ισοσταθμιστής"
|
||||||
|
},
|
||||||
|
"exponential-volume": {
|
||||||
|
"description": "Κάνει το ρυθμιστικό έντασης εκθετικό, ώστε να είναι ευκολότερη η επιλογή χαμηλότερων εντάσεων.",
|
||||||
|
"name": "Εκθετικός όγκος"
|
||||||
|
},
|
||||||
|
"in-app-menu": {
|
||||||
|
"description": "Δίνει στις γραμμές μενού μια φανταχτερή, σκοτεινή ή άλμπουμ-χρωματική εμφάνιση",
|
||||||
|
"menu": {
|
||||||
|
"hide-dom-window-controls": "Απόκρυψη στοιχείων ελέγχου παραθύρου DOM"
|
||||||
|
},
|
||||||
|
"name": "Μενού εντός της εφαρμογής"
|
||||||
|
},
|
||||||
|
"lumiastream": {
|
||||||
|
"description": "Προσθέτει υποστήριξη Lumia Stream",
|
||||||
|
"name": "Lumia Stream [Beta]"
|
||||||
|
},
|
||||||
|
"lyrics-genius": {
|
||||||
|
"description": "Προσθέτει υποστήριξη στίχων για τα περισσότερα τραγούδια",
|
||||||
|
"menu": {
|
||||||
|
"romanized-lyrics": "Ρομαντικοποιημένοι στίχοι"
|
||||||
|
},
|
||||||
|
"name": "Στίχοι Genius",
|
||||||
|
"renderer": {
|
||||||
|
"fetched-lyrics": "Στίχοι για το Genius"
|
||||||
|
}
|
||||||
|
},
|
||||||
"music-together": {
|
"music-together": {
|
||||||
|
"description": "Μοιραστείτε μια λίστα αναπαραγωγής με άλλους. Όταν ο οικοδεσπότης παίζει ένα τραγούδι, όλοι οι άλλοι θα ακούσουν το ίδιο τραγούδι",
|
||||||
|
"dialog": {
|
||||||
|
"enter-host": "Εισαγωγή ID κεντρικού υπολογιστή"
|
||||||
|
},
|
||||||
"internal": {
|
"internal": {
|
||||||
"save": "Αποθήκευση",
|
"save": "Αποθήκευση",
|
||||||
|
"track-source": "Πηγή διαδρομής",
|
||||||
"unknown-user": "Άγνωστος χρήστης"
|
"unknown-user": "Άγνωστος χρήστης"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"connected-users": "Συνδεδεμένοι χρήστες"
|
"click-to-copy-id": "Αντιγραφή ID κεντρικού υπολογιστή",
|
||||||
|
"close": "Κλείσιμο Music Together",
|
||||||
|
"connected-users": "Συνδεδεμένοι χρήστες",
|
||||||
|
"disconnect": "Αποσύνδεση Music Together",
|
||||||
|
"empty-user": "Κανένας συνδεδεμένος χρήστης",
|
||||||
|
"host": "Κεντρικός υπολογιστής Music Together",
|
||||||
|
"join": "Γίνετε μέλος της Μουσικής Μαζί",
|
||||||
|
"permission": {
|
||||||
|
"all": "Επιτρέψτε στους επισκέπτες να ελέγχουν τη λίστα αναπαραγωγής και τον παίκτη",
|
||||||
|
"host-only": "Μόνο ο οικοδεσπότης μπορεί να ελέγχει τη λίστα αναπαραγωγής και τον παίκτη",
|
||||||
|
"playlist": "Επιτρέψτε στους επισκέπτες να ελέγχουν τη λίστα αναπαραγωγής"
|
||||||
|
},
|
||||||
|
"set-permission": "Άδεια ελέγχου αλλαγής",
|
||||||
|
"status": {
|
||||||
|
"disconnected": "Αποσυνδεδεμένο",
|
||||||
|
"guest": "Συνδεδεμένος ως επισκέπτης",
|
||||||
|
"host": "Συνδεδεμένος ως οικοδεσπότης"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"name": "Music Together [Beta]",
|
||||||
"toast": {
|
"toast": {
|
||||||
"add-song-failed": "Απέτυχε η προσθήκη τραγουδιού",
|
"add-song-failed": "Απέτυχε η προσθήκη τραγουδιού",
|
||||||
"remove-song-failed": "Απέτυχε η αφαίρεση τραγουδιού"
|
"closed": "Το Music Together έκλεισε",
|
||||||
|
"disconnected": "Το Music Together αποσυνδέθηκε",
|
||||||
|
"host-failed": "Απέτυχε να φιλοξενήσει το Μουσική Μαζί",
|
||||||
|
"id-copied": "Το ID κεντρικού υπολογιστή αντιγράφηκε στο πρόχειρο",
|
||||||
|
"id-copy-failed": "Απέτυχε η αντιγραφή ID κεντρικού υπολογιστή στο πρόχειρο",
|
||||||
|
"join-failed": "Απέτυχε να ενταχθεί στη Μουσική Μαζί",
|
||||||
|
"joined": "Ενωμένη μουσική μαζί",
|
||||||
|
"permission-changed": "Η άδεια «Μουσική Μαζί» άλλαξε σε «{{permission}}»",
|
||||||
|
"remove-song-failed": "Απέτυχε η αφαίρεση τραγουδιού",
|
||||||
|
"user-connected": "{{name}} εντάχθηκε στη Μουσική Μαζί",
|
||||||
|
"user-disconnected": "{{name}} αριστερά Μουσική Μαζί"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
"description": "Βέλη πλοήγησης Επόμενο/Πίσω ενσωματωμένα απευθείας στο περιβάλλον εργασίας, όπως στο αγαπημένο σας πρόγραμμα περιήγησης",
|
||||||
"name": "Πλοήγηση"
|
"name": "Πλοήγηση"
|
||||||
},
|
},
|
||||||
"no-google-login": {
|
"no-google-login": {
|
||||||
|
"description": "Αφαίρεση των κουμπιών και των συνδέσμων σύνδεσης Google από το περιβάλλον εργασίας",
|
||||||
"name": "No Google Login"
|
"name": "No Google Login"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
"description": "Εμφάνιση ειδοποίησης όταν ξεκινάει η αναπαραγωγή ενός τραγουδιού (οι διαδραστικές ειδοποιήσεις είναι διαθέσιμες στα Windows)",
|
||||||
|
"menu": {
|
||||||
|
"interactive": "Διαδραστικές ειδοποιήσεις",
|
||||||
|
"interactive-settings": {
|
||||||
|
"label": "Διαδραστικές ρυθμίσεις",
|
||||||
|
"submenu": {
|
||||||
|
"hide-button-text": "Απόκρυψη κειμένου κουμπιού",
|
||||||
|
"refresh-on-play-pause": "Ανανέωση σε Αναπαραγωγή/Παύση",
|
||||||
|
"tray-controls": "Άνοιγμα/κλείσιμο με κλικ στο δίσκο"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"priority": "Προτεραιότητα κοινοποίησης",
|
||||||
|
"toast-style": "Στυλ τοστ",
|
||||||
|
"unpause-notification": "Εμφάνιση ειδοποίησης κατά την κατάργηση της παύσης"
|
||||||
|
},
|
||||||
"name": "Ειδοποιήσεις"
|
"name": "Ειδοποιήσεις"
|
||||||
},
|
},
|
||||||
"picture-in-picture": {
|
"picture-in-picture": {
|
||||||
|
"description": "Επιτρέπει την εναλλαγή της εφαρμογής σε λειτουργία εικόνας σε εικόνα",
|
||||||
"menu": {
|
"menu": {
|
||||||
"always-on-top": "Πάντα σε πρώτο πλάνο",
|
"always-on-top": "Πάντα σε πρώτο πλάνο",
|
||||||
"hotkey": {
|
"hotkey": {
|
||||||
@ -409,26 +609,47 @@
|
|||||||
"prompt": {
|
"prompt": {
|
||||||
"keybind-options": {
|
"keybind-options": {
|
||||||
"hotkey": "Πλήκτρο πρόσβασης"
|
"hotkey": "Πλήκτρο πρόσβασης"
|
||||||
}
|
},
|
||||||
|
"label": "Επιλέξτε ένα πλήκτρο συντόμευσης για να ενεργοποιήσετε την εικόνα στην εικόνα",
|
||||||
|
"title": "Πλήκτρο Hotkey Εικόνα-σε-Εικόνα"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"save-window-position": "Αποθήκευση θέσης παραθύρου",
|
"save-window-position": "Αποθήκευση θέσης παραθύρου",
|
||||||
"save-window-size": "Αποθήκευση μεγέθους παραθύρου"
|
"save-window-size": "Αποθήκευση μεγέθους παραθύρου",
|
||||||
|
"use-native-pip": "Χρήση εγγενούς PiP του προγράμματος περιήγησης"
|
||||||
|
},
|
||||||
|
"name": "Εικόνα-στην-εικόνα",
|
||||||
|
"templates": {
|
||||||
|
"button": "Εικόνα-στην-εικόνα"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playback-speed": {
|
"playback-speed": {
|
||||||
|
"description": "Ακούστε γρήγορα, ακούστε αργά! Προσθέτει ένα ρυθμιστικό που ελέγχει την ταχύτητα του τραγουδιού",
|
||||||
"name": "Ταχύτητα αναπαραγωγής",
|
"name": "Ταχύτητα αναπαραγωγής",
|
||||||
"templates": {
|
"templates": {
|
||||||
"button": "Ταχύτητα"
|
"button": "Ταχύτητα"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"precise-volume": {
|
"precise-volume": {
|
||||||
|
"description": "Ελέγξτε την ένταση του ήχου με ακρίβεια χρησιμοποιώντας τον τροχό του ποντικιού/τα πλήκτρα, με ένα προσαρμοσμένο HUD και προσαρμόσιμα βήματα έντασης",
|
||||||
|
"menu": {
|
||||||
|
"arrows-shortcuts": "Τοπικά πλήκτρα βέλους Έλεγχοι",
|
||||||
|
"custom-volume-steps": "Ορισμός προσαρμοσμένων βημάτων έντασης ήχου",
|
||||||
|
"global-shortcuts": "Παγκόσμια πλήκτρα συντόμευσης"
|
||||||
|
},
|
||||||
|
"name": "Ακριβής Ήχος",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"global-shortcuts": {
|
"global-shortcuts": {
|
||||||
"keybind-options": {
|
"keybind-options": {
|
||||||
"decrease": "Μείωση έντασης",
|
"decrease": "Μείωση έντασης",
|
||||||
"increase": "Αύξηση έντασης"
|
"increase": "Αύξηση έντασης"
|
||||||
}
|
},
|
||||||
|
"label": "Επιλέξτε Παγκόσμια δέσμευση πλήκτρων έντασης ήχου:",
|
||||||
|
"title": "Επιλέξτε Παγκόσμια δέσμευση πλήκτρων έντασης ήχου"
|
||||||
|
},
|
||||||
|
"volume-steps": {
|
||||||
|
"label": "Επιλέξτε Βήματα αύξησης/μείωσης έντασης ήχου",
|
||||||
|
"title": "Βήματα έντασης"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -436,46 +657,189 @@
|
|||||||
"backend": {
|
"backend": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"quality-changer": {
|
"quality-changer": {
|
||||||
"detail": "Τρέχουσα ποιότητα: {{quality}}"
|
"detail": "Τρέχουσα ποιότητα: {{quality}}",
|
||||||
|
"message": "Επιλογή ποιότητας βίντεο:",
|
||||||
|
"title": "Επιλογή ποιότητας βίντεο"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Επιτρέπει την αλλαγή της ποιότητας βίντεο με ένα κουμπί στην επικάλυψη βίντεο",
|
||||||
|
"name": "Αλλαγή ποιότητας βίντεο"
|
||||||
|
},
|
||||||
|
"scrobbler": {
|
||||||
|
"description": "Προσθήκη υποστήριξης scrobbling (κ.λπ. last.fm, Listenbrainz)",
|
||||||
|
"dialog": {
|
||||||
|
"lastfm": {
|
||||||
|
"auth-failed": {
|
||||||
|
"message": "Απέτυχε η πιστοποίηση ταυτότητας στο Last.fm\nΚρύψτε το αναδυόμενο παράθυρο μέχρι την επόμενη επανεκκίνηση.",
|
||||||
|
"title": "Αποτυχία ελέγχου ταυτότητας"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"lastfm": {
|
||||||
|
"api-settings": "Ρυθμίσεις API Last.fm"
|
||||||
|
},
|
||||||
|
"listenbrainz": {
|
||||||
|
"token": "Εισάγετε το διακριτικό χρήστη ListenBrainz"
|
||||||
|
},
|
||||||
|
"scrobble-alternative-title": "Χρήση εναλλακτικών τίτλων",
|
||||||
|
"scrobble-other-media": "Scrobble άλλα μέσα ενημέρωσης"
|
||||||
|
},
|
||||||
|
"name": "Σκρόμπλερ",
|
||||||
|
"prompt": {
|
||||||
|
"lastfm": {
|
||||||
|
"api-key": "Κλειδί API Last.fm",
|
||||||
|
"api-secret": "Μυστικό API του Last.fm"
|
||||||
|
},
|
||||||
|
"listenbrainz": {
|
||||||
|
"token": {
|
||||||
|
"label": "Εισάγετε το διακριτικό χρήστη ListenBrainz:",
|
||||||
|
"title": "Κουπόνι ListenBrainz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
|
"description": "Επιτρέπετε τον καθορισμό παγκόσμιων πλήκτρων άμεσης πρόσβασης για την παρακολούθηση (αναπαραγωγή/παύση/επόμενη/προηγούμενη) και την απενεργοποίηση του OSD πολυμέσων με παράκαμψη των πλήκτρων πολυμέσων, την ενεργοποίηση του Ctrl/CMD + F για αναζήτηση, την ενεργοποίηση της υποστήριξης Linux MPRIS για τα πλήκτρα πολυμέσων και προσαρμοσμένα πλήκτρα άμεσης πρόσβασης για προχωρημένους χρήστες",
|
||||||
|
"menu": {
|
||||||
|
"override-media-keys": "Παράκαμψη κλειδιών πολυμέσων",
|
||||||
|
"set-keybinds": "Ορισμός παγκόσμιων ελέγχων τραγουδιού"
|
||||||
|
},
|
||||||
|
"name": "Συντομεύσεις (& MPRIS)",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"keybind": {
|
"keybind": {
|
||||||
"keybind-options": {
|
"keybind-options": {
|
||||||
"next": "Επόμενο",
|
"next": "Επόμενο",
|
||||||
"play-pause": "Αναπαραγωγή / Παύση",
|
"play-pause": "Αναπαραγωγή / Παύση",
|
||||||
"previous": "Προηγούμενο"
|
"previous": "Προηγούμενο"
|
||||||
}
|
},
|
||||||
|
"label": "Επιλέξτε Global Keybinds για το τραγούδι Έλεγχος:",
|
||||||
|
"title": "Παγκόσμια δέσμευση πλήκτρων"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"skip-disliked-songs": {
|
||||||
|
"description": "Παραλείπει τα αρεστά τραγούδια",
|
||||||
|
"name": "Παραλείψτε τα τραγούδια που δεν άρεσαν"
|
||||||
|
},
|
||||||
|
"skip-silences": {
|
||||||
|
"description": "Αυτόματη παράλειψη τμημάτων σιωπής σε τραγούδια",
|
||||||
|
"name": "Παραλείψτε τις σιωπές"
|
||||||
|
},
|
||||||
"sponsorblock": {
|
"sponsorblock": {
|
||||||
|
"description": "Παραλείπει αυτόματα μέρη που δεν είναι μουσικά, όπως intro/outro ή μέρη μουσικών βίντεο όπου δεν παίζεται το τραγούδι",
|
||||||
"name": "SponsorBlock"
|
"name": "SponsorBlock"
|
||||||
},
|
},
|
||||||
|
"synced-lyrics": {
|
||||||
|
"description": "Παρέχει συγχρονισμένους στίχους σε τραγούδια, χρησιμοποιώντας παρόχους όπως η LRClib.",
|
||||||
|
"errors": {
|
||||||
|
"fetch": "⚠️ Προέκυψε σφάλμα κατά την ανάκτηση των στίχων.\n\tΠροσπαθήστε ξανά αργότερα.",
|
||||||
|
"not-found": "⚠️ Δεν βρέθηκαν στίχοι για αυτό το τραγούδι."
|
||||||
|
},
|
||||||
|
"menu": {
|
||||||
|
"default-text-string": {
|
||||||
|
"label": "Προεπιλεγμένος χαρακτήρας μεταξύ στίχων",
|
||||||
|
"tooltip": "Επιλέξτε τον προεπιλεγμένο χαρακτήρα που θα χρησιμοποιηθεί για το κενό μεταξύ των στίχων"
|
||||||
|
},
|
||||||
|
"line-effect": {
|
||||||
|
"label": "Επίδραση γραμμής",
|
||||||
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "Φανταχτερό",
|
||||||
|
"tooltip": "Χρήση μεγάλων εφέ που μοιάζουν με εφαρμογές στην τρέχουσα γραμμή"
|
||||||
|
},
|
||||||
|
"focus": {
|
||||||
|
"label": "Εστίαση",
|
||||||
|
"tooltip": "Κάντε μόνο την τρέχουσα γραμμή λευκή"
|
||||||
|
},
|
||||||
|
"offset": {
|
||||||
|
"label": "Μετατόπιση",
|
||||||
|
"tooltip": "Μετατόπιση προς τα δεξιά της τρέχουσας γραμμής"
|
||||||
|
},
|
||||||
|
"scale": {
|
||||||
|
"label": "Κλίμακα",
|
||||||
|
"tooltip": "Κλιμάκωση της τρέχουσας γραμμής"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tooltip": "Επιλέξτε το εφέ που θα εφαρμοστεί στην τρέχουσα γραμμή"
|
||||||
|
},
|
||||||
|
"precise-timing": {
|
||||||
|
"label": "Κάντε τους στίχους τέλεια συγχρονισμένους",
|
||||||
|
"tooltip": "Υπολογίζει με ακρίβεια χιλιοστού του δευτερολέπτου την εμφάνιση της επόμενης γραμμής (μπορεί να έχει μικρή επίπτωση στην απόδοση)"
|
||||||
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Στίχοι Ρομαντικοποίηση",
|
||||||
|
"tooltip": "Αν οι στίχοι είναι σε διαφορετική γλώσσα, προσπαθήστε να εμφανίσετε μια λατινική έκδοση."
|
||||||
|
},
|
||||||
|
"show-lyrics-even-if-inexact": {
|
||||||
|
"label": "Εμφάνιση στίχων ακόμα και αν είναι ανακριβείς",
|
||||||
|
"tooltip": "Εάν το τραγούδι δεν βρεθεί, το πρόσθετο προσπαθεί ξανά με διαφορετικό ερώτημα αναζήτησης.\nΤο αποτέλεσμα της δεύτερης προσπάθειας μπορεί να μην είναι ακριβές."
|
||||||
|
},
|
||||||
|
"show-time-codes": {
|
||||||
|
"label": "Εμφάνιση κωδικών ώρας",
|
||||||
|
"tooltip": "Εμφάνιση των κωδικών ώρας δίπλα στους στίχους"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Συγχρονισμένοι στίχοι",
|
||||||
|
"refetch-btn": {
|
||||||
|
"fetching": "Φέρνοντας...",
|
||||||
|
"normal": "Στίχοι Refetch"
|
||||||
|
},
|
||||||
|
"warnings": {
|
||||||
|
"duration-mismatch": "⚠️ - Οι στίχοι ενδέχεται να μην είναι συγχρονισμένοι λόγω αναντιστοιχίας διάρκειας.",
|
||||||
|
"inexact": "⚠️ - Οι στίχοι για αυτό το τραγούδι μπορεί να μην είναι ακριβείς",
|
||||||
|
"instrumental": "⚠️ - Αυτό είναι ένα ορχηστρικό τραγούδι"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"taskbar-mediacontrol": {
|
||||||
|
"description": "Έλεγχος αναπαραγωγής από τη γραμμή εργασιών των Windows",
|
||||||
|
"name": "Έλεγχος μέσων γραμμής εργασιών"
|
||||||
|
},
|
||||||
"touchbar": {
|
"touchbar": {
|
||||||
|
"description": "Προσθέτει ένα γραφικό στοιχείο TouchBar για χρήστες macOS",
|
||||||
"name": "TouchBar"
|
"name": "TouchBar"
|
||||||
},
|
},
|
||||||
"tuna-obs": {
|
"tuna-obs": {
|
||||||
|
"description": "Ενσωμάτωση με το plugin Tuna του OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Αποτρέπει την εμφάνιση του προγράμματος αναπαραγωγής κατά την αναπαραγωγή ενός τραγουδιού",
|
||||||
|
"name": "Ανεπαίσθητος παίκτης"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
|
"description": "Προσθέτει ένα κουμπί για εναλλαγή μεταξύ της λειτουργίας βίντεο/τραγουδιού. μπορεί επίσης προαιρετικά να αφαιρέσει ολόκληρη την καρτέλα βίντεο",
|
||||||
"menu": {
|
"menu": {
|
||||||
"align": {
|
"align": {
|
||||||
|
"label": "Στοίχιση",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"left": "Αριστερά",
|
||||||
"middle": "Middle",
|
"middle": "Middle",
|
||||||
"right": "Right"
|
"right": "Δεξιά"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"force-hide": "Αναγκαστική αφαίρεση καρτέλας βίντεο",
|
||||||
"mode": {
|
"mode": {
|
||||||
"label": "Mode"
|
"label": "Mode",
|
||||||
|
"submenu": {
|
||||||
|
"custom": "Προσαρμοσμένη εναλλαγή",
|
||||||
|
"disabled": "Απενεργοποιημένο",
|
||||||
|
"native": "Γηγενής εναλλαγή"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"name": "Εναλλαγή βίντεο",
|
||||||
"templates": {
|
"templates": {
|
||||||
"button": "Song"
|
"button": "Τραγούδι"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"visualizer": {
|
||||||
|
"description": "Προσθέτει έναν απεικονιστή στο πρόγραμμα αναπαραγωγής",
|
||||||
|
"menu": {
|
||||||
|
"visualizer-type": "Τύπος απεικονιστή"
|
||||||
|
},
|
||||||
|
"name": "Απεικονιστής"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -588,6 +588,10 @@
|
|||||||
},
|
},
|
||||||
"name": "Notifications"
|
"name": "Notifications"
|
||||||
},
|
},
|
||||||
|
"performance-improvement": {
|
||||||
|
"description": "Improve performance by enabling dangerous scripts",
|
||||||
|
"name": "Performance improvement [Beta]"
|
||||||
|
},
|
||||||
"picture-in-picture": {
|
"picture-in-picture": {
|
||||||
"description": "Allows to switch the app to picture-in-picture mode",
|
"description": "Allows to switch the app to picture-in-picture mode",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"console": {
|
"console": {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"execute-failed": "Error al ejecutar el plugin {{pluginName}}::{{contextName}}",
|
"execute-failed": "Error al ejecutar el plugin {{pluginName}}::{{contextName}}",
|
||||||
"executed-at-ms": "Plugin {{pluginName}}: {{contextName}} ejecutado en {{ms}}ms",
|
"executed-at-ms": "Plugin {{pluginName}}::{{contextName}} Ejecutó en {{ms}}ms",
|
||||||
"initialize-failed": "Error al inicializar el plugin \"{{pluginName}}\"",
|
"initialize-failed": "Error al inicializar el plugin \"{{pluginName}}\"",
|
||||||
"load-all": "Cargando todos los plugins",
|
"load-all": "Cargando todos los plugins",
|
||||||
"load-failed": "Error al cargar el plugin \"{{pluginName}}\"",
|
"load-failed": "Error al cargar el plugin \"{{pluginName}}\"",
|
||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Introduzca el token de usuario de ListenBrainz"
|
"token": "Introduzca el token de usuario de ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Usar títulos alternativos",
|
||||||
"scrobble-other-media": "Scrobble en otros medios"
|
"scrobble-other-media": "Scrobble en otros medios"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Haz que la letra esté perfectamente sincronizada",
|
"label": "Haz que la letra esté perfectamente sincronizada",
|
||||||
"tooltip": "Calcular al milisegundo la visualización de la siguiente línea (puede tener un pequeño impacto en el rendimiento)"
|
"tooltip": "Calcular al milisegundo la visualización de la siguiente línea (puede tener un pequeño impacto en el rendimiento)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Romanizar letras",
|
||||||
|
"tooltip": "Si la letra está en un idioma diferente, intenta mostrar una versión en latín."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Mostrar la letra aunque sea inexacta",
|
"label": "Mostrar la letra aunque sea inexacta",
|
||||||
"tooltip": "Si no se encuentra la canción, el plugin vuelve a intentarlo con una búsqueda diferente.\nEl resultado del segundo intento puede no ser exacto."
|
"tooltip": "Si no se encuentra la canción, el plugin vuelve a intentarlo con una búsqueda diferente.\nEl resultado del segundo intento puede no ser exacto."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Integración con el plugin Tuna de OBS",
|
"description": "Integración con el plugin Tuna de OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Evita que el reproductor aparezca al reproducir una canción",
|
||||||
|
"name": "Jugador discreto"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Añade un botón para cambiar entre el modo Vídeo/Canción. También puede eliminar opcionalmente toda la pestaña de vídeo",
|
"description": "Añade un botón para cambiar entre el modo Vídeo/Canción. También puede eliminar opcionalmente toda la pestaña de vídeo",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -53,7 +53,19 @@
|
|||||||
"quit": "Välju",
|
"quit": "Välju",
|
||||||
"relaunch": "Käivita uuesti",
|
"relaunch": "Käivita uuesti",
|
||||||
"wait": "Oota"
|
"wait": "Oota"
|
||||||
}
|
},
|
||||||
|
"detail": "Vabandame ebamugavuste pärast! Palun vali kuidas jätkata:",
|
||||||
|
"message": "Rakendus ei vasta ega reageeri",
|
||||||
|
"title": "Aken ei vasta ega reageeri"
|
||||||
|
},
|
||||||
|
"update-available": {
|
||||||
|
"buttons": {
|
||||||
|
"disable": "Lülita uuendused välja",
|
||||||
|
"download": "Laadi alla",
|
||||||
|
"ok": "Sobib"
|
||||||
|
},
|
||||||
|
"detail": "Saadaval on uus versioon, ning seda saad alla laadida siit {{downloadLink}}",
|
||||||
|
"message": "Uus versioon on saadaval"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -148,6 +160,23 @@
|
|||||||
"navigation": {
|
"navigation": {
|
||||||
"name": "Liikumine"
|
"name": "Liikumine"
|
||||||
},
|
},
|
||||||
|
"no-google-login": {
|
||||||
|
"description": "Eemalda kasutajaliidesest Google'i sisselogimisnupud",
|
||||||
|
"name": "Elu ilma Google'i sisselogimiseta"
|
||||||
|
},
|
||||||
|
"quality-changer": {
|
||||||
|
"backend": {
|
||||||
|
"dialog": {
|
||||||
|
"quality-changer": {
|
||||||
|
"detail": "Praegune kvaliteet: {{quality}}",
|
||||||
|
"message": "Vali video kvaliteet:",
|
||||||
|
"title": "Videokvaliteedi valik"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Võimaldab muuta video kvaliteeti nupust, mis asub video ülekattes",
|
||||||
|
"name": "Videokvaliteedi muutja"
|
||||||
|
},
|
||||||
"scrobbler": {
|
"scrobbler": {
|
||||||
"description": "Lisa kraasimise tugi (last.fm, Listenbrainz, jne)",
|
"description": "Lisa kraasimise tugi (last.fm, Listenbrainz, jne)",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "توکن کاربری ListenBrainz را وارد کنید"
|
"token": "توکن کاربری ListenBrainz را وارد کنید"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "از عناوین جایگزین استفاده کنید",
|
||||||
"scrobble-other-media": "ردیابی رسانههای دیگر"
|
"scrobble-other-media": "ردیابی رسانههای دیگر"
|
||||||
},
|
},
|
||||||
"name": "ابزار ثبتکنندهی آهنگ",
|
"name": "ابزار ثبتکنندهی آهنگ",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "هماهنگسازی کامل متن ترانه",
|
"label": "هماهنگسازی کامل متن ترانه",
|
||||||
"tooltip": "محاسبه دقیق نمایش خط بعدی تا میلیثانیه (ممکن است تاثیر کمی بر عملکرد داشته باشد)"
|
"tooltip": "محاسبه دقیق نمایش خط بعدی تا میلیثانیه (ممکن است تاثیر کمی بر عملکرد داشته باشد)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "اشعار رومی شده",
|
||||||
|
"tooltip": "اگر اشعار به زبانی متفاوت هستند، سعی کنید نسخه لاتین را نمایش دهید."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "نمایش متن ترانه ها حتی اگر دقیق نباشد",
|
"label": "نمایش متن ترانه ها حتی اگر دقیق نباشد",
|
||||||
"tooltip": "اگر آهنگ پیدا نشد، افزونه دوباره با یک جستجوی متفاوت امتحان میکند.\nنتیجهی این تلاش ممکن است دقیق نباشد."
|
"tooltip": "اگر آهنگ پیدا نشد، افزونه دوباره با یک جستجوی متفاوت امتحان میکند.\nنتیجهی این تلاش ممکن است دقیق نباشد."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "ادغام با پلاگین Tuna در OBS",
|
"description": "ادغام با پلاگین Tuna در OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "هنگام پخش یک آهنگ از پخش کننده جلوگیری می کند",
|
||||||
|
"name": "پخشکننده بی نظیر"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "دکمهای اضافه میکند برای جابجایی بین حالت ویدیو/آهنگ. همچنین به صورت اختیاری میتواند تب ویدیو را حذف کند",
|
"description": "دکمهای اضافه میکند برای جابجایی بین حالت ویدیو/آهنگ. همچنین به صورت اختیاری میتواند تب ویدیو را حذف کند",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -207,6 +207,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
|
"ad-speedup": {
|
||||||
|
"description": "Jos mainos toistuu, mykistä ääni ja aseta toistonopeus 16x:een",
|
||||||
|
"name": "Mainoksen nopeutus"
|
||||||
|
},
|
||||||
"adblocker": {
|
"adblocker": {
|
||||||
"description": "Estä kaikki mainokset ja seuranta",
|
"description": "Estä kaikki mainokset ja seuranta",
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -275,6 +279,9 @@
|
|||||||
},
|
},
|
||||||
"name": "Tunnelmallinen Tila"
|
"name": "Tunnelmallinen Tila"
|
||||||
},
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "Lisää YouTube Music tuen Amusen nyt soitetaan -widgetille, kehittäjänä 6K Labs"
|
||||||
|
},
|
||||||
"api-server": {
|
"api-server": {
|
||||||
"description": "Lisää API-palvelimen hallitsemaan soitinta",
|
"description": "Lisää API-palvelimen hallitsemaan soitinta",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -282,7 +289,9 @@
|
|||||||
"buttons": {
|
"buttons": {
|
||||||
"allow": "Hyväksy",
|
"allow": "Hyväksy",
|
||||||
"deny": "Kiellä"
|
"deny": "Kiellä"
|
||||||
}
|
},
|
||||||
|
"message": "Sallitaanko {{ID}} ({{origin}}) pääsy API:in?",
|
||||||
|
"title": "API vahvistuspyyntö"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -297,7 +306,12 @@
|
|||||||
"label": "Portti"
|
"label": "Portti"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "API Serveri [Beta]"
|
"name": "API Serveri [Beta]",
|
||||||
|
"prompt": {
|
||||||
|
"port": {
|
||||||
|
"title": "Portti"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"audio-compressor": {
|
"audio-compressor": {
|
||||||
"description": "Lisää äänen kompressointia (hiljentää voimakkaimpien äänien voimakkuutta ja tehostaa pehmeämpien äänien voimakkuutta)",
|
"description": "Lisää äänen kompressointia (hiljentää voimakkaimpien äänien voimakkuutta ja tehostaa pehmeämpien äänien voimakkuutta)",
|
||||||
@ -431,6 +445,15 @@
|
|||||||
"description": "Lataa MP3- tai lähdetiedoston suoraan käyttöliittymästä",
|
"description": "Lataa MP3- tai lähdetiedoston suoraan käyttöliittymästä",
|
||||||
"menu": {
|
"menu": {
|
||||||
"choose-download-folder": "Valitse latauskansio",
|
"choose-download-folder": "Valitse latauskansio",
|
||||||
|
"download-finish-settings": {
|
||||||
|
"prompt": {
|
||||||
|
"last-seconds": "Viimeiset x sekuntia"
|
||||||
|
},
|
||||||
|
"submenu": {
|
||||||
|
"enabled": "Päällä",
|
||||||
|
"percent": "Prosentti"
|
||||||
|
}
|
||||||
|
},
|
||||||
"download-playlist": "Lataa soittolista",
|
"download-playlist": "Lataa soittolista",
|
||||||
"presets": "Esiasetukset",
|
"presets": "Esiasetukset",
|
||||||
"skip-existing": "Ohita olemassa olevat tiedostot"
|
"skip-existing": "Ohita olemassa olevat tiedostot"
|
||||||
@ -585,6 +608,46 @@
|
|||||||
"label": "Valitse yleiset äänenvoimakkuuden pikanäppäimet:"
|
"label": "Valitse yleiset äänenvoimakkuuden pikanäppäimet:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"quality-changer": {
|
||||||
|
"backend": {
|
||||||
|
"dialog": {
|
||||||
|
"quality-changer": {
|
||||||
|
"detail": "Nykyinen laatu: {{quality}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scrobbler": {
|
||||||
|
"dialog": {
|
||||||
|
"lastfm": {
|
||||||
|
"auth-failed": {
|
||||||
|
"title": "Todennus epäonnistui"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shortcuts": {
|
||||||
|
"prompt": {
|
||||||
|
"keybind": {
|
||||||
|
"keybind-options": {
|
||||||
|
"previous": "Edellinen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tuna-obs": {
|
||||||
|
"name": "Tuna OBS"
|
||||||
|
},
|
||||||
|
"video-toggle": {
|
||||||
|
"menu": {
|
||||||
|
"align": {
|
||||||
|
"submenu": {
|
||||||
|
"left": "Vasen",
|
||||||
|
"right": "Oikea"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -584,6 +584,10 @@
|
|||||||
"save-window-position": "I-save ang posisyon ng window",
|
"save-window-position": "I-save ang posisyon ng window",
|
||||||
"save-window-size": "I-save ang laki ng window",
|
"save-window-size": "I-save ang laki ng window",
|
||||||
"use-native-pip": "Gamitin ang browser native na PiP"
|
"use-native-pip": "Gamitin ang browser native na PiP"
|
||||||
|
},
|
||||||
|
"name": "Picture-na-picture",
|
||||||
|
"templates": {
|
||||||
|
"button": "Picture-na-picture"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playback-speed": {
|
"playback-speed": {
|
||||||
@ -641,6 +645,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Ilagay ang user token ng ListenBrainz"
|
"token": "Ilagay ang user token ng ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Gumamit ng alternatibong mga title",
|
||||||
"scrobble-other-media": "Mag-Scrobble ng ibang media"
|
"scrobble-other-media": "Mag-Scrobble ng ibang media"
|
||||||
},
|
},
|
||||||
"prompt": {
|
"prompt": {
|
||||||
@ -719,6 +724,10 @@
|
|||||||
"label": "Gawing perpektong naka-sync ang lyrics",
|
"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)"
|
"tooltip": "Kalkulahin sa millisecond ang pagpapakita ng susunod na linya (maaaring magkaroon ng maliit na epekto sa performance)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "I-romanize ang lyrics",
|
||||||
|
"tooltip": "Kung ang lyrics ay nasa ibang wika, subukang magpakita ng latin na bersyon."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Ipakita ang lyrics kahit di-eksakto",
|
"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."
|
"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."
|
||||||
@ -728,6 +737,7 @@
|
|||||||
"tooltip": "Ipakita ang mga time code kasunod sa lyrics"
|
"tooltip": "Ipakita ang mga time code kasunod sa lyrics"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"name": "Pag-sync ng Lyrics",
|
||||||
"refetch-btn": {
|
"refetch-btn": {
|
||||||
"fetching": "Nag-fe-fetch...",
|
"fetching": "Nag-fe-fetch...",
|
||||||
"normal": "I-fetch muli ang lyrics"
|
"normal": "I-fetch muli ang lyrics"
|
||||||
@ -747,10 +757,15 @@
|
|||||||
"tuna-obs": {
|
"tuna-obs": {
|
||||||
"description": "Integrasyon kasama ang Tuna na OBS plugin"
|
"description": "Integrasyon kasama ang Tuna na OBS plugin"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Pinipigilan ang player na mag-pop up kapag nagpe-play ng kanta",
|
||||||
|
"name": "Hindi mapanghimasok na Player"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Idaragdag ng button na magpalit sa Video/Kanta na mode. maaari ding opsyonal na alisin ang tab ng video",
|
"description": "Idaragdag ng button na magpalit sa Video/Kanta na mode. maaari ding opsyonal na alisin ang tab ng video",
|
||||||
"menu": {
|
"menu": {
|
||||||
"align": {
|
"align": {
|
||||||
|
"label": "Pag-align",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"left": "Kaliwa",
|
"left": "Kaliwa",
|
||||||
"middle": "Gitna",
|
"middle": "Gitna",
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Entrer le token utilisateur de ListenBrainz"
|
"token": "Entrer le token utilisateur de ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Utiliser des titres alternatifs",
|
||||||
"scrobble-other-media": "Scrobbler d'autres médias"
|
"scrobble-other-media": "Scrobbler d'autres médias"
|
||||||
},
|
},
|
||||||
"name": "Scrobble",
|
"name": "Scrobble",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Rend les paroles parfaitement synchronisées",
|
"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)"
|
"tooltip": "Calcul à la milliseconde près l'affichage de la ligne suivante (peut avoir un faible impact sur les performances)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Romaniser les paroles",
|
||||||
|
"tooltip": "Si les paroles sont dans une autre langue, essayez de les afficher dans une version latine."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Afficher les paroles même si inexactes",
|
"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."
|
"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."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Intégration avec le plugin OBS Tuna",
|
"description": "Intégration avec le plugin OBS Tuna",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Empêche le lecteur de s'afficher quand un chanson est en lecture",
|
||||||
|
"name": "Lecteur Non-Intrusif"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Ajoute un bouton pour basculer entre le mode Vidéo/Chanson. peut également supprimer tout l'onglet vidéo",
|
"description": "Ajoute un bouton pour basculer entre le mode Vidéo/Chanson. peut également supprimer tout l'onglet vidéo",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -112,7 +112,7 @@
|
|||||||
"toggle-dev-tools": "שנה את מצב כלי המפתחים"
|
"toggle-dev-tools": "שנה את מצב כלי המפתחים"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"always-on-top": "תמיד מעל הכל",
|
"always-on-top": "השאר מקדימה",
|
||||||
"auto-update": "עדכון אוטומטי",
|
"auto-update": "עדכון אוטומטי",
|
||||||
"hide-menu": {
|
"hide-menu": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -185,9 +185,145 @@
|
|||||||
"label": "מראה",
|
"label": "מראה",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"force-reload": "התחל מחדש בכוח",
|
"force-reload": "התחל מחדש בכוח",
|
||||||
"reload": "טען מחדש"
|
"reload": "טען מחדש",
|
||||||
|
"reset-zoom": "גודל אמיתי",
|
||||||
|
"toggle-fullscreen": "מסך מלא",
|
||||||
|
"zoom-in": "התקרב",
|
||||||
|
"zoom-out": "התרחק"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tray": {
|
||||||
|
"next": "הבא",
|
||||||
|
"play-pause": "נגן/הפסק",
|
||||||
|
"previous": "הקודם",
|
||||||
|
"quit": "יציאה",
|
||||||
|
"restart": "הפעל מחדש",
|
||||||
|
"show": "הראה חלון",
|
||||||
|
"tooltip": {
|
||||||
|
"default": "יוטיוב מיוזיק",
|
||||||
|
"with-song-info": "יוטיוב מיוזיק: {{artist}} - {{title}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"ad-speedup": {
|
||||||
|
"description": "במקרה של פרסומת, הסאונד מושתק ומהירות הוידאו מוכפלת ב-16",
|
||||||
|
"name": "הגבר מהירות פרסומת"
|
||||||
|
},
|
||||||
|
"adblocker": {
|
||||||
|
"description": "חסום את כל המודעות והמעקב מחוץ לקופסה",
|
||||||
|
"menu": {
|
||||||
|
"blocker": "חוסם"
|
||||||
|
},
|
||||||
|
"name": "חוסם פרסומות"
|
||||||
|
},
|
||||||
|
"album-actions": {
|
||||||
|
"description": "מוסיף לחצני ביטול אהבתי, דיסלייק, 'אהבתי' ו'לא אהבתי' כדי להחיל זאת על כל השירים ברשימת השמעה או אלבום",
|
||||||
|
"name": "פעולות אלבום"
|
||||||
|
},
|
||||||
|
"album-color-theme": {
|
||||||
|
"description": "מחיל נושא דינמי ואפקטים חזותיים המבוססים על לוח הצבעים של האלבום",
|
||||||
|
"menu": {
|
||||||
|
"color-mix-ratio": {
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{ratio}}%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "ערכת נושא צבע אלבום"
|
||||||
|
},
|
||||||
|
"ambient-mode": {
|
||||||
|
"description": "מחיל אפקט תאורה על ידי הטלת צבעים עדינים מהסרטון, אל הרקע של המסך",
|
||||||
|
"menu": {
|
||||||
|
"blur-amount": {
|
||||||
|
"label": "כמות טשטוש",
|
||||||
|
"submenu": {
|
||||||
|
"pixels": "{{blurAmount}} פיקסלים"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buffer": {
|
||||||
|
"submenu": {
|
||||||
|
"buffer": "{{buffer}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"opacity": {
|
||||||
|
"label": "אֲטִימוּת",
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{opacity}}%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quality": {
|
||||||
|
"label": "אֵיכוּת",
|
||||||
|
"submenu": {
|
||||||
|
"pixels": "{{quality}} פיקסלים"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"label": "גוֹדֶל",
|
||||||
|
"submenu": {
|
||||||
|
"percent": "{{size}}%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"smoothness-transition": {
|
||||||
|
"submenu": {
|
||||||
|
"during": "במהלך {{interpolationTime}} שניות"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"use-fullscreen": {
|
||||||
|
"label": "שימוש במסך מלא"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "מצב אווירה"
|
||||||
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "מוסיף תמיכה ב-YouTube Music עבור הווידג'ט של Amuse המתנגן כעת על ידי 6K Labs"
|
||||||
|
},
|
||||||
|
"discord": {
|
||||||
|
"menu": {
|
||||||
|
"hide-github-button": "הסתר את לחצן הקישור של GitHub",
|
||||||
|
"play-on-youtube-music": "הפעל ביוטיוב מיוזיק",
|
||||||
|
"set-inactivity-timeout": "הגדר פסק זמן לחוסר פעילות"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"downloader": {
|
||||||
|
"backend": {
|
||||||
|
"dialog": {
|
||||||
|
"error": {
|
||||||
|
"title": "שגיאה בהורדה!"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"feedback": {
|
||||||
|
"downloading": "מוריד…",
|
||||||
|
"loading": "בטְעִינָה…",
|
||||||
|
"playlist-has-only-one-song": "לפלייליסט יש רק פריט אחד, מוריד אותו ישירות",
|
||||||
|
"playlist-id-not-found": "לא נמצא מזהה ID פלייליסט",
|
||||||
|
"preparing-file": "מכין קובץ…",
|
||||||
|
"saving": "שומר…",
|
||||||
|
"trying-to-get-playlist-id": "מנסה להשיג מזהה פלייליסט: {{playlistId}}",
|
||||||
|
"video-id-not-found": "הסרטון לא נמצא"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "מוריד MP3 / אודיו מקור ישירות מהממשק",
|
||||||
|
"menu": {
|
||||||
|
"choose-download-folder": "בחר תיקיית הורדה",
|
||||||
|
"download-finish-settings": {
|
||||||
|
"label": "הורדה בסיום",
|
||||||
|
"prompt": {
|
||||||
|
"last-percent": "אחרי x אחוזים",
|
||||||
|
"last-seconds": "נשארו x שניות",
|
||||||
|
"title": "הגדר מתי להוריד"
|
||||||
|
},
|
||||||
|
"submenu": {
|
||||||
|
"advanced": "מִתקַדֵם",
|
||||||
|
"enabled": "מופעל",
|
||||||
|
"percent": "אָחוּז",
|
||||||
|
"seconds": "שניות"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"presets": "הגדרות קבועות מראש",
|
||||||
|
"skip-existing": "דלג על קבצים קיימים"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -268,11 +268,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"smoothness-transition": {
|
"smoothness-transition": {
|
||||||
"label": "चिकनाई संक्रमण"
|
"label": "चिकनाई संक्रमण",
|
||||||
|
"submenu": {
|
||||||
|
"during": "दौरान {{interpolationTime}}"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"use-fullscreen": {
|
"use-fullscreen": {
|
||||||
"label": "पूर्णस्क्रीन का उपयोग"
|
"label": "पूर्णस्क्रीन का उपयोग"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"name": "अम्बिएन्ट मोड्"
|
||||||
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "6K लैब्स द्वारा Amuse now playing विजेट के लिए YouTube म्यूजिक समर्थन जोड़ा गया",
|
||||||
|
"name": "मन बहलाना",
|
||||||
|
"response": {
|
||||||
|
"query": "अमयूस ए.पि.ऐ. चल रहा है। गाने की जान्कारि होने के लिये GET /query कीजिये।"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"api-server": {
|
"api-server": {
|
||||||
|
|||||||
@ -3,7 +3,11 @@
|
|||||||
"console": {
|
"console": {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"execute-failed": "Neuspjelo izvršenje plugina {{pluginName}}::{{contextName}}",
|
"execute-failed": "Neuspjelo izvršenje plugina {{pluginName}}::{{contextName}}",
|
||||||
"executed-at-ms": "Plugin{{pluginName}}::{{contextName}}{{je izvršen za {{ms}}ms"
|
"executed-at-ms": "Plugin{{pluginName}}::{{contextName}}{{je izvršen za {{ms}}ms",
|
||||||
|
"initialize-failed": "Nije uspilo inicijalitirati plugin \"{{pluginName}}\"",
|
||||||
|
"load-all": "Učitavaju se svi plugini",
|
||||||
|
"load-failed": "Neuspješno ućitavanje plugina \"{{pluginName}}\"",
|
||||||
|
"loaded": "Plugin \"{{pluginName}}\" je učitan"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -11,5 +15,34 @@
|
|||||||
"code": "hr",
|
"code": "hr",
|
||||||
"local-name": "Hrvatski",
|
"local-name": "Hrvatski",
|
||||||
"name": "Croatian"
|
"name": "Croatian"
|
||||||
|
},
|
||||||
|
"main": {
|
||||||
|
"console": {
|
||||||
|
"i18n": {
|
||||||
|
"loaded": "i18n je učitan"
|
||||||
|
},
|
||||||
|
"second-instance": {
|
||||||
|
"receive-command": "Zaprimljena komanda preko protokola: \"{{command}}\""
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"css-file-not-found": "CSS fajl \"{{cssFile}}\" ne postoji, ignorišem"
|
||||||
|
},
|
||||||
|
"when-ready": {
|
||||||
|
"clearing-cache-after-20s": "Brisanje cache memorije u toku"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"hide-menu-enabled": {
|
||||||
|
"detail": "Meni je sakriven, pritisni 'Alt' da bi se prikazao (ili 'Escape' ako se koristi In-App Menu)",
|
||||||
|
"message": "Sakriveni Meni je uključen"
|
||||||
|
},
|
||||||
|
"need-to-restart": {
|
||||||
|
"buttons": {
|
||||||
|
"later": "Kasnije",
|
||||||
|
"restart-now": "Pokreni ponovo"
|
||||||
|
},
|
||||||
|
"detail": "\"{{pluginName}}\" dodatak zahtjeva pokretanje aplikacije ponovo da bi promjene bile vidljive"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Add meg a ListenBrainz felhasználói tokenedet"
|
"token": "Add meg a ListenBrainz felhasználói tokenedet"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Alternatív címek használata",
|
||||||
"scrobble-other-media": "Más média scrobbelése"
|
"scrobble-other-media": "Más média scrobbelése"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Dalszöveg tökéletes szinkronizálása",
|
"label": "Dalszöveg tökéletes szinkronizálása",
|
||||||
"tooltip": "Számítsa ki az aktuális sor megjelenítésének idejét ezredmásodperc pontossággal (ez kis mértékben befolyásolhatja a teljesítményt)"
|
"tooltip": "Számítsa ki az aktuális sor megjelenítésének idejét ezredmásodperc pontossággal (ez kis mértékben befolyásolhatja a teljesítményt)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Latin betűs szöveg",
|
||||||
|
"tooltip": "Idegennyelvű szöveg esetén próbálkozás a szöveglatin betűs megjelenítésével."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Pontatlan időzítésű dalszövegek megjelenítése",
|
"label": "Pontatlan időzítésű dalszövegek megjelenítése",
|
||||||
"tooltip": "Ha a dalt nem találja, a bővítmény újra próbálkozik egy másik keresési lekérdezéssel.\nAz eredmény a második próbálkozás után nem biztos, hogy pontos lesz."
|
"tooltip": "Ha a dalt nem találja, a bővítmény újra próbálkozik egy másik keresési lekérdezéssel.\nAz eredmény a második próbálkozás után nem biztos, hogy pontos lesz."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Integráció az OBS Tuna pluginjával",
|
"description": "Integráció az OBS Tuna pluginjával",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Megakadályozza a lejátszó felugrását zenehallgatás közben",
|
||||||
|
"name": "Rejtett lejátszó"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Hozzáad egy gombot a Videó/Dal mód közötti váltáshoz. Opcionálisan teljesen eltávolíthatja a videó fület is",
|
"description": "Hozzáad egy gombot a Videó/Dal mód közötti váltáshoz. Opcionálisan teljesen eltávolíthatja a videó fület is",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -768,6 +768,10 @@
|
|||||||
"label": "Buat liriknya tersinkronisasi dengan sempurna",
|
"label": "Buat liriknya tersinkronisasi dengan sempurna",
|
||||||
"tooltip": "Hitung hingga milidetik tampilan baris berikutnya (dapat berdampak kecil pada kinerja)"
|
"tooltip": "Hitung hingga milidetik tampilan baris berikutnya (dapat berdampak kecil pada kinerja)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Romanize Liriknya",
|
||||||
|
"tooltip": "Apabila lirik berada dalam bahasa berbeda, cobalah untuk menampilkan versi latinnya."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Tampilkan lirik meskipun tidak tepat",
|
"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."
|
"tooltip": "Jika lagu tidak ditemukan, plugin akan mencoba lagi dengan kueri pencarian yang berbeda.\nHasil dari percobaan kedua mungkin tidak tepat."
|
||||||
@ -800,6 +804,10 @@
|
|||||||
"description": "Integrasi dengan plugin Tuna OBS",
|
"description": "Integrasi dengan plugin Tuna OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Cegah pemutar musik muncul ketika memutar musik",
|
||||||
|
"name": "Pemutar simpel (tidak menganggu)"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Tambahkan tombol untuk beralih antara mode Lagu/Video. secara opsional juga dapat menghapus keseluruhan tab video",
|
"description": "Tambahkan tombol untuk beralih antara mode Lagu/Video. secara opsional juga dapat menghapus keseluruhan tab video",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -160,10 +160,10 @@
|
|||||||
"theme": {
|
"theme": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"button": {
|
"button": {
|
||||||
"cancel": "Cancella",
|
"cancel": "Annulla",
|
||||||
"remove": "Rimuovi"
|
"remove": "Rimuovi"
|
||||||
},
|
},
|
||||||
"remove-theme": "Sicuro di voler rimuovere il tema personalizzato?",
|
"remove-theme": "Sei sicuro di voler rimuovere il tema personalizzato?",
|
||||||
"remove-theme-message": "Questo rimuoverà il tema personalizzato"
|
"remove-theme-message": "Questo rimuoverà il tema personalizzato"
|
||||||
},
|
},
|
||||||
"label": "Tema",
|
"label": "Tema",
|
||||||
@ -495,7 +495,7 @@
|
|||||||
"description": "Aggiunge un equalizzatore al player",
|
"description": "Aggiunge un equalizzatore al player",
|
||||||
"menu": {
|
"menu": {
|
||||||
"presets": {
|
"presets": {
|
||||||
"label": "Presets",
|
"label": "Preset",
|
||||||
"list": {
|
"list": {
|
||||||
"bass-booster": "Booster dei bassi"
|
"bass-booster": "Booster dei bassi"
|
||||||
}
|
}
|
||||||
@ -734,8 +734,8 @@
|
|||||||
"synced-lyrics": {
|
"synced-lyrics": {
|
||||||
"description": "Fornisce testi sincronizzati alle canzoni, utilizzando provider come LRClib.",
|
"description": "Fornisce testi sincronizzati alle canzoni, utilizzando provider come LRClib.",
|
||||||
"errors": {
|
"errors": {
|
||||||
"fetch": "⚠️ - Si è verificato un errore nel recuperare il testo. Per favore riprova più tardi.",
|
"fetch": "⚠️ \tSi è verificato un errore nel recuperare il testo.\n\tPer favore riprova più tardi.",
|
||||||
"not-found": "⚠️ - Nessun testo trovato per questa canzone."
|
"not-found": "⚠️ Nessun testo trovato per questa canzone."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"default-text-string": {
|
"default-text-string": {
|
||||||
@ -767,6 +767,10 @@
|
|||||||
"label": "Rendi i testi perfettamente sincronizzati",
|
"label": "Rendi i testi perfettamente sincronizzati",
|
||||||
"tooltip": "Calcola al millisecondo la visualizzazione della riga successiva (può avere un piccolo impatto sulle prestazioni)"
|
"tooltip": "Calcola al millisecondo la visualizzazione della riga successiva (può avere un piccolo impatto sulle prestazioni)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Testi in caratteri occidentali",
|
||||||
|
"tooltip": "Qualora il testo fosse scritto in una lingua non occidentale, prova a visualizzarlo in caratteri latini."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Mostra le lyric anche se incorrette",
|
"label": "Mostra le lyric anche se incorrette",
|
||||||
"tooltip": "Se il brano non viene trovato, il plugin riprova con un'altra query di ricerca.\nIl risultato del secondo tentativo potrebbe non essere esatto."
|
"tooltip": "Se il brano non viene trovato, il plugin riprova con un'altra query di ricerca.\nIl risultato del secondo tentativo potrebbe non essere esatto."
|
||||||
@ -799,6 +803,10 @@
|
|||||||
"description": "Integrazione con il plugin OBS Tuna",
|
"description": "Integrazione con il plugin OBS Tuna",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Evita che il player si apra automaticamente durante la riproduzione di un brano",
|
||||||
|
"name": "Player Discreto"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Aggiunge un pulsante per passare dalla modalità Video a quella Brano. Può anche rimuovere l'intera scheda Brano/Video",
|
"description": "Aggiunge un pulsante per passare dalla modalità Video a quella Brano. Può anche rimuovere l'intera scheda Brano/Video",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -279,6 +279,13 @@
|
|||||||
},
|
},
|
||||||
"name": "アンビエント モード"
|
"name": "アンビエント モード"
|
||||||
},
|
},
|
||||||
|
"amuse": {
|
||||||
|
"description": "6K LabsのAmuse再生中ウィジェットがYouTube Musicに対応しました",
|
||||||
|
"name": "Amuse",
|
||||||
|
"response": {
|
||||||
|
"query": "AmuseのAPIサーバーが稼働中です。GET /query で楽曲情報を取得できます。"
|
||||||
|
}
|
||||||
|
},
|
||||||
"api-server": {
|
"api-server": {
|
||||||
"description": "プレイヤーを制御するAPIサーバーを追加",
|
"description": "プレイヤーを制御するAPIサーバーを追加",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -485,7 +492,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"equalizer": {
|
"equalizer": {
|
||||||
"description": "プレイヤーにイコライザーを追加",
|
"description": "イコライザーを追加",
|
||||||
"menu": {
|
"menu": {
|
||||||
"presets": {
|
"presets": {
|
||||||
"label": "プリセット",
|
"label": "プリセット",
|
||||||
@ -676,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "ListenBrainzユーザートークンを入力してください"
|
"token": "ListenBrainzユーザートークンを入力してください"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "代替タイトルを使用する",
|
||||||
"scrobble-other-media": "他のメディアをScrobbleする"
|
"scrobble-other-media": "他のメディアをScrobbleする"
|
||||||
},
|
},
|
||||||
"name": "スクロブラー",
|
"name": "スクロブラー",
|
||||||
@ -726,8 +734,8 @@
|
|||||||
"synced-lyrics": {
|
"synced-lyrics": {
|
||||||
"description": "LRClibのようなプロバイダを使って、楽曲に同期した歌詞を使用する。",
|
"description": "LRClibのようなプロバイダを使って、楽曲に同期した歌詞を使用する。",
|
||||||
"errors": {
|
"errors": {
|
||||||
"fetch": "⚠️ - 歌詞の取得中にエラーが発生しました。 後でもう一度お試しください。",
|
"fetch": "⚠️ \t歌詞の取得中にエラーが発生しました。\n\t後でもう一度お試しください。",
|
||||||
"not-found": "⚠️ - この曲の歌詞は見つかりませんでした。"
|
"not-found": "⚠️ この曲の歌詞は見つかりませんでした。"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"default-text-string": {
|
"default-text-string": {
|
||||||
@ -737,6 +745,10 @@
|
|||||||
"line-effect": {
|
"line-effect": {
|
||||||
"label": "歌詞表示のエフェクト",
|
"label": "歌詞表示のエフェクト",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "ファンシー",
|
||||||
|
"tooltip": "現在の行にアプリのような大きなエフェクトを使う"
|
||||||
|
},
|
||||||
"focus": {
|
"focus": {
|
||||||
"label": "フォーカス",
|
"label": "フォーカス",
|
||||||
"tooltip": "現在の行だけを白くする"
|
"tooltip": "現在の行だけを白くする"
|
||||||
@ -756,6 +768,10 @@
|
|||||||
"label": "歌詞を完璧に同期させる",
|
"label": "歌詞を完璧に同期させる",
|
||||||
"tooltip": "次の行の表示をミリ秒単位で計算する(パフォーマンスに若干の影響を与える可能性があります)"
|
"tooltip": "次の行の表示をミリ秒単位で計算する(パフォーマンスに若干の影響を与える可能性があります)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "ローマ字歌詞",
|
||||||
|
"tooltip": "歌詞が異なる言語で書かれている場合は、ラテン語バージョンを表示するようにしてください。"
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "歌詞が不正確でも表示する",
|
"label": "歌詞が不正確でも表示する",
|
||||||
"tooltip": "曲が見つからなかった場合、プラグインは別の検索クエリで再試行します。\nただし、再試行の結果は正確でない可能性があります。"
|
"tooltip": "曲が見つからなかった場合、プラグインは別の検索クエリで再試行します。\nただし、再試行の結果は正確でない可能性があります。"
|
||||||
@ -788,6 +804,10 @@
|
|||||||
"description": "OBSのプラグインTunaの統合",
|
"description": "OBSのプラグインTunaの統合",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "曲の再生時にプレーヤーがポップアップしないようにする",
|
||||||
|
"name": "控えめなプレーヤー"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "ビデオ/ソングモードを切り替えるボタンを追加します。オプションでビデオタブ全体を削除することもできます",
|
"description": "ビデオ/ソングモードを切り替えるボタンを追加します。オプションでビデオタブ全体を削除することもできます",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -7,7 +7,9 @@
|
|||||||
"initialize-failed": "პლაგინის ინიციალიზაცია ვერ მოხდა\"{{pluginName}}\"",
|
"initialize-failed": "პლაგინის ინიციალიზაცია ვერ მოხდა\"{{pluginName}}\"",
|
||||||
"load-all": "იტვირთება ყველა პლაგინი",
|
"load-all": "იტვირთება ყველა პლაგინი",
|
||||||
"load-failed": "პლაგინის ჩატვირთვა ვერ მოხდა \"{{pluginName}}\"",
|
"load-failed": "პლაგინის ჩატვირთვა ვერ მოხდა \"{{pluginName}}\"",
|
||||||
"loaded": "პლაგინი \"{{pluginName}}\" ჩაიტვირთა"
|
"loaded": "პლაგინი \"{{pluginName}}\" ჩაიტვირთა",
|
||||||
|
"unload-failed": "პლაგინის {{pluginName}} გათიშვა ვერ მოხერხდა",
|
||||||
|
"unloaded": "პლაგინი {{pluginName}} გათიშულია"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -17,6 +19,26 @@
|
|||||||
"name": "Georgian"
|
"name": "Georgian"
|
||||||
},
|
},
|
||||||
"main": {
|
"main": {
|
||||||
|
"console": {
|
||||||
|
"did-finish-load": {
|
||||||
|
"dev-tools": "ჩატვირთვა დასრულებულია. DevTools გახსნილია"
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"loaded": "i18n ჩართულია"
|
||||||
|
},
|
||||||
|
"second-instance": {
|
||||||
|
"receive-command": "მიღებულია ბრძანება პროტოკოლზე: {{command}}"
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"css-file-not-found": "CSS ფაილი {{cssFile}} არ არსებობს, იგნორირება"
|
||||||
|
},
|
||||||
|
"unresponsive": {
|
||||||
|
"details": "უპასუხო შეცდომა!\n{{error}}"
|
||||||
|
},
|
||||||
|
"when-ready": {
|
||||||
|
"clearing-cache-after-20s": "აპლიკაციის ქეშის გაწმენდვა"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"need-to-restart": {
|
"need-to-restart": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
|
|||||||
7
src/i18n/resources/kn.json
Normal file
7
src/i18n/resources/kn.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"language": {
|
||||||
|
"code": "kn",
|
||||||
|
"local-name": "ಕನ್ನಡ",
|
||||||
|
"name": "Kannada"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -600,6 +600,10 @@
|
|||||||
},
|
},
|
||||||
"name": "알림"
|
"name": "알림"
|
||||||
},
|
},
|
||||||
|
"performance-improvement": {
|
||||||
|
"description": "위험한 스크립트를 활성화하여 성능을 개선합니다",
|
||||||
|
"name": "성능 개선 [베타]"
|
||||||
|
},
|
||||||
"picture-in-picture": {
|
"picture-in-picture": {
|
||||||
"description": "앱을 PiP 모드로 전환할 수 있게 허용합니다",
|
"description": "앱을 PiP 모드로 전환할 수 있게 허용합니다",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
57
src/i18n/resources/ml.json
Normal file
57
src/i18n/resources/ml.json
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"common": {
|
||||||
|
"console": {
|
||||||
|
"plugins": {
|
||||||
|
"initialize-failed": "{{pluginName}}എന്ന പ്ലഗിൻ തുടങ്ങുന്നതിൽ പരാജയപെട്ടു",
|
||||||
|
"load-all": "എല്ലാ പ്ലേഗിനും ലോഡ് ചെയ്യുന്നു",
|
||||||
|
"loaded": "{{pluginName}} എന്ന പ്ലഗിൻ ലോഡ് ചെയ്തു",
|
||||||
|
"unloaded": "{{pluginName}} എന്ന പ്ലഗിൻ അൺലോഡ് ചെയ്തു"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"code": "ml",
|
||||||
|
"local-name": "മലയാളം",
|
||||||
|
"name": "Malayalam"
|
||||||
|
},
|
||||||
|
"main": {
|
||||||
|
"console": {
|
||||||
|
"did-finish-load": {
|
||||||
|
"dev-tools": "ലോഡിങ് തീർത്തു. DevTools തുറന്നു"
|
||||||
|
},
|
||||||
|
"i18n": {
|
||||||
|
"loaded": "i18n ലോഡ് ചെയ്തു"
|
||||||
|
},
|
||||||
|
"second-instance": {
|
||||||
|
"receive-command": "പ്രോട്ടോക്കോളിലൂടെ കമാൻഡ് ലഭിച്ചു : \"{{command}}\""
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"css-file-not-found": "\"{{cssFile}}\" എന്ന CSS file നിലവിൽ ഇല്ല. ഉപേക്ഷിക്കുന്നു"
|
||||||
|
},
|
||||||
|
"unresponsive": {
|
||||||
|
"details": "പ്രതികാരമില്ലാത്ത എറർ \n{{error}}"
|
||||||
|
},
|
||||||
|
"when-ready": {
|
||||||
|
"clearing-cache-after-20s": "ആപ്പ് cache ക്ലിയർ ചെയ്യുന്നു"
|
||||||
|
},
|
||||||
|
"window": {
|
||||||
|
"tried-to-render-offscreen": "Window സ്ക്രീനിനു വെളിയിൽ render ചെയ്യാൻ ശ്രമിച്ചു, windowSize={{windowSize}}, displaySize={{displaySize}}, position={{position}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"hide-menu-enabled": {
|
||||||
|
"detail": "Menu മറച്ചിരിക്കുന്നു, അവതരിപ്പിക്കാൻ 'Alt' ഉപയോഗിക്കു (In-App Menu ഉപയോഗിക്കുന്നെങ്കിൽ 'Escape' )",
|
||||||
|
"message": "Hide Menu പ്രവർത്തിയിൽ",
|
||||||
|
"title": "Hide Menu പ്രവർത്തിയിൽ"
|
||||||
|
},
|
||||||
|
"need-to-restart": {
|
||||||
|
"buttons": {
|
||||||
|
"later": "പിന്നീട",
|
||||||
|
"restart-now": "ഇപ്പോൾ പുനരാരംഭിക്കുക"
|
||||||
|
},
|
||||||
|
"detail": "\"{{pluginName}}\" പ്രവർത്തിയിൽ ആകാൻ restart വേണ്ടിയിരിക്കുന്നു",
|
||||||
|
"message": "\"{{pluginName}}\" restart ആവശ്യപെടുന്നു"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Voer het ListenBrainz-gebruikerstoken in"
|
"token": "Voer het ListenBrainz-gebruikerstoken in"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Gebruik alternatieve titels",
|
||||||
"scrobble-other-media": "Scrobble andere media"
|
"scrobble-other-media": "Scrobble andere media"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Zorg ervoor dat de songteksten perfect gesynchroniseerd zijn",
|
"label": "Zorg ervoor dat de songteksten perfect gesynchroniseerd zijn",
|
||||||
"tooltip": "Bereken tot op de milliseconde de weergave van de volgende regel (kan een kleine impact hebben op de prestaties)"
|
"tooltip": "Bereken tot op de milliseconde de weergave van de volgende regel (kan een kleine impact hebben op de prestaties)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Romaniseer songtekst",
|
||||||
|
"tooltip": "Als de songtekst in een andere taal is, probeer dan een Latijnse versie weer te geven."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Toon songteksten, zelfs als ze onnauwkeurig zijn",
|
"label": "Toon songteksten, zelfs als ze onnauwkeurig zijn",
|
||||||
"tooltip": "Als het nummer niet wordt gevonden, probeert de plug-in het opnieuw met een andere zoekopdracht.\nHet resultaat van de tweede poging is mogelijk niet exact."
|
"tooltip": "Als het nummer niet wordt gevonden, probeert de plug-in het opnieuw met een andere zoekopdracht.\nHet resultaat van de tweede poging is mogelijk niet exact."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Integratie met OBS's plug-in Tuna",
|
"description": "Integratie met OBS's plug-in Tuna",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Voorkomt dat de speler bij het afspelen van een nummer verschijnt",
|
||||||
|
"name": "Minder opdringerige speler"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Voegt een knop toe om te schakelen tussen de video-/nummermodus. kan optioneel ook het hele videotabblad verwijderen",
|
"description": "Voegt een knop toe om te schakelen tussen de video-/nummermodus. kan optioneel ook het hele videotabblad verwijderen",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -364,7 +364,7 @@
|
|||||||
"name": "Kompaktowy pasek boczny"
|
"name": "Kompaktowy pasek boczny"
|
||||||
},
|
},
|
||||||
"crossfade": {
|
"crossfade": {
|
||||||
"description": "Przenikanie pomiędzy utworami",
|
"description": "Pozwól odtwarzaczowi płynnie przechodzić między utworami",
|
||||||
"menu": {
|
"menu": {
|
||||||
"advanced": "Zaawansowane"
|
"advanced": "Zaawansowane"
|
||||||
},
|
},
|
||||||
@ -768,6 +768,10 @@
|
|||||||
"label": "Zsynchronizuj tekst utworu do perfekcji",
|
"label": "Zsynchronizuj tekst utworu do perfekcji",
|
||||||
"tooltip": "Wylicz czas wyświetlania następnej linijki co do milisekundy (może mieć mały wpływ na wydajność systemu)"
|
"tooltip": "Wylicz czas wyświetlania następnej linijki co do milisekundy (może mieć mały wpływ na wydajność systemu)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Romanizacja utworów",
|
||||||
|
"tooltip": "Jeżeli tekst piosenki nie jest w alfabecie łacińskim, poddaje ją romanizacji, czyli przedstawia mowy za pomocą owych liter."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Pokaż teksty, mimo niezgodności",
|
"label": "Pokaż teksty, mimo niezgodności",
|
||||||
"tooltip": "Jeżeli nie znaleziono tekstu piosenki z bazy danych, wtyczka spróbuje ponownie przez wyszukanie przybliżonej frazy.\nNależy jednak pamiętać, że następne próby mogą nie być trafne co do oryginału."
|
"tooltip": "Jeżeli nie znaleziono tekstu piosenki z bazy danych, wtyczka spróbuje ponownie przez wyszukanie przybliżonej frazy.\nNależy jednak pamiętać, że następne próby mogą nie być trafne co do oryginału."
|
||||||
@ -800,6 +804,10 @@
|
|||||||
"description": "Integracja z wtyczką OBS Tuna",
|
"description": "Integracja z wtyczką OBS Tuna",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Zapobiega wyświetlaniu się ekranu z utworem po wybraniu innego tytułu",
|
||||||
|
"name": "Niewidoczny odtwarzacz"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Dodaje przycisk do przełączania między trybem wideo a piosenki. Może również opcjonalnie usunąć całą kartę wideo",
|
"description": "Dodaje przycisk do przełączania między trybem wideo a piosenki. Może również opcjonalnie usunąć całą kartę wideo",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Insira o token de usuário ListenBrainz"
|
"token": "Insira o token de usuário ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Usar títulos alternativos",
|
||||||
"scrobble-other-media": "Scrobble outras mídias"
|
"scrobble-other-media": "Scrobble outras mídias"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Deixa as letras perfeitamente sincronizadas",
|
"label": "Deixa as letras perfeitamente sincronizadas",
|
||||||
"tooltip": "Calcular até o milissegundo a exibição da próxima linha (pode ter um pequeno impacto no desempenho)"
|
"tooltip": "Calcular até o milissegundo a exibição da próxima linha (pode ter um pequeno impacto no desempenho)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Letras romanizadas",
|
||||||
|
"tooltip": "Se as letras estiverem em um idioma diferente, tente exibir uma versão latina."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Mostrar letras mesmo que não sejam exatas",
|
"label": "Mostrar letras mesmo que não sejam exatas",
|
||||||
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
|
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Integração com o plugin Tuna do OBS",
|
"description": "Integração com o plugin Tuna do OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Evita que o player apareça ao tocar uma música",
|
||||||
|
"name": "Player discreto"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Adiciona um botão para alternar entre o modo Vídeo/Música. Também é possível remover opcionalmente toda a aba de vídeo",
|
"description": "Adiciona um botão para alternar entre o modo Vídeo/Música. Também é possível remover opcionalmente toda a aba de vídeo",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Introduza o token de utilizador do ListenBrainz"
|
"token": "Introduza o token de utilizador do ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Usar títulos alternativos",
|
||||||
"scrobble-other-media": "Scrobble de outros conteúdos"
|
"scrobble-other-media": "Scrobble de outros conteúdos"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Fazer com que as letras estejam perfeitamente sincronizadas",
|
"label": "Fazer com que as letras estejam perfeitamente sincronizadas",
|
||||||
"tooltip": "Calcular ao milissegundo a visualização da linha seguinte (pode ter um pequeno impacto no desempenho)"
|
"tooltip": "Calcular ao milissegundo a visualização da linha seguinte (pode ter um pequeno impacto no desempenho)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Letras Romanas",
|
||||||
|
"tooltip": "Se as letras estiverem numa linguagem diferente, tente mostrar uma versão em latim."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Mostrar as letras, mesmo que sejam imprecisas",
|
"label": "Mostrar as letras, mesmo que sejam imprecisas",
|
||||||
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
|
"tooltip": "Se a música não for encontrada, o plugin tenta novamente com uma consulta de pesquisa diferente.\nO resultado da segunda tentativa pode não ser exato."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Integração com o plugin Tuna do OBS",
|
"description": "Integração com o plugin Tuna do OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Previne o programa de aparecer enquanto toca uma música",
|
||||||
|
"name": "Reprodutor não obstrutivo"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Adiciona um botão para alternar entre o modo Vídeo/ Música. Opcionalmente, também pode remover completamente o separador do vídeo",
|
"description": "Adiciona um botão para alternar entre o modo Vídeo/ Música. Opcionalmente, também pode remover completamente o separador do vídeo",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -768,6 +768,10 @@
|
|||||||
"label": "Идеально синхронизировать слова",
|
"label": "Идеально синхронизировать слова",
|
||||||
"tooltip": "До миллисекунды рассчитывает отображение следующей строки(может оказать небольшое влияние на производительность)"
|
"tooltip": "До миллисекунды рассчитывает отображение следующей строки(может оказать небольшое влияние на производительность)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Романизировать слова",
|
||||||
|
"tooltip": "Если слова на другом языке, пытаться отображать версию на латинице."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Показывать слова, даже если неточные",
|
"label": "Показывать слова, даже если неточные",
|
||||||
"tooltip": "Если песня не найдена, плагин попытается снова с другим поисковым запросом.\nСо второй попытки результат может быть неточным."
|
"tooltip": "Если песня не найдена, плагин попытается снова с другим поисковым запросом.\nСо второй попытки результат может быть неточным."
|
||||||
@ -800,6 +804,10 @@
|
|||||||
"description": "Интеграция с плагином Tuna от OBS",
|
"description": "Интеграция с плагином Tuna от OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Предотвращает выскакивание плеера при воспроизведении",
|
||||||
|
"name": "Ненавязчивый плеер"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Добавляет кнопку для переключения между режимами видео и песни. Также можно удалить всю вкладку с видео",
|
"description": "Добавляет кнопку для переключения между режимами видео и песни. Также можно удалить всю вкладку с видео",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -7,9 +7,9 @@
|
|||||||
"initialize-failed": "\"{{pluginName}}\" ප්ලගිනය ආරම්භ කිරීමට අසමත් විය",
|
"initialize-failed": "\"{{pluginName}}\" ප්ලගිනය ආරම්භ කිරීමට අසමත් විය",
|
||||||
"load-all": "සියලුම ප්ලගින පූරණය කරමින්",
|
"load-all": "සියලුම ප්ලගින පූරණය කරමින්",
|
||||||
"load-failed": "\"{{pluginName}}\" ප්ලගිනය පූරණය කිරීමට අසමත් විය",
|
"load-failed": "\"{{pluginName}}\" ප්ලගිනය පූරණය කිරීමට අසමත් විය",
|
||||||
"loaded": "ප්ලගිනය \"{{pluginName}}\" පූරණය කරන ලදී",
|
"loaded": "\"{{pluginName}}\" ප්ලගිනය පූරණය විය",
|
||||||
"unload-failed": "ප්ලගින් \"{{pluginName}}\" ගලවන්න අසාර්ථක වුන",
|
"unload-failed": "\"{{pluginName}}\" ප්ලගිනය යළි ඉවත් කිරීමට අසාර්ථක විය",
|
||||||
"unloaded": "ප්ලගින් \"{{pluginName}}\" ගැලෙව්වා"
|
"unloaded": "\"{{pluginName}}\" ප්ලගිනය යළි ඉවත් කරන ලදී"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -21,36 +21,39 @@
|
|||||||
"main": {
|
"main": {
|
||||||
"console": {
|
"console": {
|
||||||
"did-finish-load": {
|
"did-finish-load": {
|
||||||
"dev-tools": "පූරණය සම්පුර්නි. ඩෙව්ටූල්ස් ඇරිලා"
|
"dev-tools": "පූරණය අවසන්. DevTools විවෘත වී ඇත"
|
||||||
},
|
},
|
||||||
"i18n": {
|
"i18n": {
|
||||||
"loaded": "i18n පූරණය කර ඇත"
|
"loaded": "i18n පූරණය කරන ලදී"
|
||||||
},
|
},
|
||||||
"second-instance": {
|
"second-instance": {
|
||||||
"receive-command": "ප්රෝටෝකාල් හරහා විධානය ලැබුණි: \"{{command}}\""
|
"receive-command": "ප්රෝටෝකාල් හරහා විධානය ලැබුණි: \"{{command}}\""
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"css-file-not-found": "සීඑස්එස් ගොනුව \"{{cssFile}}\" නොපවතී, නොසලකා හැරීම"
|
"css-file-not-found": "css ගොනුව \"{{cssFile}}\" නොපවතී, නොසලකා හරී"
|
||||||
},
|
},
|
||||||
"unresponsive": {
|
"unresponsive": {
|
||||||
"details": "ප්රතිචාර නොදක්වන දෝෂයක්\n{{error}}"
|
"details": "ප්රතිචාර නොදක්වයි, දෝෂයක්\n{{error}}"
|
||||||
},
|
},
|
||||||
"when-ready": {
|
"when-ready": {
|
||||||
"clearing-cache-after-20s": "යෙදුම් කෑශ් නිදහස් කරමින්"
|
"clearing-cache-after-20s": "යෙදුමේ දත්ත සංචිතය හිස් කරමින්"
|
||||||
|
},
|
||||||
|
"window": {
|
||||||
|
"tried-to-render-offscreen": "වින්ඩෝව තිරයෙන් පිටත පෙන්වීමට උත්සාහ කළේය, වින්ඩෝවේ ප්රමාණය={{windowSize}}, තිරයෙ ප්රමාණය={{displaySize}}, පිහිටීම={{position}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"hide-menu-enabled": {
|
"hide-menu-enabled": {
|
||||||
"detail": "මෙනුව සැගවී ඇත, නැවත පෙන්වීමට 'Alt' යතුර භාවිතා කරන්න. (හෝ In-App මෙනුවේ 'Escape')",
|
"detail": "මෙනුව සැගවී ඇත, නැවත පෙන්වීමට 'Alt' යතුර භාවිතා කරන්න. (හෝ In-App මෙනුවේ 'Escape')",
|
||||||
"message": "මෙනුව සැගවීම සාර්තකයි",
|
"message": "මෙනුව සැගවීම සක්රීය කර ඇත",
|
||||||
"title": "මෙනුව සැගවීම සක්රීයයි"
|
"title": "මෙනුව සැගවීම සක්රීයයි"
|
||||||
},
|
},
|
||||||
"need-to-restart": {
|
"need-to-restart": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"later": "පසුව",
|
"later": "පසුව",
|
||||||
"restart-now": "යෙදුම වසා නැවත ආරම්භ කරන්න"
|
"restart-now": "නැවත ආරම්භ කරන්න"
|
||||||
},
|
},
|
||||||
"detail": "\"{{pluginName}}\" ප්ලගිනය යෙදුම නැවත ආරම්භ කිරීමක් ඉල්ලයි",
|
"detail": "\"{{pluginName}}\" ප්ලගිනය ක්රියාත්මක වීමට නැවත ආරම්භ කිරීමක් අවශ්යයි",
|
||||||
"message": "\"{{pluginName}}\" නැවත ආරම්භ කළ යුතුය",
|
"message": "\"{{pluginName}}\" නැවත ආරම්භ කළ යුතුය",
|
||||||
"title": "නැවත ආරම්භ කිරීම අවශ්යයි"
|
"title": "නැවත ආරම්භ කිරීම අවශ්යයි"
|
||||||
},
|
},
|
||||||
@ -66,8 +69,8 @@
|
|||||||
},
|
},
|
||||||
"update-available": {
|
"update-available": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"disable": "යාවත්කාලීන කිරීම් නවතන්න",
|
"disable": "යාවත්කාලීන කිරීම් අක්රිය කරන්න",
|
||||||
"download": "බාගත කිරීම",
|
"download": "බාගත කරන්න",
|
||||||
"ok": "හරි"
|
"ok": "හරි"
|
||||||
},
|
},
|
||||||
"detail": "නව අනුවාදයක් ඇති අතර එය මෙයින් බාගන්න {{downloadLink}}",
|
"detail": "නව අනුවාදයක් ඇති අතර එය මෙයින් බාගන්න {{downloadLink}}",
|
||||||
|
|||||||
7
src/i18n/resources/sr.json
Normal file
7
src/i18n/resources/sr.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"language": {
|
||||||
|
"code": "sr",
|
||||||
|
"local-name": "Српски",
|
||||||
|
"name": "Serbian"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -99,17 +99,29 @@
|
|||||||
"auto-reset-app-cache": "Nollställ appcache när appen startar",
|
"auto-reset-app-cache": "Nollställ appcache när appen startar",
|
||||||
"disable-hardware-acceleration": "Stäng av hårdvaruacceleration",
|
"disable-hardware-acceleration": "Stäng av hårdvaruacceleration",
|
||||||
"edit-config-json": "Redigera config.json",
|
"edit-config-json": "Redigera config.json",
|
||||||
|
"override-user-agent": "Ersätt User-Agent",
|
||||||
"restart-on-config-changes": "Starta om vid konfigurationsändringar",
|
"restart-on-config-changes": "Starta om vid konfigurationsändringar",
|
||||||
"set-proxy": {
|
"set-proxy": {
|
||||||
"label": "Ställ in proxy",
|
"label": "Ställ in proxy",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
|
"label": "Ange Proxy-adress: (lämna tomt för att inaktivera)",
|
||||||
|
"placeholder": "Exempel: SOCKS5://127.0.0.1:9999",
|
||||||
"title": "Ställ in proxy"
|
"title": "Ställ in proxy"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"toggle-dev-tools": "Utvecklarverktyg"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"always-on-top": "Alltid överst",
|
"always-on-top": "Alltid överst",
|
||||||
"auto-update": "Uppdatera automatiskt"
|
"auto-update": "Uppdatera automatiskt",
|
||||||
|
"language": {
|
||||||
|
"dialog": {
|
||||||
|
"message": "Språket ändras efter omstart",
|
||||||
|
"title": "Språket har ändrats"
|
||||||
|
},
|
||||||
|
"label": "Språk"
|
||||||
|
},
|
||||||
|
"resume-on-start": "Fortsätt spela när appen öppnas"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,9 +14,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"code": "என்",
|
"code": "ta",
|
||||||
"local-name": "ஆங்கிலம்",
|
"local-name": "தமிழ்",
|
||||||
"name": "ஆங்கிலம்"
|
"name": "Tamil"
|
||||||
},
|
},
|
||||||
"main": {
|
"main": {
|
||||||
"console": {
|
"console": {
|
||||||
@ -444,7 +444,7 @@
|
|||||||
"download-info": "பதிவிறக்கம் {{artist}} - {{title}} [{{videoId}}}",
|
"download-info": "பதிவிறக்கம் {{artist}} - {{title}} [{{videoId}}}",
|
||||||
"download-progress": "பதிவிறக்கம்: {{percent}}%",
|
"download-progress": "பதிவிறக்கம்: {{percent}}%",
|
||||||
"downloading": "பதிவிறக்கம்…",
|
"downloading": "பதிவிறக்கம்…",
|
||||||
"downloading-counter": "பதிவிறக்கம் {{current}}/{{{total}}…",
|
"downloading-counter": "பதிவிறக்கம் {{current}}/{{total}}…",
|
||||||
"downloading-playlist": "பிளேலிச்ட்டைப் பதிவிறக்குதல் \"{{playlistTitle}}\" - {{playlistSize}} பாடல்கள் ({{playlistId}})",
|
"downloading-playlist": "பிளேலிச்ட்டைப் பதிவிறக்குதல் \"{{playlistTitle}}\" - {{playlistSize}} பாடல்கள் ({{playlistId}})",
|
||||||
"error-while-downloading": "பிழை \"{{author}} - {{title}}\": {{error}}",
|
"error-while-downloading": "பிழை \"{{author}} - {{title}}\": {{error}}",
|
||||||
"folder-already-exists": "{{playlistFolder}}} ஏற்கனவே உள்ளது",
|
"folder-already-exists": "{{playlistFolder}}} ஏற்கனவே உள்ளது",
|
||||||
@ -667,7 +667,7 @@
|
|||||||
"name": "வீடியோ தர மாற்றி"
|
"name": "வீடியோ தர மாற்றி"
|
||||||
},
|
},
|
||||||
"scrobbler": {
|
"scrobbler": {
|
||||||
"description": "ச்க்ரோப்ளிங் ஆதரவைச் சேர்க்கவும் (முதலியன.",
|
"description": "ச்க்ரோப்ளிங் ஆதரவைச் சேர் (last.fm, Listenbrainz முதலியன)",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"lastfm": {
|
"lastfm": {
|
||||||
"auth-failed": {
|
"auth-failed": {
|
||||||
@ -700,7 +700,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"description": "பிளேபேக்கிற்கான உலகளாவிய ஆட்கீசை அமைக்க அனுமதிக்கிறது (நாடகம்/இடைநிறுத்தம்/அடுத்த/முந்தைய) மீடியா விசைகளை மீறுவதன் மூலம் மீடியா ஓ.எச்.டி.",
|
"description": "பிளேபேக்கிற்கான உலகளாவிய ஆட்கீசை அமைக்க அனுமதிக்கிறது (நாடகம்/இடைநிறுத்தம்/அடுத்த/முந்தைய) மீடியா விசைகளை மீறுவதன் மூலம் மீடியா ஓஎச்டி",
|
||||||
"menu": {
|
"menu": {
|
||||||
"override-media-keys": "மீடியா விசைகளை மேலெழுதவும்",
|
"override-media-keys": "மீடியா விசைகளை மேலெழுதவும்",
|
||||||
"set-keybinds": "உலகளாவிய பாடல் கட்டுப்பாடுகளை அமைக்கவும்"
|
"set-keybinds": "உலகளாவிய பாடல் கட்டுப்பாடுகளை அமைக்கவும்"
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "ใส่ user token ของ ListenBrainz"
|
"token": "ใส่ user token ของ ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "ใช้ชื่ออื่น",
|
||||||
"scrobble-other-media": "บันทึกการเล่นสื่ออื่นๆ"
|
"scrobble-other-media": "บันทึกการเล่นสื่ออื่นๆ"
|
||||||
},
|
},
|
||||||
"name": "บันทึกการเล่น (Scrobbler)",
|
"name": "บันทึกการเล่น (Scrobbler)",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "ให้เนื้อเพลงตรงกับเพลงเป๊ะๆ",
|
"label": "ให้เนื้อเพลงตรงกับเพลงเป๊ะๆ",
|
||||||
"tooltip": "คำนวณมิลิวินาทีในการแสดงบรรทัดถัดไป (มีผลเล็กน้อยกับประสิทธิภาพการทำงาน)"
|
"tooltip": "คำนวณมิลิวินาทีในการแสดงบรรทัดถัดไป (มีผลเล็กน้อยกับประสิทธิภาพการทำงาน)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "เนื้อเพลงตัวด้วยอักษรโรมัน",
|
||||||
|
"tooltip": "ถ้าหากเนื้อเพลงอยู่ในภาษาอื่น ลองเปลี่ยนการแสดงผลโดยใช้เวอร์ชั่นลาติน"
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "แสดงเนื้อเพลงแม้ไม่ตรงเป๊ะ",
|
"label": "แสดงเนื้อเพลงแม้ไม่ตรงเป๊ะ",
|
||||||
"tooltip": "ถ้าหาเนื้อเพลงไม่เจอจะลองหาด้วยคำค้นหาที่ต่างกัน\nอาจได้เนื้อเพลงไม่ตรง"
|
"tooltip": "ถ้าหาเนื้อเพลงไม่เจอจะลองหาด้วยคำค้นหาที่ต่างกัน\nอาจได้เนื้อเพลงไม่ตรง"
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "ใช้งานร่วมกันกับปลั้กอิน Tuna บน OBS",
|
"description": "ใช้งานร่วมกันกับปลั้กอิน Tuna บน OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "ป้องกันเครื่องเล่นแสดงขึ้นเมื่อเริ่มเล่นเพลง",
|
||||||
|
"name": "เครื่องเล่นที่ไม่รบกวน"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "เพิ่มปุ่มสลับระหว่างโหมดเพลงกับโหมดวิดีโอ หรือลบแถบวิดีโอออกทั้งแถบ",
|
"description": "เพิ่มปุ่มสลับระหว่างโหมดเพลงกับโหมดวิดีโอ หรือลบแถบวิดีโอออกทั้งแถบ",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "ListenBrainz kullanıcı kimliğinizi girin"
|
"token": "ListenBrainz kullanıcı kimliğinizi girin"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Alternatif başlıklar kullan",
|
||||||
"scrobble-other-media": "Diğer medya ortamlarında listele"
|
"scrobble-other-media": "Diğer medya ortamlarında listele"
|
||||||
},
|
},
|
||||||
"name": "Listeleyici",
|
"name": "Listeleyici",
|
||||||
@ -767,6 +768,10 @@
|
|||||||
"label": "Şarkı sözlerini mükemmel şekilde senkronize edin",
|
"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)"
|
"tooltip": "Bir sonraki satırın görüntülenmesini milisaniyesine kadar hesaplayın (performans üzerinde küçük bir etkisi olabilir)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Sözleri Romanize Et",
|
||||||
|
"tooltip": "Sözler başka bir dilde gözüküyorsa, Latin versiyonunu dene."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Kesin olmasa bile şarkı sözlerini gösterin",
|
"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."
|
"tooltip": "Şarkı bulunamazsa, eklenti farklı bir arama sorgusuyla tekrar dener. \nİkinci denemenin sonucu tam olmayabilir."
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "OBS eklentisi Tuna ile entegrasyon sağlar",
|
"description": "OBS eklentisi Tuna ile entegrasyon sağlar",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Müzik oynatıcının şarkı çalarken saçmalamasını engeller",
|
||||||
|
"name": "Göze Batmayan Çalar"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Video/Şarkı modu arasında geçiş yapmak için bir düğme ekler. ayrıca isteğe bağlı olarak tüm video sekmesini kaldırabilir",
|
"description": "Video/Şarkı modu arasında geçiş yapmak için bir düğme ekler. ayrıca isteğe bağlı olarak tüm video sekmesini kaldırabilir",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -683,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Ввести токен користувача ListenBrainz"
|
"token": "Ввести токен користувача ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Використовувати альтернативні назви",
|
||||||
"scrobble-other-media": "Скробилити інші медіа"
|
"scrobble-other-media": "Скробилити інші медіа"
|
||||||
},
|
},
|
||||||
"name": "Скроблер",
|
"name": "Скроблер",
|
||||||
@ -758,7 +759,7 @@
|
|||||||
},
|
},
|
||||||
"scale": {
|
"scale": {
|
||||||
"label": "Масштабувати",
|
"label": "Масштабувати",
|
||||||
"tooltip": "Масштабуваты поточну лінію"
|
"tooltip": "Масштабувати поточну лінію"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tooltip": "Виберіть ефект, який потрібно застосувати до поточної лінії"
|
"tooltip": "Виберіть ефект, який потрібно застосувати до поточної лінії"
|
||||||
@ -767,13 +768,17 @@
|
|||||||
"label": "Зробити текст пісні ідеально синхронізованим",
|
"label": "Зробити текст пісні ідеально синхронізованим",
|
||||||
"tooltip": "Обчисли до мілісекунд відображення наступного рядка (може мати невеликий вплив на продуктивність)"
|
"tooltip": "Обчисли до мілісекунд відображення наступного рядка (може мати невеликий вплив на продуктивність)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "Транслітерувати текст пісень",
|
||||||
|
"tooltip": "Якщо текст пісні іншою мовою, спробувати його відобразити латинською версією."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Показувати текст пісні, навіть якщо він неточний",
|
"label": "Показувати текст пісні, навіть якщо він неточний",
|
||||||
"tooltip": "Якщо пісня не знайдена, плагін повторює спробу з іншим пошуковим запитом.\nРезультат з другої спроби може бути не точним."
|
"tooltip": "Якщо пісня не знайдена, плагін повторює спробу з іншим пошуковим запитом.\nРезультат з другої спроби може бути не точним."
|
||||||
},
|
},
|
||||||
"show-time-codes": {
|
"show-time-codes": {
|
||||||
"label": "Показувати часові марки",
|
"label": "Відображати часові коди",
|
||||||
"tooltip": "Показує часові маркы поруч із текстом пісні"
|
"tooltip": "Відображати часові коди біля тексту"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "Синхронізовані тексти",
|
"name": "Синхронізовані тексти",
|
||||||
@ -799,6 +804,10 @@
|
|||||||
"description": "Інтеграція з плагіном Tuna для OBS",
|
"description": "Інтеграція з плагіном Tuna для OBS",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "Запобігання спливання плеєру під час відтворення пісні",
|
||||||
|
"name": "Ненав'язливий програвач"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "Додає кнопку для перемикання між режимом відео і режимом пісні. Також може опціонально видаляти вкладку відео",
|
"description": "Додає кнопку для перемикання між режимом відео і режимом пісні. Також може опціонально видаляти вкладку відео",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -125,10 +125,80 @@
|
|||||||
"dialog": {
|
"dialog": {
|
||||||
"message": "دوبارہ شروع کرنے کے بعد زبان بدل دی جائے گی",
|
"message": "دوبارہ شروع کرنے کے بعد زبان بدل دی جائے گی",
|
||||||
"title": "زبان بدل گئی ہے"
|
"title": "زبان بدل گئی ہے"
|
||||||
|
},
|
||||||
|
"label": "زبان",
|
||||||
|
"submenu": {
|
||||||
|
"to-help-translate": "ترجمہ میں مدد کرنا چاہتے ہیں؟ یہاں دبائیں"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resume-on-start": "ایپ شروع ہونے پر آخری گانا دوبارہ شروع کریں",
|
||||||
|
"single-instance-lock": "ایک واحد مثال لاک",
|
||||||
|
"start-at-login": "لاگ ان پر شروع کریں",
|
||||||
|
"starting-page": {
|
||||||
|
"label": "شروعاتی صفحہ",
|
||||||
|
"unset": "غیر متعین"
|
||||||
|
},
|
||||||
|
"tray": {
|
||||||
|
"label": "سسٹم ٹرے",
|
||||||
|
"submenu": {
|
||||||
|
"disabled": "غیر فعال",
|
||||||
|
"enabled-and-hide-app": "فعال اور ایپ کو چھپائیں",
|
||||||
|
"enabled-and-show-app": "فعال اور ایپ دکھائیں",
|
||||||
|
"play-pause-on-click": "دبانے پر چلائیں/روکیں"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"visual-tweaks": {
|
||||||
|
"label": "بصری تبدیلیاں",
|
||||||
|
"submenu": {
|
||||||
|
"like-buttons": {
|
||||||
|
"default": "پہلے سے طے شدہ",
|
||||||
|
"force-show": "زبردستی دکھائیں",
|
||||||
|
"hide": "چھپائیں",
|
||||||
|
"label": "لائیک بٹن"
|
||||||
|
},
|
||||||
|
"remove-upgrade-button": "اپ گریڈ بٹن ہٹائیں",
|
||||||
|
"theme": {
|
||||||
|
"dialog": {
|
||||||
|
"button": {
|
||||||
|
"cancel": "منسوخ کریں",
|
||||||
|
"remove": "ہٹائیں"
|
||||||
|
},
|
||||||
|
"remove-theme": "کیا آپ واقعی کسٹم تھیم کو ہٹانا چاہتے ہیں؟",
|
||||||
|
"remove-theme-message": "یہ کسٹم تھیم کو ہٹا دے گا"
|
||||||
|
},
|
||||||
|
"label": "تھیم",
|
||||||
|
"submenu": {
|
||||||
|
"import-css-file": "کسٹم CSS فائل درآمد کریں",
|
||||||
|
"no-theme": "کوئی تھیم نہیں"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"enabled": "فعال",
|
||||||
|
"label": "پلگ انز",
|
||||||
|
"new": "نیا"
|
||||||
|
},
|
||||||
|
"view": {
|
||||||
|
"label": "دیکھیں",
|
||||||
|
"submenu": {
|
||||||
|
"force-reload": "زبردستی دوبارہ لوڈ کریں",
|
||||||
|
"reload": "دوبارہ لوڈ کریں",
|
||||||
|
"reset-zoom": "اصل سائز",
|
||||||
|
"toggle-fullscreen": "پوری سکرین ٹوگل کریں",
|
||||||
|
"zoom-in": "زوم ان کریں",
|
||||||
|
"zoom-out": "زوم آؤٹ کریں"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"tray": {
|
||||||
|
"next": "اگلا",
|
||||||
|
"play-pause": "چلائیں/روکیں",
|
||||||
|
"previous": "پچھلا",
|
||||||
|
"quit": "باہر نکلیں",
|
||||||
|
"restart": "ایپ دوبارہ شروع کریں"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -490,6 +490,9 @@
|
|||||||
"button": "Tải xuống"
|
"button": "Tải xuống"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"equalizer": {
|
||||||
|
"name": "Cân bằng âm thanh"
|
||||||
|
},
|
||||||
"exponential-volume": {
|
"exponential-volume": {
|
||||||
"description": "Làm cho thanh trượt âm lượng theo cấp số nhân để dễ dàng chọn âm lượng thấp hơn.",
|
"description": "Làm cho thanh trượt âm lượng theo cấp số nhân để dễ dàng chọn âm lượng thấp hơn.",
|
||||||
"name": "Âm lượng theo cấp số nhân"
|
"name": "Âm lượng theo cấp số nhân"
|
||||||
@ -670,6 +673,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "Nhập mã người dùng ListenBrainz"
|
"token": "Nhập mã người dùng ListenBrainz"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "Dùng tiêu đề thay thế",
|
||||||
"scrobble-other-media": "Scrobber nội dung khác"
|
"scrobble-other-media": "Scrobber nội dung khác"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
@ -720,8 +724,8 @@
|
|||||||
"synced-lyrics": {
|
"synced-lyrics": {
|
||||||
"description": "Cung cấp lời bài hát được đồng bộ hoá với các bài hát, sử dụng những nhà cung cấp như LRClib.",
|
"description": "Cung cấp lời bài hát được đồng bộ hoá với các bài hát, sử dụng những nhà cung cấp như LRClib.",
|
||||||
"errors": {
|
"errors": {
|
||||||
"fetch": "⚠️ - Đã xảy ra lỗi khi tìm lời bài hát, Vui lòng thử lại sau.",
|
"fetch": "⚠️\t\tĐã xảy ra lỗi khi tìm lời bài hát.\n\tVui lòng thử lại sau.",
|
||||||
"not-found": "⚠️ - Không tìm thấy lời cho bài hát này."
|
"not-found": "⚠️ Không tìm thấy lời cho bài hát này."
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"default-text-string": {
|
"default-text-string": {
|
||||||
@ -731,6 +735,9 @@
|
|||||||
"line-effect": {
|
"line-effect": {
|
||||||
"label": "Kiểu đường thẳng",
|
"label": "Kiểu đường thẳng",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "Màu mè"
|
||||||
|
},
|
||||||
"focus": {
|
"focus": {
|
||||||
"label": "Tập trung",
|
"label": "Tập trung",
|
||||||
"tooltip": "Chỉ làm cho dòng hiện tại có màu trắng"
|
"tooltip": "Chỉ làm cho dòng hiện tại có màu trắng"
|
||||||
@ -750,6 +757,9 @@
|
|||||||
"label": "Làm cho lời bài hát được đồng bộ hoàn hảo",
|
"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)"
|
"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)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"tooltip": "Nếu lời bài hát đang ở ngôn ngữ khác, thử hiển thị phiên bản bảng chữ cái La-tinh."
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "Hiển thị lời bài hát ngay cả khi không chính xác",
|
"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."
|
"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."
|
||||||
|
|||||||
@ -199,7 +199,11 @@
|
|||||||
"previous": "上一首",
|
"previous": "上一首",
|
||||||
"quit": "退出",
|
"quit": "退出",
|
||||||
"restart": "重启应用",
|
"restart": "重启应用",
|
||||||
"show": "显示窗口"
|
"show": "显示窗口",
|
||||||
|
"tooltip": {
|
||||||
|
"default": "YouTube Music",
|
||||||
|
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
@ -277,6 +281,7 @@
|
|||||||
},
|
},
|
||||||
"amuse": {
|
"amuse": {
|
||||||
"description": "为 6K Labs 的 Amuse 正在播放小部件添加 YouTube Music 支持",
|
"description": "为 6K Labs 的 Amuse 正在播放小部件添加 YouTube Music 支持",
|
||||||
|
"name": "Amuse",
|
||||||
"response": {
|
"response": {
|
||||||
"query": "Amuse API服务器已在运行。使用 /query 以获取歌曲信息。"
|
"query": "Amuse API服务器已在运行。使用 /query 以获取歌曲信息。"
|
||||||
}
|
}
|
||||||
@ -678,6 +683,7 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "输入 ListenBrainz 用户令牌"
|
"token": "输入 ListenBrainz 用户令牌"
|
||||||
},
|
},
|
||||||
|
"scrobble-alternative-title": "使用替代标题",
|
||||||
"scrobble-other-media": "记录其他媒体文件"
|
"scrobble-other-media": "记录其他媒体文件"
|
||||||
},
|
},
|
||||||
"name": "歌曲记录器",
|
"name": "歌曲记录器",
|
||||||
@ -728,7 +734,7 @@
|
|||||||
"synced-lyrics": {
|
"synced-lyrics": {
|
||||||
"description": "透过 LRClib 等服务提供滚动歌词显示。",
|
"description": "透过 LRClib 等服务提供滚动歌词显示。",
|
||||||
"errors": {
|
"errors": {
|
||||||
"fetch": "⚠️ - 获取歌词时发生错误。请稍后再试。",
|
"fetch": "⚠️ 获取歌词时发生错误。\n 请稍后再试。",
|
||||||
"not-found": "⚠️ 未找到此歌曲的歌词。"
|
"not-found": "⚠️ 未找到此歌曲的歌词。"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -739,6 +745,10 @@
|
|||||||
"line-effect": {
|
"line-effect": {
|
||||||
"label": "歌词行特效",
|
"label": "歌词行特效",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "Fancy",
|
||||||
|
"tooltip": "在当前行上使用大的、类似应用的效果"
|
||||||
|
},
|
||||||
"focus": {
|
"focus": {
|
||||||
"label": "高亮",
|
"label": "高亮",
|
||||||
"tooltip": "仅将当前歌词行显示为白色"
|
"tooltip": "仅将当前歌词行显示为白色"
|
||||||
@ -758,6 +768,10 @@
|
|||||||
"label": "让滚动歌词完全同步",
|
"label": "让滚动歌词完全同步",
|
||||||
"tooltip": "以毫秒精度估算下句歌词的显示时间(可能对性能有小幅影响)"
|
"tooltip": "以毫秒精度估算下句歌词的显示时间(可能对性能有小幅影响)"
|
||||||
},
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "将歌词罗马化",
|
||||||
|
"tooltip": "如果歌词以不同语言显示,试着展示拉丁字母版本。"
|
||||||
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "即使时值不精确依然显示歌词",
|
"label": "即使时值不精确依然显示歌词",
|
||||||
"tooltip": "若首次搜索未找到该歌曲的歌词,插件将尝试用不同的查询方式重新获取。\n重试查询的结果可能不精确。"
|
"tooltip": "若首次搜索未找到该歌曲的歌词,插件将尝试用不同的查询方式重新获取。\n重试查询的结果可能不精确。"
|
||||||
@ -790,6 +804,10 @@
|
|||||||
"description": "与 OBS 的 Tuna 插件集成",
|
"description": "与 OBS 的 Tuna 插件集成",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "防止播放器在播放歌曲时弹出",
|
||||||
|
"name": "非侵扰式播放器"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "增加视频/音频模式间的切换按钮。兼具移除整个视频页面的功能",
|
"description": "增加视频/音频模式间的切换按钮。兼具移除整个视频页面的功能",
|
||||||
"menu": {
|
"menu": {
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
"loaded": "i18n 已載入"
|
"loaded": "i18n 已載入"
|
||||||
},
|
},
|
||||||
"second-instance": {
|
"second-instance": {
|
||||||
"receive-command": "使用協定來接收指令:「{{command}}」"
|
"receive-command": "使用通訊協定來接收指令:「{{command}}」"
|
||||||
},
|
},
|
||||||
"theme": {
|
"theme": {
|
||||||
"css-file-not-found": "CSS 檔案「{{cssFile}}」不存在,已忽略"
|
"css-file-not-found": "CSS 檔案「{{cssFile}}」不存在,已忽略"
|
||||||
@ -53,13 +53,13 @@
|
|||||||
"later": "稍後",
|
"later": "稍後",
|
||||||
"restart-now": "立即重啟"
|
"restart-now": "立即重啟"
|
||||||
},
|
},
|
||||||
"detail": "\"{{pluginName}}\" 外掛需要重啟應用之後才會生效",
|
"detail": "\"{{pluginName}}\" 外掛需要重新啟動之後才會生效",
|
||||||
"message": "\"{{pluginName}}\" 需要重啟應用",
|
"message": "\"{{pluginName}}\" 需要重新啟動",
|
||||||
"title": "需要重啟應用"
|
"title": "需要重新啟動"
|
||||||
},
|
},
|
||||||
"unresponsive": {
|
"unresponsive": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"quit": "離開",
|
"quit": "結束",
|
||||||
"relaunch": "重新啟動",
|
"relaunch": "重新啟動",
|
||||||
"wait": "等一下"
|
"wait": "等一下"
|
||||||
},
|
},
|
||||||
@ -83,11 +83,11 @@
|
|||||||
"navigation": {
|
"navigation": {
|
||||||
"label": "導覽列",
|
"label": "導覽列",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"copy-current-url": "複製當前頁面的網址",
|
"copy-current-url": "複製目前頁面的網址",
|
||||||
"go-back": "回到上一頁",
|
"go-back": "回到上一頁",
|
||||||
"go-forward": "回到下一頁",
|
"go-forward": "回到下一頁",
|
||||||
"quit": "退出",
|
"quit": "結束",
|
||||||
"restart": "重啟應用"
|
"restart": "重新啟動"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
@ -100,7 +100,7 @@
|
|||||||
"disable-hardware-acceleration": "關閉硬體加速",
|
"disable-hardware-acceleration": "關閉硬體加速",
|
||||||
"edit-config-json": "編輯 config.json",
|
"edit-config-json": "編輯 config.json",
|
||||||
"override-user-agent": "覆寫使用者代理",
|
"override-user-agent": "覆寫使用者代理",
|
||||||
"restart-on-config-changes": "設定變更時自動重啟應用",
|
"restart-on-config-changes": "設定變更時自動重新啟動",
|
||||||
"set-proxy": {
|
"set-proxy": {
|
||||||
"label": "設定代理伺服器",
|
"label": "設定代理伺服器",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
@ -123,7 +123,7 @@
|
|||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"message": "語言會在重啟應用後變更",
|
"message": "語言會在重新啟動後變更",
|
||||||
"title": "語言已變更"
|
"title": "語言已變更"
|
||||||
},
|
},
|
||||||
"label": "語言",
|
"label": "語言",
|
||||||
@ -142,9 +142,9 @@
|
|||||||
"label": "系統匣",
|
"label": "系統匣",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"disabled": "已停用",
|
"disabled": "已停用",
|
||||||
"enabled-and-hide-app": "啟用並最小化應用",
|
"enabled-and-hide-app": "啟用並最小化應用程式",
|
||||||
"enabled-and-show-app": "啟用並顯示應用",
|
"enabled-and-show-app": "啟用並顯示應用程式",
|
||||||
"play-pause-on-click": "點擊時播放/暫停"
|
"play-pause-on-click": "點選時播放/暫停"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"visual-tweaks": {
|
"visual-tweaks": {
|
||||||
@ -177,17 +177,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"enabled": "啟用",
|
"enabled": "已啟用",
|
||||||
"label": "外掛功能",
|
"label": "外掛功能",
|
||||||
"new": "新的"
|
"new": "新的"
|
||||||
},
|
},
|
||||||
"view": {
|
"view": {
|
||||||
"label": "視窗",
|
"label": "檢視",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"force-reload": "強制重新整理",
|
"force-reload": "強制重新整理",
|
||||||
"reload": "重新整理",
|
"reload": "重新整理",
|
||||||
"reset-zoom": "重設大小",
|
"reset-zoom": "重設大小",
|
||||||
"toggle-fullscreen": "全螢幕",
|
"toggle-fullscreen": "切換全螢幕",
|
||||||
"zoom-in": "放大",
|
"zoom-in": "放大",
|
||||||
"zoom-out": "縮小"
|
"zoom-out": "縮小"
|
||||||
}
|
}
|
||||||
@ -198,10 +198,10 @@
|
|||||||
"play-pause": "播放/暫停",
|
"play-pause": "播放/暫停",
|
||||||
"previous": "上一首",
|
"previous": "上一首",
|
||||||
"quit": "關閉",
|
"quit": "關閉",
|
||||||
"restart": "重啟程式",
|
"restart": "重新啟動應用程式",
|
||||||
"show": "顯示視窗",
|
"show": "顯示視窗",
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"default": "Youtube Music",
|
"default": "YouTube Music",
|
||||||
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
|
"with-song-info": "YouTube Music: {{artist}} - {{title}}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@
|
|||||||
"name": "隨歌曲色調變更主題"
|
"name": "隨歌曲色調變更主題"
|
||||||
},
|
},
|
||||||
"ambient-mode": {
|
"ambient-mode": {
|
||||||
"description": "影片周圍背景根據影片內容改變顏色, 讓觀眾在觀賞影片時更有臨場感",
|
"description": "影片周圍背景根據影片內容改變顏色,讓觀眾在觀賞影片時更有臨場感",
|
||||||
"menu": {
|
"menu": {
|
||||||
"blur-amount": {
|
"blur-amount": {
|
||||||
"label": "模糊等級",
|
"label": "模糊等級",
|
||||||
@ -280,10 +280,10 @@
|
|||||||
"name": "微光效果"
|
"name": "微光效果"
|
||||||
},
|
},
|
||||||
"amuse": {
|
"amuse": {
|
||||||
"description": "加入支援 6K Labs 的 Amuse OBS 外掛以取得 Youtube Music 現正播放資訊",
|
"description": "加入支援 6K Labs 的 Amuse OBS 外掛以取得 YouTube Music 現正播放資訊",
|
||||||
"name": "Amuse",
|
"name": "Amuse",
|
||||||
"response": {
|
"response": {
|
||||||
"query": "Amuse API 伺服器正在運行中,使用 /query 以取得歌曲資訊。"
|
"query": "Amuse API 伺服器正在運作中,使用 /query 以取得歌曲資訊。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"api-server": {
|
"api-server": {
|
||||||
@ -294,7 +294,7 @@
|
|||||||
"allow": "允許",
|
"allow": "允許",
|
||||||
"deny": "拒絕"
|
"deny": "拒絕"
|
||||||
},
|
},
|
||||||
"message": "允許 {{ID}} ({{origin}}) 訪問 API 嗎?",
|
"message": "允許 {{ID}} ({{origin}}) 存取 API 嗎?",
|
||||||
"title": "API 驗證請求"
|
"title": "API 驗證請求"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -314,7 +314,7 @@
|
|||||||
"label": "主機名稱"
|
"label": "主機名稱"
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"label": "接口"
|
"label": "連接埠"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "API 伺服器 [Beta]",
|
"name": "API 伺服器 [Beta]",
|
||||||
@ -324,13 +324,13 @@
|
|||||||
"title": "主機名稱"
|
"title": "主機名稱"
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"label": "輸入 API 伺服器接口:",
|
"label": "輸入 API 伺服器連接埠:",
|
||||||
"title": "接口"
|
"title": "連接埠"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"audio-compressor": {
|
"audio-compressor": {
|
||||||
"description": "使用音效壓縮 (大聲部份的音量降低, 柔和部份的音量提高)",
|
"description": "使用音效壓縮 (大聲部份的音量降低,柔和部份的音量提高)",
|
||||||
"name": "音效壓縮器"
|
"name": "音效壓縮器"
|
||||||
},
|
},
|
||||||
"blur-nav-bar": {
|
"blur-nav-bar": {
|
||||||
@ -338,21 +338,21 @@
|
|||||||
"name": "模糊導覽列"
|
"name": "模糊導覽列"
|
||||||
},
|
},
|
||||||
"bypass-age-restrictions": {
|
"bypass-age-restrictions": {
|
||||||
"description": "繞過Youtube年齡驗證",
|
"description": "繞過 YouTube 年齡驗證",
|
||||||
"name": "繞過年齡驗證"
|
"name": "繞過年齡驗證"
|
||||||
},
|
},
|
||||||
"captions-selector": {
|
"captions-selector": {
|
||||||
"description": "音軌標題選擇",
|
"description": "YouTube Music 音軌字幕選擇器",
|
||||||
"menu": {
|
"menu": {
|
||||||
"autoload": "自動選擇最後使用的標題",
|
"autoload": "自動選擇上次使用的字幕",
|
||||||
"disable-captions": "預設無標題"
|
"disable-captions": "預設無標題"
|
||||||
},
|
},
|
||||||
"name": "標題選擇器",
|
"name": "標題選擇器",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
"selector": {
|
"selector": {
|
||||||
"label": "目前標題語言:{{language}}",
|
"label": "目前字幕語言:{{language}}",
|
||||||
"none": "無",
|
"none": "無",
|
||||||
"title": "選擇標題語言"
|
"title": "選擇字幕語言"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
@ -394,19 +394,19 @@
|
|||||||
},
|
},
|
||||||
"discord": {
|
"discord": {
|
||||||
"backend": {
|
"backend": {
|
||||||
"already-connected": "已嘗試可用連接",
|
"already-connected": "已嘗試可用連線",
|
||||||
"connected": "已連接至 Discord",
|
"connected": "已連線至 Discord",
|
||||||
"disconnected": "與 Discord 斷開連接"
|
"disconnected": "已與 Discord 中斷連線"
|
||||||
},
|
},
|
||||||
"description": "使用 Discord 狀態與你的好友分享你正在收聽的音樂",
|
"description": "使用 Discord 狀態與你的好友分享你正在收聽的音樂",
|
||||||
"menu": {
|
"menu": {
|
||||||
"auto-reconnect": "自動重新連接",
|
"auto-reconnect": "自動重新連線",
|
||||||
"clear-activity": "清除狀態",
|
"clear-activity": "清除狀態",
|
||||||
"clear-activity-after-timeout": "在音樂暫停後清除狀態",
|
"clear-activity-after-timeout": "在音樂暫停後清除狀態",
|
||||||
"connected": "已連接",
|
"connected": "已連線",
|
||||||
"disconnected": "已斷開連接",
|
"disconnected": "已斷開連線",
|
||||||
"hide-duration-left": "隱藏音樂剩餘時間狀態",
|
"hide-duration-left": "隱藏音樂剩餘時間狀態",
|
||||||
"hide-github-button": "隱藏 Github 頁面按鈕",
|
"hide-github-button": "隱藏 GitHub 頁面按鈕",
|
||||||
"play-on-youtube-music": "顯示 Play on YouTube Music 按鈕",
|
"play-on-youtube-music": "顯示 Play on YouTube Music 按鈕",
|
||||||
"set-inactivity-timeout": "設定閒置狀態時長"
|
"set-inactivity-timeout": "設定閒置狀態時長"
|
||||||
},
|
},
|
||||||
@ -425,8 +425,8 @@
|
|||||||
"buttons": {
|
"buttons": {
|
||||||
"ok": "完成"
|
"ok": "完成"
|
||||||
},
|
},
|
||||||
"message": "啊!抱歉,下載失敗了…",
|
"message": "啊!抱歉,下載失敗了…",
|
||||||
"title": "下載出現錯誤!"
|
"title": "下載出現錯誤!"
|
||||||
},
|
},
|
||||||
"start-download-playlist": {
|
"start-download-playlist": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
@ -448,15 +448,15 @@
|
|||||||
"downloading-playlist": "正在下載播放清單 \"{{playlistTitle}}\" - 共 {{playlistSize}} 首歌 ({{playlistId}})",
|
"downloading-playlist": "正在下載播放清單 \"{{playlistTitle}}\" - 共 {{playlistSize}} 首歌 ({{playlistId}})",
|
||||||
"error-while-downloading": "無法下載 \"{{author}} - {{title}}\": {{error}}",
|
"error-while-downloading": "無法下載 \"{{author}} - {{title}}\": {{error}}",
|
||||||
"folder-already-exists": "資料夾 {{playlistFolder}} 已經存在",
|
"folder-already-exists": "資料夾 {{playlistFolder}} 已經存在",
|
||||||
"getting-playlist-info": "正在獲取播放清單資訊…",
|
"getting-playlist-info": "正在取得播放清單資訊…",
|
||||||
"loading": "載入中…",
|
"loading": "載入中…",
|
||||||
"playlist-has-only-one-song": "播放清單內只有一首歌曲, 將直接下載",
|
"playlist-has-only-one-song": "播放清單內只有一首歌曲,將直接下載",
|
||||||
"playlist-id-not-found": "沒有找到播放清單 ID",
|
"playlist-id-not-found": "沒有找到播放清單 ID",
|
||||||
"playlist-is-empty": "播放清單是空的",
|
"playlist-is-empty": "播放清單是空的",
|
||||||
"playlist-is-mix-or-private": "獲取播放清單資訊時發生錯誤:請確認非私人播放清單或是\"為你推薦的合輯\"\n\n{{error}}",
|
"playlist-is-mix-or-private": "取得播放清單資訊時發生錯誤:請確認非私人播放清單或是\"為你推薦的合輯\"\n\n{{error}}",
|
||||||
"preparing-file": "正在準備檔案…",
|
"preparing-file": "正在準備檔案…",
|
||||||
"saving": "儲存中…",
|
"saving": "儲存中…",
|
||||||
"trying-to-get-playlist-id": "正在嘗試獲取播放清單 ID:{{playlistId}}",
|
"trying-to-get-playlist-id": "正在嘗試取得播放清單 ID:{{playlistId}}",
|
||||||
"video-id-not-found": "未能找到該影片",
|
"video-id-not-found": "未能找到該影片",
|
||||||
"writing-id3": "正在寫入 ID3 標籤…"
|
"writing-id3": "正在寫入 ID3 標籤…"
|
||||||
}
|
}
|
||||||
@ -510,7 +510,7 @@
|
|||||||
"in-app-menu": {
|
"in-app-menu": {
|
||||||
"description": "使選單列變更為黑色或隨主題變色",
|
"description": "使選單列變更為黑色或隨主題變色",
|
||||||
"menu": {
|
"menu": {
|
||||||
"hide-dom-window-controls": "隱藏DOM視窗控制"
|
"hide-dom-window-controls": "隱藏 DOM 視窗控制"
|
||||||
},
|
},
|
||||||
"name": "程式內選單列"
|
"name": "程式內選單列"
|
||||||
},
|
},
|
||||||
@ -525,13 +525,13 @@
|
|||||||
},
|
},
|
||||||
"name": "第三方字幕",
|
"name": "第三方字幕",
|
||||||
"renderer": {
|
"renderer": {
|
||||||
"fetched-lyrics": "為 Genius 獲取字幕"
|
"fetched-lyrics": "為 Genius 取得字幕"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"music-together": {
|
"music-together": {
|
||||||
"description": "與他人共享播放清單。當發起人播放歌曲時,其他成員也會同步收聽",
|
"description": "與他人共享播放清單。當主持人播放歌曲時,其他成員也會同步收聽",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"enter-host": "輸入發起人 ID"
|
"enter-host": "輸入主持人 ID"
|
||||||
},
|
},
|
||||||
"internal": {
|
"internal": {
|
||||||
"save": "儲存",
|
"save": "儲存",
|
||||||
@ -539,11 +539,11 @@
|
|||||||
"unknown-user": "未知使用者"
|
"unknown-user": "未知使用者"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"click-to-copy-id": "複製發起人 ID",
|
"click-to-copy-id": "複製主持人 ID",
|
||||||
"close": "同步關閉音樂",
|
"close": "同步關閉音樂",
|
||||||
"connected-users": "已連接的使用者",
|
"connected-users": "已連線的使用者",
|
||||||
"disconnect": "斷開連接共享音樂",
|
"disconnect": "斷開連線共享音樂",
|
||||||
"empty-user": "無已連接的使用者",
|
"empty-user": "無已連線的使用者",
|
||||||
"host": "發起共享音樂",
|
"host": "發起共享音樂",
|
||||||
"join": "加入共享音樂",
|
"join": "加入共享音樂",
|
||||||
"permission": {
|
"permission": {
|
||||||
@ -551,23 +551,23 @@
|
|||||||
"host-only": "不允許加入的使用者控制播放清單及播放控制",
|
"host-only": "不允許加入的使用者控制播放清單及播放控制",
|
||||||
"playlist": "只允許加入的使用者控制播放清單"
|
"playlist": "只允許加入的使用者控制播放清單"
|
||||||
},
|
},
|
||||||
"set-permission": "切換共享音樂播放權限",
|
"set-permission": "切換共享音樂播放許可權",
|
||||||
"status": {
|
"status": {
|
||||||
"disconnected": "已斷開連接",
|
"disconnected": "已斷開連線",
|
||||||
"guest": "以使用者身份加入",
|
"guest": "以訪客身份加入",
|
||||||
"host": "以發起人身份加入"
|
"host": "以主持人身份加入"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "共享音樂 [Beta]",
|
"name": "共享音樂 [Beta]",
|
||||||
"toast": {
|
"toast": {
|
||||||
"add-song-failed": "歌曲加入失敗",
|
"add-song-failed": "歌曲加入失敗",
|
||||||
"closed": "關閉共享音樂",
|
"closed": "關閉共享音樂",
|
||||||
"disconnected": "共享音樂已斷開連接",
|
"disconnected": "共享音樂已斷開連線",
|
||||||
"host-failed": "發起共享音樂失敗",
|
"host-failed": "發起共享音樂失敗",
|
||||||
"id-copied": "已複製發起人 ID",
|
"id-copied": "已複製主持人 ID",
|
||||||
"id-copy-failed": "複製發起人 ID 失敗",
|
"id-copy-failed": "複製主持人 ID 失敗",
|
||||||
"join-failed": "加入共享音樂失敗",
|
"join-failed": "加入共享音樂失敗",
|
||||||
"joined": "加入共享音樂",
|
"joined": "已加入共享音樂",
|
||||||
"permission-changed": "共享音樂播放權限已切換至 \"{{permission}}\"",
|
"permission-changed": "共享音樂播放權限已切換至 \"{{permission}}\"",
|
||||||
"remove-song-failed": "歌曲移除失敗",
|
"remove-song-failed": "歌曲移除失敗",
|
||||||
"user-connected": "{{name}} 已加入共享音樂",
|
"user-connected": "{{name}} 已加入共享音樂",
|
||||||
@ -583,20 +583,20 @@
|
|||||||
"name": "停用 Google 登入"
|
"name": "停用 Google 登入"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"description": "在歌曲播放時發送一個系統通知 (可互動通知僅限Windows)",
|
"description": "在歌曲播放時傳送一個系統通知 (可互動通知僅限 Windows)",
|
||||||
"menu": {
|
"menu": {
|
||||||
"interactive": "可互動通知",
|
"interactive": "可互動通知",
|
||||||
"interactive-settings": {
|
"interactive-settings": {
|
||||||
"label": "通知互動設定",
|
"label": "通知互動設定",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"hide-button-text": "隱藏按鈕文字",
|
"hide-button-text": "隱藏按鈕文字",
|
||||||
"refresh-on-play-pause": "在播放/暫停時刷新",
|
"refresh-on-play-pause": "在播放/暫停時重新整理",
|
||||||
"tray-controls": "點擊系統閘圖示時打開/關閉"
|
"tray-controls": "點選系統閘圖示時開啟/關閉"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"priority": "通知優先權",
|
"priority": "通知優先權",
|
||||||
"toast-style": "通知樣式",
|
"toast-style": "通知樣式",
|
||||||
"unpause-notification": "在取消暫停時發送通知"
|
"unpause-notification": "在取消暫停時傳送通知"
|
||||||
},
|
},
|
||||||
"name": "歌曲播放通知"
|
"name": "歌曲播放通知"
|
||||||
},
|
},
|
||||||
@ -624,7 +624,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"playback-speed": {
|
"playback-speed": {
|
||||||
"description": "傷心的人別聽慢歌, 新增一個滑桿控制歌曲速度",
|
"description": "傷心的人別聽慢歌,新增一個滑桿控制歌曲速度",
|
||||||
"name": "控制歌曲速度",
|
"name": "控制歌曲速度",
|
||||||
"templates": {
|
"templates": {
|
||||||
"button": "速度"
|
"button": "速度"
|
||||||
@ -671,7 +671,7 @@
|
|||||||
"dialog": {
|
"dialog": {
|
||||||
"lastfm": {
|
"lastfm": {
|
||||||
"auth-failed": {
|
"auth-failed": {
|
||||||
"message": "Last.fm認證失敗\n將隱藏彈窗直到重啟。",
|
"message": "Last.fm 認證失敗\n將隱藏彈窗直到重啟。",
|
||||||
"title": "認證失敗"
|
"title": "認證失敗"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -683,8 +683,8 @@
|
|||||||
"listenbrainz": {
|
"listenbrainz": {
|
||||||
"token": "輸入 ListenBrainz 使用者憑證"
|
"token": "輸入 ListenBrainz 使用者憑證"
|
||||||
},
|
},
|
||||||
"scrobble-alternative-title": "使用另類歌曲標題",
|
"scrobble-alternative-title": "使用替代歌曲標題",
|
||||||
"scrobble-other-media": "紀錄其他媒體文件"
|
"scrobble-other-media": "紀錄其他媒體檔案"
|
||||||
},
|
},
|
||||||
"name": "Scrobbler",
|
"name": "Scrobbler",
|
||||||
"prompt": {
|
"prompt": {
|
||||||
@ -701,7 +701,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
"description": "使用全域快捷鍵控制音樂 (播放/暫停/下一首/上一首) + 透過覆寫媒體快捷鍵停用媒體OSD + 允許Ctrl/CMD + F來搜尋 + 支援Linux MPRIS媒體快捷鍵 + 更多自訂快捷鍵給進階使用者",
|
"description": "使用全域快捷鍵控制音樂 (播放/暫停/下一首/上一首) + 透過覆寫媒體快捷鍵停用媒體 OSD + 允許 Ctrl/CMD + F 來搜尋 + 支援 Linux MPRIS 媒體快捷鍵 + 更多自訂快捷鍵給進階使用者",
|
||||||
"menu": {
|
"menu": {
|
||||||
"override-media-keys": "覆寫媒體快捷鍵",
|
"override-media-keys": "覆寫媒體快捷鍵",
|
||||||
"set-keybinds": "設定全域歌曲控制"
|
"set-keybinds": "設定全域歌曲控制"
|
||||||
@ -729,7 +729,7 @@
|
|||||||
},
|
},
|
||||||
"sponsorblock": {
|
"sponsorblock": {
|
||||||
"description": "自動跳過贊助片段",
|
"description": "自動跳過贊助片段",
|
||||||
"name": "贊助阻擋"
|
"name": "SponsorBlock"
|
||||||
},
|
},
|
||||||
"synced-lyrics": {
|
"synced-lyrics": {
|
||||||
"description": "使用 LRClib 等管道提供歌詞同步顯示。",
|
"description": "使用 LRClib 等管道提供歌詞同步顯示。",
|
||||||
@ -747,26 +747,30 @@
|
|||||||
"submenu": {
|
"submenu": {
|
||||||
"fancy": {
|
"fancy": {
|
||||||
"label": "絢麗",
|
"label": "絢麗",
|
||||||
"tooltip": "使用較為接近原生樣式並且放大當前該行歌詞"
|
"tooltip": "使用較為接近原生樣式並且放大目前該行歌詞"
|
||||||
},
|
},
|
||||||
"focus": {
|
"focus": {
|
||||||
"label": "高亮",
|
"label": "聚焦",
|
||||||
"tooltip": "高亮當前的歌詞"
|
"tooltip": "聚焦目前的歌詞"
|
||||||
},
|
},
|
||||||
"offset": {
|
"offset": {
|
||||||
"label": "凸行",
|
"label": "凸行",
|
||||||
"tooltip": "凸行當前的歌詞"
|
"tooltip": "凸行目前的歌詞"
|
||||||
},
|
},
|
||||||
"scale": {
|
"scale": {
|
||||||
"label": "放大",
|
"label": "放大",
|
||||||
"tooltip": "放大當前的歌詞"
|
"tooltip": "放大目前的歌詞"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tooltip": "選擇要使用的歌詞顯示效果"
|
"tooltip": "選擇要使用的歌詞顯示效果"
|
||||||
},
|
},
|
||||||
"precise-timing": {
|
"precise-timing": {
|
||||||
"label": "使歌詞完美同步",
|
"label": "使歌詞完美同步",
|
||||||
"tooltip": "更精確的計算下一行歌詞的顯示(將會降低些許效能)"
|
"tooltip": "更精確的計算下一行歌詞的顯示 (將會降低些許效能)"
|
||||||
|
},
|
||||||
|
"romanization": {
|
||||||
|
"label": "羅馬拼音化歌詞",
|
||||||
|
"tooltip": "如果歌詞使用不同語言,嘗試使用拉丁文顯示。"
|
||||||
},
|
},
|
||||||
"show-lyrics-even-if-inexact": {
|
"show-lyrics-even-if-inexact": {
|
||||||
"label": "即使不精確依然強制顯示歌詞",
|
"label": "即使不精確依然強制顯示歌詞",
|
||||||
@ -793,13 +797,17 @@
|
|||||||
"name": "工作列媒體控制"
|
"name": "工作列媒體控制"
|
||||||
},
|
},
|
||||||
"touchbar": {
|
"touchbar": {
|
||||||
"description": "為macOS使用者新增觸控列支援",
|
"description": "為 macOS 使用者新增觸控列支援",
|
||||||
"name": "觸控列 (Touchbar) 支援"
|
"name": "觸控列 (Touchbar) 支援"
|
||||||
},
|
},
|
||||||
"tuna-obs": {
|
"tuna-obs": {
|
||||||
"description": "與 OBS 的 Tuna 外掛連接",
|
"description": "與 OBS 的 Tuna 外掛連線",
|
||||||
"name": "Tuna OBS"
|
"name": "Tuna OBS"
|
||||||
},
|
},
|
||||||
|
"unobtrusive-player": {
|
||||||
|
"description": "防止播放器介面在點選歌曲後彈出",
|
||||||
|
"name": "低干擾播放器介面"
|
||||||
|
},
|
||||||
"video-toggle": {
|
"video-toggle": {
|
||||||
"description": "新增一個按鈕可以控制影片/歌曲切換和完全移除整個影片頁面的功能",
|
"description": "新增一個按鈕可以控制影片/歌曲切換和完全移除整個影片頁面的功能",
|
||||||
"menu": {
|
"menu": {
|
||||||
@ -813,7 +821,7 @@
|
|||||||
},
|
},
|
||||||
"force-hide": "強制移除整個影片頁面",
|
"force-hide": "強制移除整個影片頁面",
|
||||||
"mode": {
|
"mode": {
|
||||||
"label": "樣式",
|
"label": "模式",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
"custom": "自訂樣式",
|
"custom": "自訂樣式",
|
||||||
"disabled": "停用",
|
"disabled": "停用",
|
||||||
@ -827,11 +835,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"visualizer": {
|
"visualizer": {
|
||||||
"description": "新增一個可視化音樂效果",
|
"description": "新增一個視覺化音樂效果",
|
||||||
"menu": {
|
"menu": {
|
||||||
"visualizer-type": "樣式"
|
"visualizer-type": "視覺化效果類型"
|
||||||
},
|
},
|
||||||
"name": "可視化音樂效果"
|
"name": "視覺化效果"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export interface APIServerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const defaultAPIServerConfig: APIServerConfig = {
|
export const defaultAPIServerConfig: APIServerConfig = {
|
||||||
enabled: true,
|
enabled: false,
|
||||||
hostname: '0.0.0.0',
|
hostname: '0.0.0.0',
|
||||||
port: 26538,
|
port: 26538,
|
||||||
authStrategy: AuthStrategy.AUTH_AT_FIRST,
|
authStrategy: AuthStrategy.AUTH_AT_FIRST,
|
||||||
|
|||||||
@ -56,6 +56,14 @@ let win: BrowserWindow;
|
|||||||
let playingUrl: string;
|
let playingUrl: string;
|
||||||
|
|
||||||
const isYouTubeMusicPremium = async () => {
|
const isYouTubeMusicPremium = async () => {
|
||||||
|
// If signed out, it is understood as non-premium
|
||||||
|
const isSignedIn = (await win.webContents.executeJavaScript(
|
||||||
|
'!!yt.config_.LOGGED_IN',
|
||||||
|
)) as boolean;
|
||||||
|
|
||||||
|
if (!isSignedIn) return false;
|
||||||
|
|
||||||
|
// If signed in, check if the upgrade button is present
|
||||||
const upgradeBtnIconPathData = (await win.webContents.executeJavaScript(
|
const upgradeBtnIconPathData = (await win.webContents.executeJavaScript(
|
||||||
'document.querySelector(\'iron-iconset-svg[name="yt-sys-icons"] #youtube_music_monochrome\')?.firstChild?.getAttribute("d")?.substring(0, 15)',
|
'document.querySelector(\'iron-iconset-svg[name="yt-sys-icons"] #youtube_music_monochrome\')?.firstChild?.getAttribute("d")?.substring(0, 15)',
|
||||||
)) as string | null;
|
)) as string | null;
|
||||||
@ -63,10 +71,10 @@ const isYouTubeMusicPremium = async () => {
|
|||||||
// Fallback to non-premium if the icon is not found
|
// Fallback to non-premium if the icon is not found
|
||||||
if (!upgradeBtnIconPathData) return false;
|
if (!upgradeBtnIconPathData) return false;
|
||||||
|
|
||||||
const selector = `ytmusic-guide-entry-renderer:has(> tp-yt-paper-item > yt-icon path[d^="${upgradeBtnIconPathData}"])`;
|
const upgradeButton = `ytmusic-guide-entry-renderer:has(> tp-yt-paper-item > yt-icon path[d^="${upgradeBtnIconPathData}"])`;
|
||||||
|
|
||||||
return (await win.webContents.executeJavaScript(
|
return (await win.webContents.executeJavaScript(
|
||||||
`!document.querySelector('${selector}')`,
|
`!document.querySelector('${upgradeButton}')`,
|
||||||
)) as boolean;
|
)) as boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { DataConnection, Peer } from 'peerjs';
|
import { DataConnection, Peer, PeerErrorType } from 'peerjs';
|
||||||
|
import delay from 'delay';
|
||||||
|
|
||||||
import type { Permission, Profile, VideoData } from './types';
|
import type { Permission, Profile, VideoData } from './types';
|
||||||
|
|
||||||
@ -54,16 +55,16 @@ export class Connection {
|
|||||||
this._mode = 'host';
|
this._mode = 'host';
|
||||||
this.waitOpen.resolve(id);
|
this.waitOpen.resolve(id);
|
||||||
});
|
});
|
||||||
this.peer.on('connection', (conn) => {
|
this.peer.on('connection', async (conn) => {
|
||||||
this._mode = 'host';
|
this._mode = 'host';
|
||||||
this.registerConnection(conn);
|
await this.registerConnection(conn);
|
||||||
});
|
});
|
||||||
this.peer.on('error', (err) => {
|
this.peer.on('error', (err) => {
|
||||||
this._mode = 'disconnected';
|
this._mode = 'disconnected';
|
||||||
|
|
||||||
this.waitOpen.reject(err);
|
this.waitOpen.reject(err);
|
||||||
this.connectionListeners.forEach((listener) => listener());
|
this.connectionListeners.forEach((listener) => listener());
|
||||||
console.log(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +75,9 @@ export class Connection {
|
|||||||
|
|
||||||
async connect(id: string) {
|
async connect(id: string) {
|
||||||
this._mode = 'guest';
|
this._mode = 'guest';
|
||||||
const conn = this.peer.connect(id);
|
const conn = this.peer.connect(id, {
|
||||||
|
reliable: true,
|
||||||
|
});
|
||||||
await this.registerConnection(conn);
|
await this.registerConnection(conn);
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
@ -120,7 +123,17 @@ export class Connection {
|
|||||||
/* privates */
|
/* privates */
|
||||||
private async registerConnection(conn: DataConnection) {
|
private async registerConnection(conn: DataConnection) {
|
||||||
return new Promise<DataConnection>((resolve, reject) => {
|
return new Promise<DataConnection>((resolve, reject) => {
|
||||||
this.peer.once('error', (err) => {
|
this.peer.once('error', async (err) => {
|
||||||
|
if (err.type === PeerErrorType.Network) {
|
||||||
|
// retrying after 10 seconds
|
||||||
|
await delay(10000);
|
||||||
|
try {
|
||||||
|
this.peer.reconnect();
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
//ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
this._mode = 'disconnected';
|
this._mode = 'disconnected';
|
||||||
|
|
||||||
reject(err);
|
reject(err);
|
||||||
|
|||||||
19
src/plugins/performance-improvement/index.ts
Normal file
19
src/plugins/performance-improvement/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { createPlugin } from '@/utils';
|
||||||
|
import { t } from '@/i18n';
|
||||||
|
|
||||||
|
import { injectRm3 } from './scripts/rm3';
|
||||||
|
import { injectCpuTamer } from './scripts/cpu-tamer';
|
||||||
|
|
||||||
|
export default createPlugin({
|
||||||
|
name: () => t('plugins.performance-improvement.name'),
|
||||||
|
description: () => t('plugins.performance-improvement.description'),
|
||||||
|
restartNeeded: true,
|
||||||
|
addedVersion: '3.9.X',
|
||||||
|
config: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
renderer() {
|
||||||
|
injectRm3();
|
||||||
|
injectCpuTamer();
|
||||||
|
},
|
||||||
|
});
|
||||||
3
src/plugins/performance-improvement/scripts/cpu-tamer/cpu-tamer-by-animationframe.d.ts
vendored
Normal file
3
src/plugins/performance-improvement/scripts/cpu-tamer/cpu-tamer-by-animationframe.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export declare const injectCpuTamerByAnimationFrame: (
|
||||||
|
__CONTEXT__: unknown,
|
||||||
|
) => void;
|
||||||
@ -0,0 +1,286 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright 2021-2025 CY Fung
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export const injectCpuTamerByAnimationFrame = ((__CONTEXT__) => {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const win = this instanceof Window ? this : window;
|
||||||
|
|
||||||
|
// Create a unique key for the script and check if it is already running
|
||||||
|
const hkey_script = 'nzsxclvflluv';
|
||||||
|
if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
|
||||||
|
win[hkey_script] = true;
|
||||||
|
|
||||||
|
/** @type {globalThis.PromiseConstructor} */
|
||||||
|
const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
|
||||||
|
const PromiseExternal = ((resolve_, reject_) => {
|
||||||
|
const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
|
||||||
|
return class PromiseExternal extends Promise {
|
||||||
|
constructor(cb = h) {
|
||||||
|
super(cb);
|
||||||
|
if (cb === h) {
|
||||||
|
/** @type {(value: any) => void} */
|
||||||
|
this.resolve = resolve_;
|
||||||
|
/** @type {(reason?: any) => void} */
|
||||||
|
this.reject = reject_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
const isGPUAccelerationAvailable = (() => {
|
||||||
|
// https://gist.github.com/cvan/042b2448fcecefafbb6a91469484cdf8
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!isGPUAccelerationAvailable) {
|
||||||
|
throw new Error('Your browser does not support GPU Acceleration. YouTube CPU Tamer by AnimationFrame is skipped.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeupdateDT = (() => {
|
||||||
|
|
||||||
|
window.__j6YiAc__ = 1;
|
||||||
|
|
||||||
|
document.addEventListener('timeupdate', () => {
|
||||||
|
window.__j6YiAc__ = Date.now();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
let kz = -1;
|
||||||
|
try {
|
||||||
|
kz = top.__j6YiAc__;
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return kz >= 1 ? () => top.__j6YiAc__ : () => window.__j6YiAc__;
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
const cleanContext = async (win) => {
|
||||||
|
const waitFn = requestAnimationFrame; // shall have been binded to window
|
||||||
|
try {
|
||||||
|
let mx = 16; // MAX TRIAL
|
||||||
|
const frameId = 'vanillajs-iframe-v1'
|
||||||
|
let frame = document.getElementById(frameId);
|
||||||
|
let removeIframeFn = null;
|
||||||
|
if (!frame) {
|
||||||
|
frame = document.createElement('iframe');
|
||||||
|
frame.id = frameId;
|
||||||
|
const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash
|
||||||
|
frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
|
||||||
|
let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
|
||||||
|
n.appendChild(frame);
|
||||||
|
while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
|
||||||
|
const root = document.documentElement;
|
||||||
|
root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
|
||||||
|
if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL));
|
||||||
|
|
||||||
|
removeIframeFn = (setTimeout) => {
|
||||||
|
const removeIframeOnDocumentReady = (e) => {
|
||||||
|
e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
|
||||||
|
e = n;
|
||||||
|
n = win = removeIframeFn = 0;
|
||||||
|
setTimeout ? setTimeout(() => e.remove(), 200) : e.remove();
|
||||||
|
}
|
||||||
|
if (!setTimeout || document.readyState !== 'loading') {
|
||||||
|
removeIframeOnDocumentReady();
|
||||||
|
} else {
|
||||||
|
win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
|
||||||
|
const fc = frame.contentWindow;
|
||||||
|
if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
|
||||||
|
try {
|
||||||
|
const { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout } = fc;
|
||||||
|
const res = { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout };
|
||||||
|
for (let k in res) res[k] = res[k].bind(win); // necessary
|
||||||
|
if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
if (removeIframeFn) removeIframeFn();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cleanContext(win).then(__CONTEXT__ => {
|
||||||
|
|
||||||
|
if (!__CONTEXT__) return null;
|
||||||
|
|
||||||
|
const { requestAnimationFrame, setTimeout, setInterval, clearTimeout, clearInterval } = __CONTEXT__;
|
||||||
|
|
||||||
|
/** @type {Function|null} */
|
||||||
|
let afInterupter = null;
|
||||||
|
|
||||||
|
const getRAFHelper = () => {
|
||||||
|
const asc = document.createElement('a-f');
|
||||||
|
if (!('onanimationiteration' in asc)) {
|
||||||
|
return (resolve) => requestAnimationFrame(afInterupter = resolve);
|
||||||
|
}
|
||||||
|
asc.id = 'a-f';
|
||||||
|
let qr = null;
|
||||||
|
asc.onanimationiteration = function () {
|
||||||
|
if (qr !== null) qr = (qr(), null);
|
||||||
|
}
|
||||||
|
if (!document.getElementById('afscript')) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = 'afscript';
|
||||||
|
style.textContent = `
|
||||||
|
@keyFrames aF1 {
|
||||||
|
0% {
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#a-f[id] {
|
||||||
|
visibility: collapse !important;
|
||||||
|
position: fixed !important;
|
||||||
|
display: block !important;
|
||||||
|
top: -100px !important;
|
||||||
|
left: -100px !important;
|
||||||
|
margin:0 !important;
|
||||||
|
padding:0 !important;
|
||||||
|
outline:0 !important;
|
||||||
|
border:0 !important;
|
||||||
|
z-index:-1 !important;
|
||||||
|
width: 0px !important;
|
||||||
|
height: 0px !important;
|
||||||
|
contain: strict !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
animation: 1ms steps(2, jump-none) 0ms infinite alternate forwards running aF1 !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
(document.head || document.documentElement).appendChild(style);
|
||||||
|
}
|
||||||
|
document.documentElement.insertBefore(asc, document.documentElement.firstChild);
|
||||||
|
return (resolve) => (qr = afInterupter = resolve);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {(resolve: () => void)} */
|
||||||
|
const rafPN = getRAFHelper(); // rAF will not execute if document is hidden
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
let afPromiseP, afPromiseQ; // non-null
|
||||||
|
afPromiseP = afPromiseQ = { resolved: true }; // initial state for !uP && !uQ
|
||||||
|
let afix = 0;
|
||||||
|
const afResolve = async (rX) => {
|
||||||
|
await new Promise(rafPN);
|
||||||
|
rX.resolved = true;
|
||||||
|
const t = afix = (afix & 1073741823) + 1;
|
||||||
|
return rX.resolve(t), t;
|
||||||
|
};
|
||||||
|
const eFunc = async () => {
|
||||||
|
const uP = !afPromiseP.resolved ? afPromiseP : null;
|
||||||
|
const uQ = !afPromiseQ.resolved ? afPromiseQ : null;
|
||||||
|
let t = 0;
|
||||||
|
if (uP && uQ) {
|
||||||
|
const t1 = await uP;
|
||||||
|
const t2 = await uQ;
|
||||||
|
t = ((t1 - t2) & 536870912) === 0 ? t1 : t2; // = 0 for t1 - t2 = [0, 536870911], [–1073741824, -536870913]
|
||||||
|
} else {
|
||||||
|
const vP = !uP ? (afPromiseP = new PromiseExternal()) : null;
|
||||||
|
const vQ = !uQ ? (afPromiseQ = new PromiseExternal()) : null;
|
||||||
|
if (uQ) await uQ; else if (uP) await uP;
|
||||||
|
if (vP) t = await afResolve(vP);
|
||||||
|
if (vQ) t = await afResolve(vQ);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const inExec = new Set();
|
||||||
|
const wFunc = async (handler, wStore) => {
|
||||||
|
try {
|
||||||
|
const ct = Date.now();
|
||||||
|
if (ct - timeupdateDT() < 800 && ct - wStore.dt < 800) {
|
||||||
|
const cid = wStore.cid;
|
||||||
|
inExec.add(cid);
|
||||||
|
const t = await eFunc();
|
||||||
|
const didNotRemove = inExec.delete(cid); // true for valid key
|
||||||
|
if (!didNotRemove || t === wStore.lastExecution) return;
|
||||||
|
wStore.lastExecution = t;
|
||||||
|
}
|
||||||
|
wStore.dt = ct;
|
||||||
|
handler();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const sFunc = (propFunc) => {
|
||||||
|
return (func, ms = 0, ...args) => {
|
||||||
|
if (typeof func === 'function') { // ignore all non-function parameter (e.g. string)
|
||||||
|
const wStore = { dt: Date.now() };
|
||||||
|
return (wStore.cid = propFunc(wFunc, ms, (args.length > 0 ? func.bind(null, ...args) : func), wStore));
|
||||||
|
} else {
|
||||||
|
return propFunc(func, ms, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
win.setTimeout = sFunc(setTimeout);
|
||||||
|
win.setInterval = sFunc(setInterval);
|
||||||
|
|
||||||
|
const dFunc = (propFunc) => {
|
||||||
|
return (cid) => {
|
||||||
|
if (cid) inExec.delete(cid) || propFunc(cid);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
win.clearTimeout = dFunc(clearTimeout);
|
||||||
|
win.clearInterval = dFunc(clearInterval);
|
||||||
|
|
||||||
|
try {
|
||||||
|
win.setTimeout.toString = setTimeout.toString.bind(setTimeout);
|
||||||
|
win.setInterval.toString = setInterval.toString.bind(setInterval);
|
||||||
|
win.clearTimeout.toString = clearTimeout.toString.bind(clearTimeout);
|
||||||
|
win.clearInterval.toString = clearInterval.toString.bind(clearInterval);
|
||||||
|
} catch (e) { console.warn(e) }
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
let mInterupter = null;
|
||||||
|
setInterval(() => {
|
||||||
|
if (mInterupter === afInterupter) {
|
||||||
|
if (mInterupter !== null) afInterupter = mInterupter = (mInterupter(), null);
|
||||||
|
} else {
|
||||||
|
mInterupter = afInterupter;
|
||||||
|
}
|
||||||
|
}, 125);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
3
src/plugins/performance-improvement/scripts/cpu-tamer/cpu-tamer-by-dom-mutation.d.ts
vendored
Normal file
3
src/plugins/performance-improvement/scripts/cpu-tamer/cpu-tamer-by-dom-mutation.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export declare const injectCpuTamerByDomMutation: (
|
||||||
|
__CONTEXT__: unknown,
|
||||||
|
) => void;
|
||||||
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright 2024-2025 CY Fung
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export const injectCpuTamerByDomMutation = ((__CONTEXT__) => {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const win = this instanceof Window ? this : window;
|
||||||
|
|
||||||
|
// Create a unique key for the script and check if it is already running
|
||||||
|
const hkey_script = 'nzsxclvflluv';
|
||||||
|
if (win[hkey_script]) throw new Error('Duplicated Userscript Calling'); // avoid duplicated scripting
|
||||||
|
win[hkey_script] = true;
|
||||||
|
|
||||||
|
/** @type {globalThis.PromiseConstructor} */
|
||||||
|
const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
|
||||||
|
const PromiseExternal = ((resolve_, reject_) => {
|
||||||
|
const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
|
||||||
|
return class PromiseExternal extends Promise {
|
||||||
|
constructor(cb = h) {
|
||||||
|
super(cb);
|
||||||
|
if (cb === h) {
|
||||||
|
/** @type {(value: any) => void} */
|
||||||
|
this.resolve = resolve_;
|
||||||
|
/** @type {(reason?: any) => void} */
|
||||||
|
this.reject = reject_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
// for future use
|
||||||
|
/*
|
||||||
|
const timeupdateDT = (() => {
|
||||||
|
|
||||||
|
window.__j6YiAc__ = 1;
|
||||||
|
|
||||||
|
document.addEventListener('timeupdate', () => {
|
||||||
|
window.__j6YiAc__ = Date.now();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
let kz = -1;
|
||||||
|
try {
|
||||||
|
kz = top.__j6YiAc__;
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return kz >= 1 ? () => top.__j6YiAc__ : () => window.__j6YiAc__;
|
||||||
|
|
||||||
|
})();
|
||||||
|
*/
|
||||||
|
|
||||||
|
const cleanContext = async (win) => {
|
||||||
|
const waitFn = requestAnimationFrame; // shall have been binded to window
|
||||||
|
try {
|
||||||
|
let mx = 16; // MAX TRIAL
|
||||||
|
const frameId = 'vanillajs-iframe-v1'
|
||||||
|
let frame = document.getElementById(frameId);
|
||||||
|
let removeIframeFn = null;
|
||||||
|
if (!frame) {
|
||||||
|
frame = document.createElement('iframe');
|
||||||
|
frame.id = frameId;
|
||||||
|
const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash
|
||||||
|
frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe
|
||||||
|
let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting)
|
||||||
|
n.appendChild(frame);
|
||||||
|
while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine
|
||||||
|
const root = document.documentElement;
|
||||||
|
root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL
|
||||||
|
if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL));
|
||||||
|
|
||||||
|
removeIframeFn = (setTimeout) => {
|
||||||
|
const removeIframeOnDocumentReady = (e) => {
|
||||||
|
e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
|
||||||
|
e = n;
|
||||||
|
n = win = removeIframeFn = 0;
|
||||||
|
setTimeout ? setTimeout(() => e.remove(), 200) : e.remove();
|
||||||
|
}
|
||||||
|
if (!setTimeout || document.readyState !== 'loading') {
|
||||||
|
removeIframeOnDocumentReady();
|
||||||
|
} else {
|
||||||
|
win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn);
|
||||||
|
const fc = frame.contentWindow;
|
||||||
|
if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL
|
||||||
|
try {
|
||||||
|
const { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout } = fc;
|
||||||
|
const res = { requestAnimationFrame, setInterval, setTimeout, clearInterval, clearTimeout };
|
||||||
|
for (let k in res) res[k] = res[k].bind(win); // necessary
|
||||||
|
if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn);
|
||||||
|
return res;
|
||||||
|
} catch (e) {
|
||||||
|
if (removeIframeFn) removeIframeFn();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const { _setAttribute, _insertBefore, _hasAttribute } = (() => {
|
||||||
|
let _setAttribute = Element.prototype.setAttribute;
|
||||||
|
try {
|
||||||
|
_setAttribute = ShadyDOM.nativeMethods.setAttribute || _setAttribute;
|
||||||
|
} catch (e) { }
|
||||||
|
let _hasAttribute = Element.prototype.hasAttribute;
|
||||||
|
try {
|
||||||
|
_hasAttribute = ShadyDOM.nativeMethods.hasAttribute || _hasAttribute;
|
||||||
|
} catch (e) { }
|
||||||
|
let _insertBefore = Node.prototype.insertBefore;
|
||||||
|
try {
|
||||||
|
_insertBefore = ShadyDOM.nativeMethods.insertBefore || _insertBefore;
|
||||||
|
} catch (e) { }
|
||||||
|
return { _setAttribute, _insertBefore, _hasAttribute};
|
||||||
|
})();
|
||||||
|
|
||||||
|
cleanContext(win).then(__CONTEXT__ => {
|
||||||
|
|
||||||
|
if (!__CONTEXT__) return null;
|
||||||
|
|
||||||
|
const { setTimeout, setInterval, clearTimeout, clearInterval } = __CONTEXT__;
|
||||||
|
|
||||||
|
/*
|
||||||
|
/-** @type {Function|null} *-/
|
||||||
|
// let afInterupter = null;
|
||||||
|
*/
|
||||||
|
|
||||||
|
const getDMHelper = () => {
|
||||||
|
let _dm = document.getElementById('d-m');
|
||||||
|
if (!_dm) {
|
||||||
|
_dm = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
||||||
|
_dm.id = 'd-m';
|
||||||
|
_insertBefore.call(document.documentElement, _dm, document.documentElement.firstChild);
|
||||||
|
}
|
||||||
|
const dm = _dm;
|
||||||
|
dm._setAttribute = _setAttribute;
|
||||||
|
dm._hasAttribute = _hasAttribute;
|
||||||
|
let j = 0;
|
||||||
|
let attributeName_;
|
||||||
|
while (dm._hasAttribute(attributeName_ = `dm-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`)) {
|
||||||
|
// none
|
||||||
|
}
|
||||||
|
const attributeName = attributeName_;
|
||||||
|
let sr = null;
|
||||||
|
const mo = new MutationObserver(() => {
|
||||||
|
const sr_ = sr;
|
||||||
|
if (sr_ !== null) {
|
||||||
|
sr = null;
|
||||||
|
if (j > 8) j = 0;
|
||||||
|
sr_.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mo.observe(document, { childList: true, subtree: true, attributes: true });
|
||||||
|
return () => {
|
||||||
|
return sr || (sr = (dm._setAttribute(attributeName, ++j), (new PromiseExternal()))); // mutationcallback in next macrotask
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @type {(resolve: () => void)} */
|
||||||
|
const dmSN = getDMHelper(); // dm will execute even if document is hidden
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
let dmPromiseP, dmPromiseQ; // non-null
|
||||||
|
dmPromiseP = dmPromiseQ = { resolved: true }; // initial state for !uP && !uQ
|
||||||
|
let dmix = 0;
|
||||||
|
const dmResolve = async (rX) => {
|
||||||
|
await dmSN();
|
||||||
|
rX.resolved = true;
|
||||||
|
const t = dmix = (dmix & 1073741823) + 1;
|
||||||
|
return rX.resolve(t), t;
|
||||||
|
};
|
||||||
|
const eFunc = async () => {
|
||||||
|
const uP = !dmPromiseP.resolved ? dmPromiseP : null;
|
||||||
|
const uQ = !dmPromiseQ.resolved ? dmPromiseQ : null;
|
||||||
|
let t = 0;
|
||||||
|
if (uP && uQ) {
|
||||||
|
const t1 = await uP;
|
||||||
|
const t2 = await uQ;
|
||||||
|
t = ((t1 - t2) & 536870912) === 0 ? t1 : t2; // = 0 for t1 - t2 = [0, 536870911], [–1073741824, -536870913]
|
||||||
|
} else {
|
||||||
|
const vP = !uP ? (dmPromiseP = new PromiseExternal()) : null;
|
||||||
|
const vQ = !uQ ? (dmPromiseQ = new PromiseExternal()) : null;
|
||||||
|
if (uQ) await uQ; else if (uP) await uP;
|
||||||
|
if (vP) t = await dmResolve(vP);
|
||||||
|
if (vQ) t = await dmResolve(vQ);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
const inExec = new Set();
|
||||||
|
const wFunc = async (handler, wStore) => {
|
||||||
|
try {
|
||||||
|
const ct = Date.now();
|
||||||
|
if (ct - wStore.dt < 800) {
|
||||||
|
const cid = wStore.cid;
|
||||||
|
inExec.add(cid);
|
||||||
|
const t = await eFunc();
|
||||||
|
const didNotRemove = inExec.delete(cid); // true for valid key
|
||||||
|
if (!didNotRemove || t === wStore.lastExecution) return;
|
||||||
|
wStore.lastExecution = t;
|
||||||
|
}
|
||||||
|
wStore.dt = ct;
|
||||||
|
handler();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const sFunc = (propFunc) => {
|
||||||
|
return (func, ms = 0, ...args) => {
|
||||||
|
if (typeof func === 'function') { // ignore all non-function parameter (e.g. string)
|
||||||
|
const wStore = { dt: Date.now() };
|
||||||
|
return (wStore.cid = propFunc(wFunc, ms, (args.length > 0 ? func.bind(null, ...args) : func), wStore));
|
||||||
|
} else {
|
||||||
|
return propFunc(func, ms, ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
win.setTimeout = sFunc(setTimeout);
|
||||||
|
win.setInterval = sFunc(setInterval);
|
||||||
|
|
||||||
|
const dFunc = (propFunc) => {
|
||||||
|
return (cid) => {
|
||||||
|
if (cid) inExec.delete(cid) || propFunc(cid);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
win.clearTimeout = dFunc(clearTimeout);
|
||||||
|
win.clearInterval = dFunc(clearInterval);
|
||||||
|
|
||||||
|
try {
|
||||||
|
win.setTimeout.toString = setTimeout.toString.bind(setTimeout);
|
||||||
|
win.setInterval.toString = setInterval.toString.bind(setInterval);
|
||||||
|
win.clearTimeout.toString = clearTimeout.toString.bind(clearTimeout);
|
||||||
|
win.clearInterval.toString = clearInterval.toString.bind(clearInterval);
|
||||||
|
} catch (e) { console.warn(e) }
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
||||||
|
/*
|
||||||
|
let mInterupter = null;
|
||||||
|
setInterval(() => {
|
||||||
|
if (mInterupter === afInterupter) {
|
||||||
|
if (mInterupter !== null) afInterupter = mInterupter = (mInterupter(), null);
|
||||||
|
} else {
|
||||||
|
mInterupter = afInterupter;
|
||||||
|
}
|
||||||
|
}, 125);
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { injectCpuTamerByAnimationFrame } from './cpu-tamer-by-animationframe';
|
||||||
|
import { injectCpuTamerByDomMutation } from './cpu-tamer-by-dom-mutation';
|
||||||
|
|
||||||
|
const isGPUAccelerationAvailable = () => {
|
||||||
|
// https://gist.github.com/cvan/042b2448fcecefafbb6a91469484cdf8
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
return !!(
|
||||||
|
canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const injectCpuTamer = () => {
|
||||||
|
if (isGPUAccelerationAvailable()) {
|
||||||
|
injectCpuTamerByAnimationFrame(null);
|
||||||
|
} else {
|
||||||
|
injectCpuTamerByDomMutation(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
1
src/plugins/performance-improvement/scripts/rm3/index.ts
Normal file
1
src/plugins/performance-improvement/scripts/rm3/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './rm3';
|
||||||
121
src/plugins/performance-improvement/scripts/rm3/rm3.d.ts
vendored
Normal file
121
src/plugins/performance-improvement/scripts/rm3/rm3.d.ts
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
declare class Rm3LinkedArrayNode<T> {
|
||||||
|
value: T;
|
||||||
|
next: Rm3LinkedArrayNode<T> | null;
|
||||||
|
prev: Rm3LinkedArrayNode<T> | null;
|
||||||
|
constructor(value: T);
|
||||||
|
}
|
||||||
|
|
||||||
|
declare class Rm3LinkedArray<T> {
|
||||||
|
head: Rm3LinkedArrayNode<T> | null;
|
||||||
|
tail: Rm3LinkedArrayNode<T> | null;
|
||||||
|
length: number;
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
push(value: T): number;
|
||||||
|
pop(): T | undefined;
|
||||||
|
unshift(value: T): number;
|
||||||
|
shift(): T | undefined;
|
||||||
|
size(): number;
|
||||||
|
getNode(index: number): Rm3LinkedArrayNode<T> | null;
|
||||||
|
get(index: number): T | undefined;
|
||||||
|
findNode(value: T): { node: Rm3LinkedArrayNode<T> | null; index: number };
|
||||||
|
toArray(): T[];
|
||||||
|
insertBeforeNode(node: Rm3LinkedArrayNode<T> | null, newValue: T): boolean;
|
||||||
|
insertAfterNode(node: Rm3LinkedArrayNode<T> | null, newValue: T): boolean;
|
||||||
|
insertBefore(existingValue: T, newValue: T): boolean;
|
||||||
|
insertAfter(existingValue: T, newValue: T): boolean;
|
||||||
|
deleteNode(node: Rm3LinkedArrayNode<T>): boolean; // Note: Original JS allowed deleting null, but TS implies non-null here
|
||||||
|
|
||||||
|
static Node: typeof Rm3LinkedArrayNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the structure of the internal LimitedSizeSet class
|
||||||
|
declare class Rm3LimitedSizeSet<T> extends Set<T> {
|
||||||
|
limit: number;
|
||||||
|
constructor(n: number);
|
||||||
|
add(key: T): this;
|
||||||
|
removeAdd(key: T): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the structure of the entryRecord tuple used internally
|
||||||
|
// [ WeakRef<HTMLElement>, attached time, detached time, time of change, inside availablePool, reuse count ]
|
||||||
|
type Rm3EntryRecord = [
|
||||||
|
WeakRef<HTMLElement>,
|
||||||
|
number,
|
||||||
|
number,
|
||||||
|
number,
|
||||||
|
boolean,
|
||||||
|
number,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Define the interface for the exported rm3 object
|
||||||
|
export interface Rm3 {
|
||||||
|
/**
|
||||||
|
* Removes duplicate values from an array.
|
||||||
|
* @param array The input array.
|
||||||
|
* @returns A new array with unique values.
|
||||||
|
*/
|
||||||
|
uniq: <T>(array: T[]) => T[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Debug only] The current page URL. Only available if DEBUG_OPT was true.
|
||||||
|
*/
|
||||||
|
location?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Debug only] Inspects the document for elements with a polymerController and returns their unique node names.
|
||||||
|
* @returns An array of unique node names.
|
||||||
|
*/
|
||||||
|
inspect: () => string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Set containing records of element operations (attach/detach).
|
||||||
|
* Each record tracks an element's lifecycle state.
|
||||||
|
*/
|
||||||
|
operations: Set<Rm3EntryRecord>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map where keys are component identifiers (e.g., "creatorTag.componentTag")
|
||||||
|
* and values are LinkedArrays of potentially reusable EntryRecords for detached elements.
|
||||||
|
*/
|
||||||
|
availablePools: Map<string, Rm3LinkedArray<Rm3EntryRecord>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the parent status of elements tracked in the operations set.
|
||||||
|
* Primarily for elements that have been detached (detached time > 0).
|
||||||
|
* @returns An array of tuples: [elementExists: boolean, nodeName: string | undefined, isParentNull: boolean]
|
||||||
|
*/
|
||||||
|
checkWhetherUnderParent: () => [boolean, string | undefined, boolean][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of unique element tag names (from `element.is`) that have been tracked.
|
||||||
|
* @returns An array of unique tag names.
|
||||||
|
*/
|
||||||
|
hookTags: () => string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Debug only] A Set containing tags that have had their methods hooked. Only available if DEBUG_OPT was true.
|
||||||
|
*/
|
||||||
|
hookTos?: Set<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Debug only] A function that returns an array representation of the reuse record log. Only available if DEBUG_OPT was true.
|
||||||
|
* @returns An array of tuples: [timestamp, tagName, entryRecord]
|
||||||
|
*/
|
||||||
|
reuseRecord?: () => [number, string, Rm3EntryRecord][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Debug only] A Map tracking the reuse count per component tag name. Only available if DEBUG_OPT was true.
|
||||||
|
*/
|
||||||
|
reuseCount_?: Map<string, number>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A counter for the total number of times elements have been reused.
|
||||||
|
*/
|
||||||
|
reuseCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const rm3: Rm3;
|
||||||
|
|
||||||
|
export function injectRm3(): void;
|
||||||
828
src/plugins/performance-improvement/scripts/rm3/rm3.js
Normal file
828
src/plugins/performance-improvement/scripts/rm3/rm3.js
Normal file
@ -0,0 +1,828 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright 2024-2025 CY Fung
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export const rm3 = {};
|
||||||
|
|
||||||
|
export const injectRm3 = () => {
|
||||||
|
const DEBUG_OPT = false;
|
||||||
|
const CONFIRM_TIME = 4000;
|
||||||
|
const CHECK_INTERVAL = 400;
|
||||||
|
const DEBUG_dataChangeReflection = true;
|
||||||
|
|
||||||
|
/** @type {globalThis.PromiseConstructor} */
|
||||||
|
const Promise = (async () => {})().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
|
||||||
|
|
||||||
|
// https://qiita.com/piroor/items/02885998c9f76f45bfa0
|
||||||
|
// https://gist.github.com/piroor/829ecb32a52c2a42e5393bbeebe5e63f
|
||||||
|
function uniq(array) {
|
||||||
|
return [...new Set(array)];
|
||||||
|
}
|
||||||
|
|
||||||
|
rm3.uniq = uniq; // [[debug]]
|
||||||
|
DEBUG_OPT && (rm3.location = location.href);
|
||||||
|
|
||||||
|
rm3.inspect = () => {
|
||||||
|
return uniq(
|
||||||
|
[...document.getElementsByTagName('*')]
|
||||||
|
.filter((e) => e?.polymerController?.createComponent_)
|
||||||
|
.map((e) => e.nodeName),
|
||||||
|
); // [[debug]]
|
||||||
|
};
|
||||||
|
|
||||||
|
const insp = (o) => o ? o.polymerController || o.inst || o || 0 : o || 0;
|
||||||
|
const indr = (o) => insp(o).$ || o.$ || 0;
|
||||||
|
|
||||||
|
const getProto = (element) => {
|
||||||
|
if (element) {
|
||||||
|
const cnt = insp(element);
|
||||||
|
return cnt.constructor.prototype || null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const LinkedArray = (() => {
|
||||||
|
class Node {
|
||||||
|
constructor(value) {
|
||||||
|
this.value = value;
|
||||||
|
this.next = null;
|
||||||
|
this.prev = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinkedArray {
|
||||||
|
constructor() {
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
this.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(value) {
|
||||||
|
const newNode = new Node(value);
|
||||||
|
if (this.length === 0) {
|
||||||
|
this.head = newNode;
|
||||||
|
this.tail = newNode;
|
||||||
|
} else {
|
||||||
|
this.tail.next = newNode;
|
||||||
|
newNode.prev = this.tail;
|
||||||
|
this.tail = newNode;
|
||||||
|
}
|
||||||
|
this.length++;
|
||||||
|
return this.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
pop() {
|
||||||
|
if (this.length === 0) return undefined;
|
||||||
|
const removedNode = this.tail;
|
||||||
|
if (this.length === 1) {
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
} else {
|
||||||
|
this.tail = removedNode.prev;
|
||||||
|
this.tail.next = null;
|
||||||
|
removedNode.prev = null;
|
||||||
|
}
|
||||||
|
this.length--;
|
||||||
|
return removedNode.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unshift(value) {
|
||||||
|
const newNode = new Node(value);
|
||||||
|
if (this.length === 0) {
|
||||||
|
this.head = newNode;
|
||||||
|
this.tail = newNode;
|
||||||
|
} else {
|
||||||
|
newNode.next = this.head;
|
||||||
|
this.head.prev = newNode;
|
||||||
|
this.head = newNode;
|
||||||
|
}
|
||||||
|
this.length++;
|
||||||
|
return this.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
shift() {
|
||||||
|
if (this.length === 0) return undefined;
|
||||||
|
const removedNode = this.head;
|
||||||
|
if (this.length === 1) {
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
} else {
|
||||||
|
this.head = removedNode.next;
|
||||||
|
this.head.prev = null;
|
||||||
|
removedNode.next = null;
|
||||||
|
}
|
||||||
|
this.length--;
|
||||||
|
return removedNode.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
size() {
|
||||||
|
return this.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a node by index (0-based)
|
||||||
|
getNode(index) {
|
||||||
|
if (index < 0 || index >= this.length) return null;
|
||||||
|
|
||||||
|
let current;
|
||||||
|
let counter;
|
||||||
|
|
||||||
|
// Optimization: start from closest end
|
||||||
|
if (index < this.length / 2) {
|
||||||
|
current = this.head;
|
||||||
|
counter = 0;
|
||||||
|
while (counter !== index) {
|
||||||
|
current = current.next;
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current = this.tail;
|
||||||
|
counter = this.length - 1;
|
||||||
|
while (counter !== index) {
|
||||||
|
current = current.prev;
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get value by index
|
||||||
|
get(index) {
|
||||||
|
const node = this.getNode(index);
|
||||||
|
return node ? node.value : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the first node with the given value and return both node and index
|
||||||
|
findNode(value) {
|
||||||
|
let current = this.head;
|
||||||
|
let idx = 0;
|
||||||
|
while (current) {
|
||||||
|
if (current.value === value) {
|
||||||
|
return { node: current, index: idx };
|
||||||
|
}
|
||||||
|
current = current.next;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
return { node: null, index: -1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
toArray() {
|
||||||
|
const arr = [];
|
||||||
|
let current = this.head;
|
||||||
|
while (current) {
|
||||||
|
arr.push(current.value);
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a new value before a given node (provided you already have the node reference)
|
||||||
|
insertBeforeNode(node, newValue) {
|
||||||
|
if (!node) {
|
||||||
|
this.unshift(newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node === this.head) {
|
||||||
|
// If the target is the head, just unshift
|
||||||
|
this.unshift(newValue);
|
||||||
|
} else {
|
||||||
|
const newNode = new Node(newValue);
|
||||||
|
const prevNode = node.prev;
|
||||||
|
|
||||||
|
prevNode.next = newNode;
|
||||||
|
newNode.prev = prevNode;
|
||||||
|
newNode.next = node;
|
||||||
|
node.prev = newNode;
|
||||||
|
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a new value after a given node (provided you already have the node reference)
|
||||||
|
insertAfterNode(node, newValue) {
|
||||||
|
if (!node) {
|
||||||
|
this.push(newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node === this.tail) {
|
||||||
|
// If the target is the tail, just push
|
||||||
|
this.push(newValue);
|
||||||
|
} else {
|
||||||
|
const newNode = new Node(newValue);
|
||||||
|
const nextNode = node.next;
|
||||||
|
|
||||||
|
node.next = newNode;
|
||||||
|
newNode.prev = node;
|
||||||
|
newNode.next = nextNode;
|
||||||
|
nextNode.prev = newNode;
|
||||||
|
|
||||||
|
this.length++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a new value before the first occurrence of an existing value (search by value)
|
||||||
|
insertBefore(existingValue, newValue) {
|
||||||
|
const { node } = this.findNode(existingValue);
|
||||||
|
if (!node) return false; // Not found
|
||||||
|
return this.insertBeforeNode(node, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a new value after the first occurrence of an existing value (search by value)
|
||||||
|
insertAfter(existingValue, newValue) {
|
||||||
|
const { node } = this.findNode(existingValue);
|
||||||
|
if (!node) return false; // Not found
|
||||||
|
return this.insertAfterNode(node, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a given node from the list
|
||||||
|
deleteNode(node) {
|
||||||
|
if (!node) return false;
|
||||||
|
|
||||||
|
if (this.length === 1 && node === this.head && node === this.tail) {
|
||||||
|
// Only one element in the list
|
||||||
|
this.head = null;
|
||||||
|
this.tail = null;
|
||||||
|
} else if (node === this.head) {
|
||||||
|
// Node is the head
|
||||||
|
this.head = node.next;
|
||||||
|
this.head.prev = null;
|
||||||
|
node.next = null;
|
||||||
|
} else if (node === this.tail) {
|
||||||
|
// Node is the tail
|
||||||
|
this.tail = node.prev;
|
||||||
|
this.tail.next = null;
|
||||||
|
node.prev = null;
|
||||||
|
} else {
|
||||||
|
// Node is in the middle
|
||||||
|
const prevNode = node.prev;
|
||||||
|
const nextNode = node.next;
|
||||||
|
prevNode.next = nextNode;
|
||||||
|
nextNode.prev = prevNode;
|
||||||
|
node.prev = null;
|
||||||
|
node.next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedArray.Node = Node;
|
||||||
|
return LinkedArray;
|
||||||
|
})();
|
||||||
|
|
||||||
|
class LimitedSizeSet extends Set {
|
||||||
|
constructor(n) {
|
||||||
|
super();
|
||||||
|
this.limit = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
add(key) {
|
||||||
|
if (!super.has(key)) {
|
||||||
|
super.add(key);
|
||||||
|
let n = super.size - this.limit;
|
||||||
|
if (n > 0) {
|
||||||
|
const iterator = super.values();
|
||||||
|
do {
|
||||||
|
const firstKey = iterator.next().value; // Get the first (oldest) key
|
||||||
|
super.delete(firstKey); // Delete the oldest key
|
||||||
|
} while (--n > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAdd(key) {
|
||||||
|
super.delete(key);
|
||||||
|
this.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!document.createElement9512 &&
|
||||||
|
typeof document.createElement === 'function' &&
|
||||||
|
document.createElement.length === 1
|
||||||
|
) {
|
||||||
|
// sizing of Map / Set. Shall limit ?
|
||||||
|
|
||||||
|
const hookTos = new Set(); // [[debug]]
|
||||||
|
DEBUG_OPT && (rm3.hookTos = hookTos);
|
||||||
|
|
||||||
|
// const reusePool = new Map(); // xx858
|
||||||
|
const entryRecords = new WeakMap(); // a weak link between element and record
|
||||||
|
|
||||||
|
// rm3.list = [];
|
||||||
|
|
||||||
|
const operations = rm3.operations = new Set(); // to find out the "oldest elements"
|
||||||
|
|
||||||
|
const availablePools = rm3.availablePools = new Map(); // those "old elements" can be used
|
||||||
|
let lastTimeCheck = 0;
|
||||||
|
|
||||||
|
const reuseRecord_ = new LimitedSizeSet(256); // [[debug]]
|
||||||
|
const reuseCount_ = new Map();
|
||||||
|
|
||||||
|
let noTimeCheck = false;
|
||||||
|
|
||||||
|
// const defaultValues = new Map();
|
||||||
|
// const noValues = new Map();
|
||||||
|
|
||||||
|
const timeCheck = () => {
|
||||||
|
// regularly check elements are old enough to put into the available pools
|
||||||
|
// note: the characterists of YouTube components are non-volatile. So don't need to waste time to check weakRef.deref() is null or not for removing in operations.
|
||||||
|
|
||||||
|
const ct = Date.now();
|
||||||
|
if (ct - lastTimeCheck < CHECK_INTERVAL || noTimeCheck) return;
|
||||||
|
lastTimeCheck = ct;
|
||||||
|
noTimeCheck = true;
|
||||||
|
|
||||||
|
// 16,777,216
|
||||||
|
if (hookTos.size > 777216) hookTos.clear(); // just debug usage, dont concern
|
||||||
|
if (operations.size > 7777216) {
|
||||||
|
// extremely old elements in operations mean they have no attach/detach action. so no reuse as well. they are just trash in memory.
|
||||||
|
// as no checking of the weakRef.deref() being null or not, those trash could be already cleaned. However we don't concern this.
|
||||||
|
// (not to count whether they are actual memory trash or not)
|
||||||
|
const half = operations.size >>> 1;
|
||||||
|
let i = 0;
|
||||||
|
for (const value of operations) {
|
||||||
|
if (i++ > half) break;
|
||||||
|
operations.delete(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// // smallest to largest
|
||||||
|
// // past to recent
|
||||||
|
|
||||||
|
// const iterator = operations[Symbol.iterator]();
|
||||||
|
// console.log(1831, '------------------------')
|
||||||
|
// while (true) {
|
||||||
|
// const iteratorResult = iterator.next(); // 順番に値を取りだす
|
||||||
|
// if (iteratorResult.done) break; // 取り出し終えたなら、break
|
||||||
|
// console.log(1835, iteratorResult.value[3])
|
||||||
|
// }
|
||||||
|
|
||||||
|
// console.log(1839, '------------------------')
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Set iterator
|
||||||
|
// s.add(2) s.add(6) s.add(1) s.add(3)
|
||||||
|
// next: 2 -> 6 -> 1 -> 3
|
||||||
|
// op1 (oldest) -> op2 -> op3 -> op4 (latest)
|
||||||
|
const iterator = operations[Symbol.iterator]();
|
||||||
|
|
||||||
|
const targetTime = ct - CONFIRM_TIME;
|
||||||
|
|
||||||
|
const pivotNodes = new WeakMap();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const iteratorResult = iterator.next(); // 順番に値を取りだす
|
||||||
|
if (iteratorResult.done) break; // 取り出し終えたなら、break
|
||||||
|
const entryRecord = iteratorResult.value;
|
||||||
|
if (entryRecord[3] > targetTime) break;
|
||||||
|
|
||||||
|
if (!entryRecord[4] && entryRecord[1] < 0 && entryRecord[2] > 0) {
|
||||||
|
const element = entryRecord[0].deref();
|
||||||
|
const eKey = (element || 0).__rm3Tag003__;
|
||||||
|
if (!eKey) {
|
||||||
|
operations.delete(entryRecord);
|
||||||
|
} else if (
|
||||||
|
element.isConnected === false &&
|
||||||
|
insp(element).isAttached === false
|
||||||
|
) {
|
||||||
|
entryRecord[4] = true;
|
||||||
|
|
||||||
|
let availablePool = availablePools.get(eKey);
|
||||||
|
if (!availablePool)
|
||||||
|
availablePools.set(eKey, availablePool = new LinkedArray());
|
||||||
|
if (!(availablePool instanceof LinkedArray)) throw new Error();
|
||||||
|
DEBUG_OPT &&
|
||||||
|
console.log(3885, 'add key', eKey, availablePools.size);
|
||||||
|
// rm3.showSize = ()=>availablePools.size
|
||||||
|
// setTimeout(()=>{
|
||||||
|
// // window?.euu1 = availablePools
|
||||||
|
// // window?.euu2 = availablePools.size
|
||||||
|
// console.log(availablePools.size)
|
||||||
|
// }, 8000)
|
||||||
|
let pivotNode = pivotNodes.get(availablePool);
|
||||||
|
if (!pivotNode)
|
||||||
|
pivotNodes.set(availablePool, pivotNode = availablePool.head); // cached the previous newest node (head) as pivotNode
|
||||||
|
|
||||||
|
availablePool.insertBeforeNode(pivotNode, entryRecord); // head = newest, tail = oldest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
noTimeCheck = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const attachedDefine = function () {
|
||||||
|
Promise.resolve().then(timeCheck);
|
||||||
|
try {
|
||||||
|
const hostElement = this?.hostElement;
|
||||||
|
if (hostElement instanceof HTMLElement) {
|
||||||
|
const entryRecord = entryRecords.get(hostElement);
|
||||||
|
if (
|
||||||
|
entryRecord &&
|
||||||
|
entryRecord[0].deref() === hostElement &&
|
||||||
|
hostElement.isConnected === true &&
|
||||||
|
this?.isAttached === true
|
||||||
|
) {
|
||||||
|
noTimeCheck = true;
|
||||||
|
const ct = Date.now();
|
||||||
|
entryRecord[1] = ct;
|
||||||
|
entryRecord[2] = -1;
|
||||||
|
entryRecord[3] = ct;
|
||||||
|
operations.delete(entryRecord);
|
||||||
|
operations.add(entryRecord);
|
||||||
|
noTimeCheck = false;
|
||||||
|
// note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.
|
||||||
|
// entryRecord[4] is not required to be updated here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return this.attached9512();
|
||||||
|
};
|
||||||
|
const detachedDefine = function () {
|
||||||
|
Promise.resolve().then(timeCheck);
|
||||||
|
try {
|
||||||
|
const hostElement = this?.hostElement;
|
||||||
|
if (hostElement instanceof HTMLElement) {
|
||||||
|
const entryRecord = entryRecords.get(hostElement);
|
||||||
|
if (
|
||||||
|
entryRecord &&
|
||||||
|
entryRecord[0].deref() === hostElement &&
|
||||||
|
hostElement.isConnected === false &&
|
||||||
|
this?.isAttached === false
|
||||||
|
) {
|
||||||
|
noTimeCheck = true;
|
||||||
|
const ct = Date.now();
|
||||||
|
entryRecord[2] = ct;
|
||||||
|
entryRecord[1] = -1;
|
||||||
|
entryRecord[3] = ct;
|
||||||
|
operations.delete(entryRecord);
|
||||||
|
operations.add(entryRecord);
|
||||||
|
noTimeCheck = false;
|
||||||
|
// note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.
|
||||||
|
// entryRecord[4] is not required to be updated here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return this.detached9512();
|
||||||
|
};
|
||||||
|
|
||||||
|
// function cpy(x) {
|
||||||
|
// if (!x) return x;
|
||||||
|
// try {
|
||||||
|
// if (typeof x === 'object' && typeof x.length ==='number' && typeof x.slice === 'function') {
|
||||||
|
// x = x.slice(0)
|
||||||
|
// } else if (typeof x === 'object' && !x.length) {
|
||||||
|
// x = JSON.parse(JSON.stringify(x));
|
||||||
|
// } else {
|
||||||
|
// return Object.assign({}, x);
|
||||||
|
// }
|
||||||
|
// } catch (e) { }
|
||||||
|
// return x;
|
||||||
|
// }
|
||||||
|
|
||||||
|
async function digestMessage(message) {
|
||||||
|
const msgUint8 = new TextEncoder().encode(message); // (utf-8 の) Uint8Array にエンコードする
|
||||||
|
const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); // メッセージをハッシュする
|
||||||
|
const hashArray = Array.from(new Uint8Array(hashBuffer)); // バッファーをバイト列に変換する
|
||||||
|
const hashHex = hashArray
|
||||||
|
.map((b) => b.toString(16).padStart(2, '0'))
|
||||||
|
.join(''); // バイト列を 16 進文字列に変換する
|
||||||
|
return hashHex.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
let onPageContainer = null;
|
||||||
|
|
||||||
|
const createComponentDefine_ = function (a, b, c) {
|
||||||
|
Promise.resolve().then(timeCheck);
|
||||||
|
|
||||||
|
const creatorTag = this?.is || this?.nodeName?.toLowerCase() || '';
|
||||||
|
|
||||||
|
const componentTag = typeof a === 'string' ? a : (a || 0).component || '';
|
||||||
|
|
||||||
|
const eKey =
|
||||||
|
creatorTag && componentTag ? `${creatorTag}.${componentTag}` : '*'; // '*' for play-safe
|
||||||
|
const availablePool = availablePools.get(eKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (availablePool instanceof LinkedArray) {
|
||||||
|
noTimeCheck = true;
|
||||||
|
|
||||||
|
let node = availablePool.tail; // oldest
|
||||||
|
|
||||||
|
while (node instanceof LinkedArray.Node) {
|
||||||
|
const entryRecord = node.value;
|
||||||
|
const prevNode = node.prev;
|
||||||
|
|
||||||
|
let ok = false;
|
||||||
|
let elm = null;
|
||||||
|
if (entryRecord[1] < 0 && entryRecord[2] > 0 && entryRecord[4]) {
|
||||||
|
elm = entryRecord[0].deref();
|
||||||
|
// elm && console.log(3882, (elm.__shady_native_textContent || elm.textContent))
|
||||||
|
if (
|
||||||
|
elm &&
|
||||||
|
elm instanceof HTMLElement &&
|
||||||
|
elm.isConnected === false &&
|
||||||
|
insp(elm).isAttached === false &&
|
||||||
|
elm.parentNode === null
|
||||||
|
) {
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
// useEntryRecord = entryRecord;
|
||||||
|
entryRecord[4] = false;
|
||||||
|
// console.log('nodeDeleted', 1, entryRecord[0].deref().nodeName)
|
||||||
|
availablePool.deleteNode(node);
|
||||||
|
// break;
|
||||||
|
|
||||||
|
if (!onPageContainer) {
|
||||||
|
let p = document.createElement('noscript');
|
||||||
|
document.body.prepend(p);
|
||||||
|
onPageContainer = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPageContainer.appendChild(elm); // to fix some issues for the rendered elements
|
||||||
|
|
||||||
|
const cnt = insp(elm);
|
||||||
|
|
||||||
|
cnt.__dataInvalid = false;
|
||||||
|
// cnt._initializeProtoProperties(cnt.data)
|
||||||
|
|
||||||
|
// window.meaa = cnt.$.container;
|
||||||
|
if (typeof (cnt.__data || 0) === 'object') {
|
||||||
|
cnt.__data = Object.assign({}, cnt.__data);
|
||||||
|
}
|
||||||
|
cnt.__dataPending = {};
|
||||||
|
cnt.__dataOld = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
cnt.markDirty();
|
||||||
|
} catch (e) {}
|
||||||
|
try {
|
||||||
|
cnt.markDirtyVisibilityObserver();
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
cnt.wasPrescan = cnt.wasVisible = !1;
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
// try{
|
||||||
|
// cnt._setPendingProperty('data', Object.assign({}, cntData), !0);
|
||||||
|
// }catch(e){}
|
||||||
|
// try {
|
||||||
|
// cnt._flushProperties();
|
||||||
|
// } catch (e) { }
|
||||||
|
|
||||||
|
if (DEBUG_OPT && DEBUG_dataChangeReflection) {
|
||||||
|
let jC1 = null;
|
||||||
|
let jC2 = null;
|
||||||
|
const jKey = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
|
||||||
|
try {
|
||||||
|
jC1 =
|
||||||
|
cnt.hostElement.__shady_native_textContent ||
|
||||||
|
cnt.hostElement.textContent;
|
||||||
|
// console.log(83802, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
jC2 =
|
||||||
|
cnt.hostElement.__shady_native_textContent ||
|
||||||
|
cnt.hostElement.textContent;
|
||||||
|
// console.log(83804, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
jC1 = await digestMessage(jC1);
|
||||||
|
jC2 = await digestMessage(jC2);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
83804,
|
||||||
|
jKey,
|
||||||
|
jC1.substring(0, 7),
|
||||||
|
jC2.substring(0, 7),
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryRecord[5] < 1e9) entryRecord[5] += 1;
|
||||||
|
DEBUG_OPT &&
|
||||||
|
Promise.resolve().then(() =>
|
||||||
|
console.log(`${eKey} reuse`, entryRecord),
|
||||||
|
); // give some time for attach process
|
||||||
|
DEBUG_OPT && reuseRecord_.add([Date.now(), cnt.is, entryRecord]);
|
||||||
|
DEBUG_OPT &&
|
||||||
|
reuseCount_.set(cnt.is, (reuseCount_.get(cnt.is) || 0) + 1);
|
||||||
|
if (rm3.reuseCount < 1e9) rm3.reuseCount++;
|
||||||
|
|
||||||
|
return elm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('condi88', entryRecord[1] < 0 , entryRecord[2] > 0 , !!entryRecord[4], !!entryRecord[0].deref())
|
||||||
|
|
||||||
|
entryRecord[4] = false;
|
||||||
|
|
||||||
|
// console.log(entryRecord);
|
||||||
|
// console.log('nodeDeleted',2, entryRecord[0]?.deref()?.nodeName)
|
||||||
|
availablePool.deleteNode(node);
|
||||||
|
node = prevNode;
|
||||||
|
}
|
||||||
|
// for(const ) availablePool
|
||||||
|
// noTimeCheck = false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
noTimeCheck = false;
|
||||||
|
|
||||||
|
// console.log('createComponentDefine_', a, b, c)
|
||||||
|
|
||||||
|
// if (!reusePool.has(componentTag)) reusePool.set(componentTag, new LinkedArray()); // xx858
|
||||||
|
|
||||||
|
// const pool = reusePool.get(componentTag); // xx858
|
||||||
|
// if (!(pool instanceof LinkedArray)) throw new Error(); // xx858
|
||||||
|
|
||||||
|
const newElement = this.createComponent9512_(a, b, c);
|
||||||
|
// if(componentTag.indexOf( 'ticker')>=0)console.log(1883, a,newElement)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cntE = insp(newElement);
|
||||||
|
if (!cntE.attached9512 && cntE.attached) {
|
||||||
|
const cProtoE = getProto(newElement);
|
||||||
|
|
||||||
|
if (cProtoE.attached === cntE.attached) {
|
||||||
|
if (
|
||||||
|
!cProtoE.attached9512 &&
|
||||||
|
typeof cProtoE.attached === 'function' &&
|
||||||
|
cProtoE.attached.length === 0
|
||||||
|
) {
|
||||||
|
cProtoE.attached9512 = cProtoE.attached;
|
||||||
|
|
||||||
|
cProtoE.attached = attachedDefine;
|
||||||
|
// hookTos.add(a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
typeof cntE.attached === 'function' &&
|
||||||
|
cntE.attached.length === 3
|
||||||
|
) {
|
||||||
|
cntE.attached9512 = cntE.attached;
|
||||||
|
|
||||||
|
cntE.attached = attachedDefine;
|
||||||
|
// hookTos.add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cntE.detached9512 && cntE.detached) {
|
||||||
|
const cProtoE = getProto(newElement);
|
||||||
|
|
||||||
|
if (cProtoE.detached === cntE.detached) {
|
||||||
|
if (
|
||||||
|
!cProtoE.detached9512 &&
|
||||||
|
typeof cProtoE.detached === 'function' &&
|
||||||
|
cProtoE.detached.length === 0
|
||||||
|
) {
|
||||||
|
cProtoE.detached9512 = cProtoE.detached;
|
||||||
|
|
||||||
|
cProtoE.detached = detachedDefine;
|
||||||
|
// hookTos.add(a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
typeof cntE.detached === 'function' &&
|
||||||
|
cntE.detached.length === 3
|
||||||
|
) {
|
||||||
|
cntE.detached9512 = cntE.detached;
|
||||||
|
|
||||||
|
cntE.detached = detachedDefine;
|
||||||
|
// hookTos.add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const acceptance = true;
|
||||||
|
// const acceptance = !cntE.__dataReady && cntE.__dataInvalid !== false; // we might need to change the acceptance condition along with YouTube Coding updates.
|
||||||
|
if (acceptance) {
|
||||||
|
// [[ weak ElementNode, attached time, detached time, time of change, inside availablePool, reuse count ]]
|
||||||
|
const entryRecord = [new WeakRef(newElement), -1, -1, -1, false, 0];
|
||||||
|
|
||||||
|
newElement.__rm3Tag003__ = eKey;
|
||||||
|
entryRecords.set(newElement, entryRecord);
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
return newElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
document.createElement9512 = document.createElement;
|
||||||
|
document.createElement = function (a) {
|
||||||
|
const r = document.createElement9512(a);
|
||||||
|
try {
|
||||||
|
const cnt = insp(r);
|
||||||
|
if (cnt.createComponent_ && !cnt.createComponent9512_) {
|
||||||
|
const cProto = getProto(r);
|
||||||
|
if (cProto.createComponent_ === cnt.createComponent_) {
|
||||||
|
if (
|
||||||
|
!cProto.createComponent9512_ &&
|
||||||
|
typeof cProto.createComponent_ === 'function' &&
|
||||||
|
cProto.createComponent_.length === 3
|
||||||
|
) {
|
||||||
|
cProto.createComponent9512_ = cProto.createComponent_;
|
||||||
|
|
||||||
|
cProto.createComponent_ = createComponentDefine_;
|
||||||
|
DEBUG_OPT && hookTos.add(a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
typeof cnt.createComponent_ === 'function' &&
|
||||||
|
cnt.createComponent_.length === 3
|
||||||
|
) {
|
||||||
|
cnt.createComponent9512_ = cnt.createComponent_;
|
||||||
|
|
||||||
|
cnt.createComponent_ = createComponentDefine_;
|
||||||
|
DEBUG_OPT && hookTos.add(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
rm3.checkWhetherUnderParent = () => {
|
||||||
|
const r = [];
|
||||||
|
for (const operation of operations) {
|
||||||
|
const elm = operation[0].deref();
|
||||||
|
if (operation[2] > 0) {
|
||||||
|
r.push([
|
||||||
|
!!elm,
|
||||||
|
elm?.nodeName.toLowerCase(),
|
||||||
|
elm?.parentNode === null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
rm3.hookTags = () => {
|
||||||
|
const r = new Set();
|
||||||
|
for (const operation of operations) {
|
||||||
|
const elm = operation[0].deref();
|
||||||
|
if (elm && elm.is) {
|
||||||
|
r.add(elm.is);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...r];
|
||||||
|
};
|
||||||
|
|
||||||
|
DEBUG_OPT &&
|
||||||
|
(rm3.reuseRecord = () => {
|
||||||
|
return [...reuseRecord_]; // [[debug]]
|
||||||
|
});
|
||||||
|
|
||||||
|
DEBUG_OPT && (rm3.reuseCount_ = reuseCount_);
|
||||||
|
}
|
||||||
|
|
||||||
|
rm3.reuseCount = 0;
|
||||||
|
};
|
||||||
@ -305,31 +305,14 @@ function registerMPRIS(win: BrowserWindow) {
|
|||||||
console.trace(error);
|
console.trace(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mprisVolNewer = false;
|
|
||||||
let autoUpdate = false;
|
|
||||||
ipcMain.on('ytmd:volume-changed', (_, newVol) => {
|
ipcMain.on('ytmd:volume-changed', (_, newVol) => {
|
||||||
if (~~(player.volume * 100) !== newVol) {
|
player.volume = Number.parseFloat((newVol / 100).toFixed(2));
|
||||||
if (mprisVolNewer) {
|
|
||||||
mprisVolNewer = false;
|
|
||||||
autoUpdate = false;
|
|
||||||
} else {
|
|
||||||
autoUpdate = true;
|
|
||||||
player.volume = Number.parseFloat((newVol / 100).toFixed(2));
|
|
||||||
mprisVolNewer = false;
|
|
||||||
autoUpdate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
player.on('volume', (newVolume: number) => {
|
player.on('volume', (newVolume: number) => {
|
||||||
if (config.plugins.isEnabled('precise-volume')) {
|
if (config.plugins.isEnabled('precise-volume')) {
|
||||||
// With precise volume we can set the volume to the exact value.
|
// With precise volume we can set the volume to the exact value.
|
||||||
const newVol = ~~(newVolume * 100);
|
win.webContents.send('setVolume', ~~(newVolume * 100));
|
||||||
if (~~(player.volume * 100) !== newVol && !autoUpdate) {
|
|
||||||
mprisVolNewer = true;
|
|
||||||
autoUpdate = false;
|
|
||||||
win.webContents.send('setVolume', newVol);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setVolume(newVolume * 100);
|
setVolume(newVolume * 100);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,13 @@ export class LRCLib implements LyricProvider {
|
|||||||
|
|
||||||
async search({
|
async search({
|
||||||
title,
|
title,
|
||||||
|
alternativeTitle,
|
||||||
artist,
|
artist,
|
||||||
album,
|
album,
|
||||||
songDuration,
|
songDuration,
|
||||||
|
tags,
|
||||||
}: SearchSongInfo): Promise<LyricResult | null> {
|
}: SearchSongInfo): Promise<LyricResult | null> {
|
||||||
|
|
||||||
let query = new URLSearchParams({
|
let query = new URLSearchParams({
|
||||||
artist_name: artist,
|
artist_name: artist,
|
||||||
track_name: title,
|
track_name: title,
|
||||||
@ -42,7 +45,9 @@ export class LRCLib implements LyricProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
query = new URLSearchParams({ q: title });
|
// Try to search with the alternative title (original language)
|
||||||
|
const trackName = alternativeTitle || title;
|
||||||
|
query = new URLSearchParams({ q: `${trackName}` });
|
||||||
url = `${this.baseUrl}/api/search?${query.toString()}`;
|
url = `${this.baseUrl}/api/search?${query.toString()}`;
|
||||||
|
|
||||||
response = await fetch(url);
|
response = await fetch(url);
|
||||||
@ -54,6 +59,22 @@ export class LRCLib implements LyricProvider {
|
|||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
throw new Error(`Expected an array, instead got ${typeof data}`);
|
throw new Error(`Expected an array, instead got ${typeof data}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If still no results, try with the original title as fallback
|
||||||
|
if (data.length === 0 && alternativeTitle) {
|
||||||
|
query = new URLSearchParams({ q: title });
|
||||||
|
url = `${this.baseUrl}/api/search?${query.toString()}`;
|
||||||
|
|
||||||
|
response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`bad HTTPStatus(${response.statusText})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = (await response.json()) as LRCLIBSearchResponse;
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error(`Expected an array, instead got ${typeof data}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredResults = [];
|
const filteredResults = [];
|
||||||
@ -63,6 +84,7 @@ export class LRCLib implements LyricProvider {
|
|||||||
const artists = artist.split(/[&,]/g).map((i) => i.trim());
|
const artists = artist.split(/[&,]/g).map((i) => i.trim());
|
||||||
const itemArtists = artistName.split(/[&,]/g).map((i) => i.trim());
|
const itemArtists = artistName.split(/[&,]/g).map((i) => i.trim());
|
||||||
|
|
||||||
|
// Try to match using artist name first
|
||||||
const permutations = [];
|
const permutations = [];
|
||||||
for (const artistA of artists) {
|
for (const artistA of artists) {
|
||||||
for (const artistB of itemArtists) {
|
for (const artistB of itemArtists) {
|
||||||
@ -76,10 +98,40 @@ export class LRCLib implements LyricProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ratio = Math.max(
|
let ratio = Math.max(
|
||||||
...permutations.map(([x, y]) => jaroWinkler(x, y)),
|
...permutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If direct artist match is below threshold and we have tags, try matching with tags
|
||||||
|
if (ratio <= 0.9 && tags && tags.length > 0) {
|
||||||
|
// Filter out the artist from tags to avoid duplicate comparisons
|
||||||
|
const filteredTags = tags.filter(tag => tag.toLowerCase() !== artist.toLowerCase());
|
||||||
|
|
||||||
|
const tagPermutations = [];
|
||||||
|
// Compare each tag with each item artist
|
||||||
|
for (const tag of filteredTags) {
|
||||||
|
for (const itemArtist of itemArtists) {
|
||||||
|
tagPermutations.push([tag.toLowerCase(), itemArtist.toLowerCase()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare each item artist with each tag
|
||||||
|
for (const itemArtist of itemArtists) {
|
||||||
|
for (const tag of filteredTags) {
|
||||||
|
tagPermutations.push([itemArtist.toLowerCase(), tag.toLowerCase()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagPermutations.length > 0) {
|
||||||
|
const tagRatio = Math.max(
|
||||||
|
...tagPermutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use the best match ratio between direct artist match and tag match
|
||||||
|
ratio = Math.max(ratio, tagRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ratio <= 0.9) continue;
|
if (ratio <= 0.9) continue;
|
||||||
filteredResults.push(item);
|
filteredResults.push(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -174,7 +174,7 @@ export const romanizeJapanese = async (line: string) =>
|
|||||||
(await kuroshiro.get()).convert(line, {
|
(await kuroshiro.get()).convert(line, {
|
||||||
to: 'romaji',
|
to: 'romaji',
|
||||||
mode: 'spaced',
|
mode: 'spaced',
|
||||||
});
|
}) ?? '';
|
||||||
|
|
||||||
export const romanizeHangul = (line: string) =>
|
export const romanizeHangul = (line: string) =>
|
||||||
esHangulRomanize(hanja.translate(line, 'SUBSTITUTION'));
|
esHangulRomanize(hanja.translate(line, 'SUBSTITUTION'));
|
||||||
|
|||||||
@ -73,6 +73,8 @@
|
|||||||
|
|
||||||
& .text-lyrics {
|
& .text-lyrics {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
/*fix cuted lyrics-glow and romanized j at line start */
|
||||||
|
padding-left: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .text-lyrics > .romaji {
|
& .text-lyrics > .romaji {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export interface LyricResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
export type SearchSongInfo = Pick<SongInfo, 'title' | 'artist' | 'album' | 'songDuration' | 'videoId'>;
|
export type SearchSongInfo = Pick<SongInfo, 'title' | 'alternativeTitle' | 'artist' | 'album' | 'songDuration' | 'videoId' | 'tags'>;
|
||||||
|
|
||||||
export interface LyricProvider {
|
export interface LyricProvider {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@ -16,7 +16,9 @@ interface Data {
|
|||||||
progress: number;
|
progress: number;
|
||||||
status: string;
|
status: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
alternativeTitle: string;
|
||||||
url: string;
|
url: string;
|
||||||
|
tags: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createPlugin({
|
export default createPlugin({
|
||||||
@ -86,10 +88,12 @@ export default createPlugin({
|
|||||||
cover_url: songInfo.imageSrc ?? '',
|
cover_url: songInfo.imageSrc ?? '',
|
||||||
album_url: songInfo.imageSrc ?? '',
|
album_url: songInfo.imageSrc ?? '',
|
||||||
title: songInfo.title,
|
title: songInfo.title,
|
||||||
|
alternativeTitle: songInfo.alternativeTitle ?? '',
|
||||||
artists: [songInfo.artist],
|
artists: [songInfo.artist],
|
||||||
status: songInfo.isPaused ? 'stopped' : 'playing',
|
status: songInfo.isPaused ? 'stopped' : 'playing',
|
||||||
album: songInfo.album,
|
album: songInfo.album,
|
||||||
url: songInfo.url ?? '',
|
url: songInfo.url ?? '',
|
||||||
|
tags: songInfo.tags ?? [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,18 +6,39 @@ import { t } from '@/i18n';
|
|||||||
const handlePlay = (e: MouseEvent) => {
|
const handlePlay = (e: MouseEvent) => {
|
||||||
if (!(e.target instanceof HTMLElement)) return;
|
if (!(e.target instanceof HTMLElement)) return;
|
||||||
|
|
||||||
if (
|
// Player bar handler
|
||||||
e.target.closest('ytmusic-play-button-renderer') &&
|
|
||||||
!e.target.closest('ytmusic-player-page')
|
|
||||||
) {
|
|
||||||
document.body.classList.add('unobtrusive-player--did-play');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
e.target.closest('ytmusic-player-bar') &&
|
e.target.closest('ytmusic-player-bar') &&
|
||||||
!document.body.classList.contains('unobtrusive-player--auto-closing')
|
!document.body.classList.contains('unobtrusive-player--auto-closing')
|
||||||
) {
|
) {
|
||||||
document.body.classList.remove('unobtrusive-player--did-play');
|
document.body.classList.remove('unobtrusive-player--did-play');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Song play button handler
|
||||||
|
if (
|
||||||
|
e.target.closest('ytmusic-play-button-renderer') &&
|
||||||
|
!e.target.closest('ytmusic-player-page')
|
||||||
|
) {
|
||||||
|
document.body.classList.add('unobtrusive-player--did-play');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle play menu item handler
|
||||||
|
const shuffleIconPathData = (
|
||||||
|
document.querySelector('iron-iconset-svg[name="yt-sys-icons"] #shuffle')
|
||||||
|
?.firstChild as SVGElement | null
|
||||||
|
)
|
||||||
|
?.getAttribute('d')
|
||||||
|
?.substring(0, 15);
|
||||||
|
|
||||||
|
if (
|
||||||
|
e.target.closest(
|
||||||
|
`ytmusic-menu-navigation-item-renderer:has(yt-icon path[d^="${shuffleIconPathData}"])`,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
document.body.classList.add('unobtrusive-player--did-play');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -179,12 +179,12 @@ export default createPlugin({
|
|||||||
if (this.config) {
|
if (this.config) {
|
||||||
this.config.hideVideo = !showVideo;
|
this.config.hideVideo = !showVideo;
|
||||||
}
|
}
|
||||||
window.mainConfig.plugins.setOptions('video-toggle', config);
|
window.mainConfig.plugins.setOptions('video-toggle', this.config);
|
||||||
|
|
||||||
const checkbox = document.querySelector<HTMLInputElement>(
|
const checkbox = document.querySelector<HTMLInputElement>(
|
||||||
'.video-switch-button-checkbox',
|
'.video-switch-button-checkbox',
|
||||||
); // custom mode
|
); // custom mode
|
||||||
if (checkbox) checkbox.checked = !config.hideVideo;
|
if (checkbox) checkbox.checked = !this.config.hideVideo;
|
||||||
|
|
||||||
if (player) {
|
if (player) {
|
||||||
player.style.margin = showVideo ? '' : 'auto 0px';
|
player.style.margin = showVideo ? '' : 'auto 0px';
|
||||||
|
|||||||
@ -42,6 +42,7 @@ export interface SongInfo {
|
|||||||
videoId: string;
|
videoId: string;
|
||||||
playlistId?: string;
|
playlistId?: string;
|
||||||
mediaType: MediaType;
|
mediaType: MediaType;
|
||||||
|
tags?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the native image using the src
|
// Grab the native image using the src
|
||||||
@ -83,6 +84,7 @@ const handleData = async (
|
|||||||
videoId: '',
|
videoId: '',
|
||||||
playlistId: '',
|
playlistId: '',
|
||||||
mediaType: MediaType.Audio,
|
mediaType: MediaType.Audio,
|
||||||
|
tags: [],
|
||||||
} satisfies SongInfo;
|
} satisfies SongInfo;
|
||||||
|
|
||||||
const microformat = data.microformat?.microformatDataRenderer;
|
const microformat = data.microformat?.microformatDataRenderer;
|
||||||
@ -96,6 +98,7 @@ const handleData = async (
|
|||||||
songInfo.alternativeTitle = microformat.linkAlternates.find(
|
songInfo.alternativeTitle = microformat.linkAlternates.find(
|
||||||
(link) => link.title,
|
(link) => link.title,
|
||||||
)?.title;
|
)?.title;
|
||||||
|
songInfo.tags = Array.isArray(microformat.tags) ? microformat.tags : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { videoDetails } = data;
|
const { videoDetails } = data;
|
||||||
|
|||||||
Reference in New Issue
Block a user