Compare commits

...

99 Commits

Author SHA1 Message Date
advplyr e05cb0ef4d Version bump v2.16.2 2024-10-29 16:11:36 -05:00
advplyr 925c7f7dc7 Merge pull request #3566 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2024-10-29 16:04:27 -05:00
Charlie c69e97ea24 Translated using Weblate (French)
Currently translated at 95.7% (1025 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fr/
2024-10-29 22:00:15 +01:00
advplyr 5e2aebc724 Merge pull request #3565 from mikiher/handle-download-errors-2
Fix incorrect call to handleDownloadError
2024-10-29 15:55:37 -05:00
advplyr 6eba467b91 Fix:Session sync for streaming podcast episodes using incorrect duration #3560 2024-10-29 15:41:31 -05:00
mikiher 524cf5ec5b Fix incorrect call to handleDownloadError 2024-10-29 21:42:44 +02:00
advplyr 50fd659749 Version bump v2.16.1 2024-10-28 17:05:47 -05:00
advplyr 8169afb59b Merge pull request #3554 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2024-10-28 17:01:24 -05:00
SunSpring d40086fea1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1071 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2024-10-28 23:00:51 +01:00
biuklija 399c40debd Translated using Weblate (Croatian)
Currently translated at 100.0% (1071 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-28 23:00:50 +01:00
Vito0912 d986673dfd Translated using Weblate (German)
Currently translated at 99.8% (1069 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2024-10-28 23:00:50 +01:00
thehijacker f83f4d41f1 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1071 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-28 23:00:49 +01:00
Dmitry 7ed711730e Translated using Weblate (Russian)
Currently translated at 100.0% (1071 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2024-10-28 23:00:49 +01:00
Frantisek Nagy 94e2ea9df3 Translated using Weblate (Hungarian)
Currently translated at 75.6% (810 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hu/
2024-10-28 23:00:48 +01:00
Bálint Kristóf 8c8c4a15c3 Translated using Weblate (Hungarian)
Currently translated at 75.6% (810 of 1071 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hu/
2024-10-28 23:00:48 +01:00
advplyr 2a9159f106 Merge pull request #3553 from mikiher/handle-download-errors
Add proper error handing for file downloads
2024-10-28 17:00:40 -05:00
advplyr 8f113d17c2 Fix:Ensure library has all settings defined when validating settings for update #3559 2024-10-28 16:57:37 -05:00
mikiher 9084055b95 Add proper error handing for file downloads 2024-10-28 08:03:31 +02:00
advplyr fba9cce82e Version bump v2.16.0 2024-10-27 15:15:44 -05:00
advplyr 92cfb46c14 Merge pull request #3542 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2024-10-27 15:10:16 -05:00
thehijacker 449dc1a0e2 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1070 of 1070 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-26 20:34:51 +00:00
SunSpring d9c345b0f3 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1070 of 1070 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2024-10-26 20:34:50 +00:00
Ahetek 69a639f76c Translated using Weblate (Polish)
Currently translated at 75.5% (806 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/pl/
2024-10-26 20:34:50 +00:00
Mathias Franco d576efe759 Translated using Weblate (Dutch)
Currently translated at 100.0% (1067 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2024-10-26 20:34:49 +00:00
biuklija 9ba2ecbc21 Translated using Weblate (Croatian)
Currently translated at 100.0% (1067 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-26 20:34:48 +00:00
Henning 84003cd67e Translated using Weblate (German)
Currently translated at 99.5% (1062 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2024-10-26 20:34:48 +00:00
kuci-JK be8c447216 Translated using Weblate (Czech)
Currently translated at 83.5% (891 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2024-10-26 20:34:47 +00:00
SunSpring e534daf5d4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1067 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2024-10-26 20:34:47 +00:00
Mathias Franco 1fefc1af92 Translated using Weblate (Dutch)
Currently translated at 92.8% (991 of 1067 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2024-10-26 20:34:46 +00:00
thehijacker e76c4ed2a4 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1064 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-26 20:34:46 +00:00
Mathias Franco e1caf13233 Translated using Weblate (Dutch)
Currently translated at 83.7% (891 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2024-10-26 20:34:45 +00:00
Plazec a7a2fbbca8 Translated using Weblate (Czech)
Currently translated at 83.3% (887 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2024-10-26 20:34:44 +00:00
Mathias Franco 28d93d9160 Translated using Weblate (Dutch)
Currently translated at 83.0% (884 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2024-10-26 20:34:44 +00:00
gallegonovato 4e90f90c28 Translated using Weblate (Spanish)
Currently translated at 97.0% (1033 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2024-10-26 20:34:43 +00:00
Plazec 2243fdddd3 Translated using Weblate (Czech)
Currently translated at 82.8% (882 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2024-10-26 20:34:43 +00:00
biuklija 39be3a2ef9 Translated using Weblate (Croatian)
Currently translated at 100.0% (1064 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-26 20:34:42 +00:00
Austin Spencer ecc30b85bc Allow users to create ereaders (#3531)
* add create eReader permission toggle

* add english label for create EReader permission

* add ereader table to account with user specific modal

* add createEreader permission

* create api endpoint and logic for updating user eReader devices

* add translated label for createEreader permission

* handle name duplicates and remove helper func

* toast for duplicate name error caught on server

* restrict user ereader updates to devices with sole ownership

* remove label

* fix other devices logic and client socket emitter

* fix for deleting ereaders

* User create ereader endpoint validate accessibility

---------

Co-authored-by: advplyr <advplyr@protonmail.com>
2024-10-26 15:34:34 -05:00
advplyr 6905b288d2 Fix:Latest version displayed when update is available 2024-10-26 14:57:04 -05:00
advplyr 0782146682 Update:Pass mark as finished library settings to media progress update #837 2024-10-25 17:27:50 -05:00
advplyr 91aea4f754 Add:Library settings for mark as finished when time remaining or percent complete #837 2024-10-24 17:19:51 -05:00
advplyr 6ca277a21d Update:Library settings tab settings in 2 columns and cleanup 2024-10-23 17:11:41 -05:00
advplyr c47c75aefe Update:More strings localized #3544 2024-10-22 17:24:31 -05:00
advplyr 9896e4381b Update:Setup variables to control when a media item is marked as finished. By time remaining or progress percentage #837 2024-10-21 17:48:02 -05:00
advplyr 953ffe889e Update:Book series embeds in grouping meta tag as semicolon deliminated, book meta tag parser falls back to using grouping tag for series if set #3473 2024-10-20 16:58:13 -05:00
advplyr 72e59e77a7 Merge pull request #3536 from nichwall/migration_indexes
Migration indexes
2024-10-19 15:51:12 -05:00
advplyr 35e2681ea9 Update index creation migration to be idempotent 2024-10-19 15:45:14 -05:00
Nicholas Wallace 84012d9090 Fix: podcast episode index name 2024-10-19 11:38:34 -07:00
Nicholas Wallace e8a1ea3b54 Fix: table naming 2024-10-19 11:20:29 -07:00
Nicholas Wallace ea6882d9ab Update changelog 2024-10-19 11:20:22 -07:00
Nicholas Wallace 1fa80e31d1 Add: migrations for authors, series, and podcast episodes 2024-10-19 10:40:17 -07:00
advplyr d80752cc9d Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2024-10-18 16:25:12 -05:00
advplyr b764e848c7 Version bump v2.15.1 2024-10-18 16:25:07 -05:00
advplyr b037c4e8a3 Merge pull request #3532 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2024-10-18 16:23:32 -05:00
thehijacker 6ba2360790 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1064 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-18 23:10:42 +02:00
SunSpring ca4eb507f0 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1064 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2024-10-18 23:10:41 +02:00
biuklija 965b094470 Translated using Weblate (Croatian)
Currently translated at 99.9% (1063 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-18 23:10:41 +02:00
gallegonovato 0fe313ecfd Translated using Weblate (Spanish)
Currently translated at 96.8% (1031 of 1064 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2024-10-18 23:10:40 +02:00
SunSpring 35a2f8d44f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2024-10-18 23:10:40 +02:00
mikiher 50797879d5 Add a REINDEX NOCASE v2.15.1 migration and update v2.15.0 migration (#3533)
* Add REINDEX NOCASE migration and update v2.15.0 migration

* Update v2.15.0 migration test

* Fix typo
2024-10-18 16:10:29 -05:00
Nicholas W 9327331ee9 Localization updates for 2.15.0 (#3520)
* Add: episode edit dropdowns

* Update: lazy episode table and row

* Various string updates

* Batch quick match strings

* Author card strings

* Update translation key for quick match episodes confirm

---------

Co-authored-by: advplyr <advplyr@protonmail.com>
2024-10-17 17:03:08 -05:00
advplyr 1c15007e32 Merge pull request #3529 from asoluter/patch-1
Fix "Extract Cover Error" for files with multiple embedded covers
2024-10-17 16:44:58 -05:00
advplyr 2151ffa114 Merge pull request #3530 from mikiher/subdirectory-fixes-2
Add server proxies for all server paths
2024-10-17 16:00:48 -05:00
mikiher 49ed208a54 Add dev proxies for all server path 2024-10-17 11:25:57 +03:00
Ihor Sofiichenko d668462529 Fix Extract Cover Error for files with multiple embedded covers 2024-10-17 00:27:21 -07:00
advplyr f2102a0a23 Merge pull request #3512 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2024-10-16 17:42:46 -05:00
biuklija 5efc6b82c1 Translated using Weblate (Croatian)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-17 00:42:17 +02:00
thehijacker 1e4e9768da Translated using Weblate (Slovenian)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-17 00:42:17 +02:00
Daniel Schosser cc5109c305 Translated using Weblate (German)
Currently translated at 98.8% (1011 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2024-10-17 00:42:16 +02:00
Mathias Franco e858d6a1d5 Translated using Weblate (Dutch)
Currently translated at 68.7% (703 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2024-10-17 00:42:15 +02:00
biuklija b4cd5d2862 Translated using Weblate (Croatian)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2024-10-17 00:42:14 +02:00
DiamondtipDR 0633a44cfb Translated using Weblate (Spanish)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2024-10-17 00:42:13 +02:00
Vito0912 5748126b83 Translated using Weblate (German)
Currently translated at 97.8% (1001 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2024-10-17 00:42:12 +02:00
thehijacker 06375743a3 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2024-10-17 00:42:12 +02:00
Ahetek 2a41c186aa Translated using Weblate (Polish)
Currently translated at 77.6% (794 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/pl/
2024-10-17 00:42:11 +02:00
burghy86 af51b7254c Translated using Weblate (Italian)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/it/
2024-10-17 00:42:11 +02:00
Charlie f63dfd769f Translated using Weblate (French)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fr/
2024-10-17 00:42:10 +02:00
apineiro97 a1512f3174 Translated using Weblate (Spanish)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2024-10-17 00:42:09 +02:00
gallegonovato 245751e2ce Translated using Weblate (Spanish)
Currently translated at 100.0% (1023 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2024-10-17 00:42:09 +02:00
Alexander Künzel 37001d9425 Translated using Weblate (German)
Currently translated at 97.0% (993 of 1023 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2024-10-17 00:42:08 +02:00
advplyr 9d1f51c6ba Add in /dev proxy for development 2024-10-16 17:42:00 -05:00
advplyr cb234fe1fc Merge pull request #3521 from mikiher/subdirectory-fixes
Fixes and cleanup for subdirectory serving support
2024-10-15 16:55:54 -05:00
advplyr cb85e0255b Fix share URLs on dev 2024-10-15 16:52:04 -05:00
advplyr 61b4cfdab7 Merge pull request #3518 from glorenzen/fix-decade-filter
Fix and simplify filter logic for publishedDecades
2024-10-15 16:19:36 -05:00
advplyr d2c405c126 Fix decade filter and query by casting publishedYear to Int 2024-10-15 16:12:56 -05:00
mikiher cbca560f92 server.js: add base path to all non-base-path requests 2024-10-15 06:40:14 +03:00
mikiher 2d7b63b4cf Add base path to socket.io connections on client and server 2024-10-15 05:50:23 +03:00
Greg Lorenzen 217038b085 Fix and simplify filter logic for publishedDecades 2024-10-14 20:58:09 +00:00
advplyr 13dd4edd6a Fix:Ignore dot files in migrations folder #3510 2024-10-14 14:46:55 -05:00
advplyr a7288b4fbf Merge pull request #3514 from koralowiec/chore/docs-nginx-client-max-body-size
chore(docs): add client_max_body_size parameter in nginx config
2024-10-14 13:04:35 -05:00
koralowiec 3020e8104e chore(docs): change indentation in nginx config example 2024-10-14 17:22:39 +00:00
koralowiec 8fdeeaaf38 chore(docs): add client_max_body_size in nginx example 2024-10-14 17:20:08 +00:00
mikiher 42616b59de Cleanup: remove explicit localhost:3333 and remove unnessesary if(dev) blocks 2024-10-14 13:30:17 +03:00
mikiher bf16681bea Merge branch 'subdirectory-fixes' of https://github.com/mikiher/audiobookshelf into subdirectory-fixes 2024-10-14 13:19:30 +03:00
mikiher 027190b5a4 Merge branch 'advplyr:master' into subdirectory-fixes 2024-10-14 13:18:04 +03:00
mikiher 241c02be30 nuxt.config.js: more cleanup and additional proxies 2024-10-14 13:12:10 +03:00
advplyr dd87268848 Merge pull request #3508 from mikiher/fix-share-player-chapters
Fix next/previous chapter behavior on public share player
2024-10-13 14:29:57 -05:00
mikiher f2ac24e623 Fix next/previous chapter behavior on public share player 2024-10-13 10:56:38 +03:00
mikiher 99ffd3050c Cleanup: Define routerBasePath constant in nuxt.config.js 2024-10-12 11:46:44 +03:00
mikiher 69dd82d329 Remove unneeded /dev routing 2024-10-12 11:18:49 +03:00
81 changed files with 2191 additions and 451 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
<p class="text-xs text-gray-300 italic">{{ Source }}</p> <p class="text-xs text-gray-300 italic">{{ Source }}</p>
</div> </div>
<a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ $config.version }}</a> <a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ versionData.latestVersion }}</a>
</div> </div>
</div> </div>
</template> </template>
@@ -167,7 +167,7 @@ export default {
}, },
podcastAuthor() { podcastAuthor() {
if (!this.isPodcast) return null if (!this.isPodcast) return null
return this.mediaMetadata.author || 'Unknown' return this.mediaMetadata.author || this.$strings.LabelUnknown
}, },
hasNextItemInQueue() { hasNextItemInQueue() {
return this.currentPlayerQueueIndex < this.playerQueueItems.length - 1 return this.currentPlayerQueueIndex < this.playerQueueItems.length - 1
@@ -251,7 +251,7 @@ export default {
sleepTimerEnd() { sleepTimerEnd() {
this.clearSleepTimer() this.clearSleepTimer()
this.playerHandler.pause() this.playerHandler.pause()
this.$toast.info('Sleep Timer Done.. zZzzZz') this.$toast.info(this.$strings.ToastSleepTimerDone)
}, },
cancelSleepTimer() { cancelSleepTimer() {
this.showSleepTimerModal = false this.showSleepTimerModal = false
@@ -525,7 +525,7 @@ export default {
}, },
showFailedProgressSyncs() { showFailedProgressSyncs() {
if (!isNaN(this.syncFailedToast)) this.$toast.dismiss(this.syncFailedToast) if (!isNaN(this.syncFailedToast)) this.$toast.dismiss(this.syncFailedToast)
this.syncFailedToast = this.$toast('Progress is not being synced. Restart playback', { timeout: false, type: 'error' }) this.syncFailedToast = this.$toast(this.$strings.ToastProgressIsNotBeingSynced, { timeout: false, type: 'error' })
}, },
sessionClosedEvent(sessionId) { sessionClosedEvent(sessionId) {
if (this.playerHandler.currentSessionId === sessionId) { if (this.playerHandler.currentSessionId === sessionId) {
+7 -4
View File
@@ -125,12 +125,15 @@ export default {
return null return null
}) })
if (!response) { if (!response) {
this.$toast.error(`Author ${this.name} not found`) this.$toast.error(this.$getString('ToastAuthorNotFound', [this.name]))
} else if (response.updated) { } else if (response.updated) {
if (response.author.imagePath) this.$toast.success(`Author ${response.author.name} was updated`) if (response.author.imagePath) {
else this.$toast.success(`Author ${response.author.name} was updated (no image found)`) this.$toast.success(this.$strings.ToastAuthorUpdateSuccess)
} else {
this.$toast.success(this.$strings.ToastAuthorUpdateSuccessNoImageFound)
}
} else { } else {
this.$toast.info(`No updates were made for Author ${response.author.name}`) this.$toast.info(this.$strings.ToastNoUpdatesNecessary)
} }
this.searching = false this.searching = false
}, },
+1 -5
View File
@@ -56,11 +56,7 @@ export default {
}, },
imgSrc() { imgSrc() {
if (!this.imagePath) return null if (!this.imagePath) return null
if (process.env.NODE_ENV !== 'production') { return `${this.$config.routerBasePath}/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
// Testing
return `http://localhost:3333${this.$config.routerBasePath}/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
}
return `/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}`
} }
}, },
methods: { methods: {
+13 -2
View File
@@ -69,6 +69,15 @@
</div> </div>
</div> </div>
<div class="flex items-center my-2 max-w-md">
<div class="w-1/2">
<p id="ereader-permissions-toggle">{{ $strings.LabelPermissionsCreateEreader }}</p>
</div>
<div class="w-1/2">
<ui-toggle-switch labeledBy="ereader-permissions-toggle" v-model="newUser.permissions.createEreader" />
</div>
</div>
<div class="flex items-center my-2 max-w-md"> <div class="flex items-center my-2 max-w-md">
<div class="w-1/2"> <div class="w-1/2">
<p id="explicit-content-permissions-toggle">{{ $strings.LabelPermissionsAccessExplicitContent }}</p> <p id="explicit-content-permissions-toggle">{{ $strings.LabelPermissionsAccessExplicitContent }}</p>
@@ -354,7 +363,8 @@ export default {
accessExplicitContent: type === 'admin', accessExplicitContent: type === 'admin',
accessAllLibraries: true, accessAllLibraries: true,
accessAllTags: true, accessAllTags: true,
selectedTagsNotAccessible: false selectedTagsNotAccessible: false,
createEreader: type === 'admin'
} }
}, },
init() { init() {
@@ -387,7 +397,8 @@ export default {
accessAllLibraries: true, accessAllLibraries: true,
accessAllTags: true, accessAllTags: true,
accessExplicitContent: false, accessExplicitContent: false,
selectedTagsNotAccessible: false selectedTagsNotAccessible: false,
createEreader: false
}, },
librariesAccessible: [], librariesAccessible: [],
itemTagsSelected: [] itemTagsSelected: []
@@ -116,10 +116,10 @@ export default {
libraryItemIds: this.selectedBookIds libraryItemIds: this.selectedBookIds
}) })
.then(() => { .then(() => {
this.$toast.info('Batch quick match of ' + this.selectedBookIds.length + ' books started!') this.$toast.info(this.$getString('ToastBatchQuickMatchStarted', [this.selectedBookIds.length]))
}) })
.catch((error) => { .catch((error) => {
this.$toast.error('Batch quick match failed') this.$toast.error(this.$strings.ToastBatchQuickMatchFailed)
console.error('Failed to batch quick match', error) console.error('Failed to batch quick match', error)
}) })
.finally(() => { .finally(() => {
+2 -2
View File
@@ -112,11 +112,11 @@ export default {
return this.$store.state.user.user return this.$store.state.user.user
}, },
demoShareUrl() { demoShareUrl() {
return `${window.origin}/share/${this.newShareSlug}` return `${window.origin}${this.$config.routerBasePath}/share/${this.newShareSlug}`
}, },
currentShareUrl() { currentShareUrl() {
if (!this.currentShare) return '' if (!this.currentShare) return ''
return `${window.origin}/share/${this.currentShare.slug}` return `${window.origin}${this.$config.routerBasePath}/share/${this.currentShare.slug}`
}, },
currentShareTimeRemaining() { currentShareTimeRemaining() {
if (!this.currentShare) return 'Error' if (!this.currentShare) return 'Error'
@@ -0,0 +1,188 @@
<template>
<modals-modal ref="modal" v-model="show" name="ereader-device-edit" :width="800" :height="'unset'" :processing="processing">
<template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="text-3xl text-white truncate">{{ title }}</p>
</div>
</template>
<form @submit.prevent="submitForm">
<div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300">
<div class="w-full px-3 py-5 md:p-12">
<div class="flex items-center -mx-1 mb-4">
<div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="ereaderNameInput" v-model="newDevice.name" :disabled="processing" :label="$strings.LabelName" />
</div>
<div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="ereaderEmailInput" v-model="newDevice.email" :disabled="processing" :label="$strings.LabelEmail" />
</div>
</div>
<div class="flex items-center pt-4">
<div class="flex-grow" />
<ui-btn color="success" type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
</div>
</div>
</div>
</form>
</modals-modal>
</template>
<script>
export default {
props: {
value: Boolean,
existingDevices: {
type: Array,
default: () => []
},
ereaderDevice: {
type: Object,
default: () => null
}
},
data() {
return {
processing: false,
newDevice: {
name: '',
email: '',
availabilityOption: 'adminAndUp',
users: []
}
}
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.init()
}
}
}
},
computed: {
show: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
user() {
return this.$store.state.user.user
},
title() {
return !this.ereaderDevice ? 'Create Device' : 'Update Device'
}
},
methods: {
submitForm() {
this.$refs.ereaderNameInput.blur()
this.$refs.ereaderEmailInput.blur()
if (!this.newDevice.name?.trim() || !this.newDevice.email?.trim()) {
this.$toast.error(this.$strings.ToastNameEmailRequired)
return
}
this.newDevice.name = this.newDevice.name.trim()
this.newDevice.email = this.newDevice.email.trim()
// Only catches duplicate names for the current user
// Duplicates with other users caught on server side
if (!this.ereaderDevice) {
if (this.existingDevices.some((d) => d.name === this.newDevice.name)) {
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
return
}
this.submitCreate()
} else {
if (this.ereaderDevice.name !== this.newDevice.name && this.existingDevices.some((d) => d.name === this.newDevice.name)) {
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
return
}
this.submitUpdate()
}
},
submitUpdate() {
this.processing = true
const existingDevicesWithoutThisOne = this.existingDevices.filter((d) => d.name !== this.ereaderDevice.name)
const payload = {
ereaderDevices: [
...existingDevicesWithoutThisOne,
{
...this.newDevice
}
]
}
this.$axios
.$post(`/api/me/ereader-devices`, payload)
.then((data) => {
this.$emit('update', data.ereaderDevices)
this.show = false
})
.catch((error) => {
console.error('Failed to update device', error)
if (error.response?.data?.toLowerCase().includes('duplicate')) {
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
} else {
this.$toast.error(this.$strings.ToastDeviceAddFailed)
}
})
.finally(() => {
this.processing = false
})
},
submitCreate() {
this.processing = true
const payload = {
ereaderDevices: [
...this.existingDevices,
{
...this.newDevice
}
]
}
this.$axios
.$post('/api/me/ereader-devices', payload)
.then((data) => {
this.$emit('update', data.ereaderDevices || [])
this.show = false
})
.catch((error) => {
console.error('Failed to add device', error)
if (error.response?.data?.toLowerCase().includes('duplicate')) {
this.$toast.error(this.$strings.ToastDeviceNameAlreadyExists)
} else {
this.$toast.error(this.$strings.ToastDeviceAddFailed)
}
})
.finally(() => {
this.processing = false
})
},
init() {
if (this.ereaderDevice) {
this.newDevice.name = this.ereaderDevice.name
this.newDevice.email = this.ereaderDevice.email
this.newDevice.availabilityOption = this.ereaderDevice.availabilityOption || 'specificUsers'
this.newDevice.users = this.ereaderDevice.users || [this.user.id]
} else {
this.newDevice.name = ''
this.newDevice.email = ''
this.newDevice.availabilityOption = 'specificUsers'
this.newDevice.users = [this.user.id]
}
}
},
mounted() {}
}
</script>
@@ -6,7 +6,7 @@
<ui-text-input-with-label ref="maxEpisodesInput" v-model="maxEpisodesToDownload" :disabled="checkingNewEpisodes" type="number" :label="$strings.LabelLimit" class="w-16 mr-2" input-class="h-10"> <ui-text-input-with-label ref="maxEpisodesInput" v-model="maxEpisodesToDownload" :disabled="checkingNewEpisodes" type="number" :label="$strings.LabelLimit" class="w-16 mr-2" input-class="h-10">
<div class="flex -mb-0.5"> <div class="flex -mb-0.5">
<p class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': checkingNewEpisodes }">{{ $strings.LabelLimit }}</p> <p class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': checkingNewEpisodes }">{{ $strings.LabelLimit }}</p>
<ui-tooltip direction="top" text="Max # of episodes to download. Use 0 for unlimited."> <ui-tooltip direction="top" :text="$strings.LabelMaxEpisodesToDownload">
<span class="material-symbols text-base">info</span> <span class="material-symbols text-base">info</span>
</ui-tooltip> </ui-tooltip>
</div> </div>
@@ -99,7 +99,7 @@ export default {
if (this.maxEpisodesToDownload < 0) { if (this.maxEpisodesToDownload < 0) {
this.maxEpisodesToDownload = 3 this.maxEpisodesToDownload = 3
this.$toast.error('Invalid max episodes to download') this.$toast.error(this.$strings.ToastInvalidMaxEpisodesToDownload)
return return
} }
@@ -120,9 +120,9 @@ export default {
.then((response) => { .then((response) => {
if (response.episodes && response.episodes.length) { if (response.episodes && response.episodes.length) {
console.log('New episodes', response.episodes.length) console.log('New episodes', response.episodes.length)
this.$toast.success(`${response.episodes.length} new episodes found!`) this.$toast.success(this.$getString('ToastNewEpisodesFound', [response.episodes.length]))
} else { } else {
this.$toast.info('No new episodes found') this.$toast.info(this.$strings.ToastNoNewEpisodesFound)
} }
this.checkingNewEpisodes = false this.checkingNewEpisodes = false
}) })
+17 -17
View File
@@ -60,7 +60,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.title" :disabled="!selectedMatchUsage.title" :label="$strings.LabelTitle" /> <ui-text-input-with-label v-model="selectedMatch.title" :disabled="!selectedMatchUsage.title" :label="$strings.LabelTitle" />
<p v-if="mediaMetadata.title" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.title" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('title', mediaMetadata.title)">{{ mediaMetadata.title || '' }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('title', mediaMetadata.title)">{{ mediaMetadata.title || '' }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -69,7 +69,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.subtitle" :disabled="!selectedMatchUsage.subtitle" :label="$strings.LabelSubtitle" /> <ui-text-input-with-label v-model="selectedMatch.subtitle" :disabled="!selectedMatchUsage.subtitle" :label="$strings.LabelSubtitle" />
<p v-if="mediaMetadata.subtitle" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.subtitle" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('subtitle', mediaMetadata.subtitle)">{{ mediaMetadata.subtitle }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('subtitle', mediaMetadata.subtitle)">{{ mediaMetadata.subtitle }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -78,7 +78,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.author" :disabled="!selectedMatchUsage.author" :label="$strings.LabelAuthor" /> <ui-text-input-with-label v-model="selectedMatch.author" :disabled="!selectedMatchUsage.author" :label="$strings.LabelAuthor" />
<p v-if="mediaMetadata.authorName" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.authorName" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('author', mediaMetadata.authorName)">{{ mediaMetadata.authorName }}</a> {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('author', mediaMetadata.authorName)">{{ mediaMetadata.authorName }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -87,7 +87,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-multi-select v-model="selectedMatch.narrator" :items="narrators" :disabled="!selectedMatchUsage.narrator" :label="$strings.LabelNarrators" /> <ui-multi-select v-model="selectedMatch.narrator" :items="narrators" :disabled="!selectedMatchUsage.narrator" :label="$strings.LabelNarrators" />
<p v-if="mediaMetadata.narratorName" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.narratorName" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('narrator', mediaMetadata.narrators)">{{ mediaMetadata.narratorName }}</a> {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('narrator', mediaMetadata.narrators)">{{ mediaMetadata.narratorName }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -96,7 +96,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-textarea-with-label v-model="selectedMatch.description" :rows="3" :disabled="!selectedMatchUsage.description" :label="$strings.LabelDescription" /> <ui-textarea-with-label v-model="selectedMatch.description" :rows="3" :disabled="!selectedMatchUsage.description" :label="$strings.LabelDescription" />
<p v-if="mediaMetadata.description" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.description" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('description', mediaMetadata.description)">{{ mediaMetadata.description.substr(0, 100) + (mediaMetadata.description.length > 100 ? '...' : '') }}</a> {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('description', mediaMetadata.description)">{{ mediaMetadata.description.substr(0, 100) + (mediaMetadata.description.length > 100 ? '...' : '') }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -105,7 +105,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.publisher" :disabled="!selectedMatchUsage.publisher" :label="$strings.LabelPublisher" /> <ui-text-input-with-label v-model="selectedMatch.publisher" :disabled="!selectedMatchUsage.publisher" :label="$strings.LabelPublisher" />
<p v-if="mediaMetadata.publisher" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.publisher" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('publisher', mediaMetadata.publisher)">{{ mediaMetadata.publisher }}</a> {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('publisher', mediaMetadata.publisher)">{{ mediaMetadata.publisher }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -114,7 +114,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.publishedYear" :disabled="!selectedMatchUsage.publishedYear" :label="$strings.LabelPublishYear" /> <ui-text-input-with-label v-model="selectedMatch.publishedYear" :disabled="!selectedMatchUsage.publishedYear" :label="$strings.LabelPublishYear" />
<p v-if="mediaMetadata.publishedYear" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.publishedYear" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('publishedYear', mediaMetadata.publishedYear)">{{ mediaMetadata.publishedYear }}</a> {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('publishedYear', mediaMetadata.publishedYear)">{{ mediaMetadata.publishedYear }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -124,7 +124,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<widgets-series-input-widget v-model="selectedMatch.series" :disabled="!selectedMatchUsage.series" /> <widgets-series-input-widget v-model="selectedMatch.series" :disabled="!selectedMatchUsage.series" />
<p v-if="mediaMetadata.seriesName" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.seriesName" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('series', mediaMetadata.series)">{{ mediaMetadata.seriesName }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('series', mediaMetadata.series)">{{ mediaMetadata.seriesName }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -133,7 +133,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-multi-select v-model="selectedMatch.genres" :items="genres" :disabled="!selectedMatchUsage.genres" :label="$strings.LabelGenres" /> <ui-multi-select v-model="selectedMatch.genres" :items="genres" :disabled="!selectedMatchUsage.genres" :label="$strings.LabelGenres" />
<p v-if="mediaMetadata.genres?.length" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.genres?.length" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('genres', mediaMetadata.genres)">{{ mediaMetadata.genres.join(', ') }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('genres', mediaMetadata.genres)">{{ mediaMetadata.genres.join(', ') }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -142,7 +142,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-multi-select v-model="selectedMatch.tags" :items="tags" :disabled="!selectedMatchUsage.tags" :label="$strings.LabelTags" /> <ui-multi-select v-model="selectedMatch.tags" :items="tags" :disabled="!selectedMatchUsage.tags" :label="$strings.LabelTags" />
<p v-if="media.tags?.length" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="media.tags?.length" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('tags', media.tags)">{{ media.tags.join(', ') }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('tags', media.tags)">{{ media.tags.join(', ') }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -151,7 +151,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.language" :disabled="!selectedMatchUsage.language" :label="$strings.LabelLanguage" /> <ui-text-input-with-label v-model="selectedMatch.language" :disabled="!selectedMatchUsage.language" :label="$strings.LabelLanguage" />
<p v-if="mediaMetadata.language" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.language" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('language', mediaMetadata.language)">{{ mediaMetadata.language }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('language', mediaMetadata.language)">{{ mediaMetadata.language }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -160,7 +160,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" /> <ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" />
<p v-if="mediaMetadata.isbn" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.isbn" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('isbn', mediaMetadata.isbn)">{{ mediaMetadata.isbn }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('isbn', mediaMetadata.isbn)">{{ mediaMetadata.isbn }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -169,7 +169,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.asin" :disabled="!selectedMatchUsage.asin" label="ASIN" /> <ui-text-input-with-label v-model="selectedMatch.asin" :disabled="!selectedMatchUsage.asin" label="ASIN" />
<p v-if="mediaMetadata.asin" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.asin" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('asin', mediaMetadata.asin)">{{ mediaMetadata.asin }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('asin', mediaMetadata.asin)">{{ mediaMetadata.asin }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -179,7 +179,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.itunesId" type="number" :disabled="!selectedMatchUsage.itunesId" label="iTunes ID" /> <ui-text-input-with-label v-model="selectedMatch.itunesId" type="number" :disabled="!selectedMatchUsage.itunesId" label="iTunes ID" />
<p v-if="mediaMetadata.itunesId" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.itunesId" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('itunesId', mediaMetadata.itunesId)">{{ mediaMetadata.itunesId }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('itunesId', mediaMetadata.itunesId)">{{ mediaMetadata.itunesId }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -188,7 +188,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.feedUrl" :disabled="!selectedMatchUsage.feedUrl" label="RSS Feed URL" /> <ui-text-input-with-label v-model="selectedMatch.feedUrl" :disabled="!selectedMatchUsage.feedUrl" label="RSS Feed URL" />
<p v-if="mediaMetadata.feedUrl" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.feedUrl" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('feedUrl', mediaMetadata.feedUrl)">{{ mediaMetadata.feedUrl }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('feedUrl', mediaMetadata.feedUrl)">{{ mediaMetadata.feedUrl }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -197,7 +197,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.itunesPageUrl" :disabled="!selectedMatchUsage.itunesPageUrl" label="iTunes Page URL" /> <ui-text-input-with-label v-model="selectedMatch.itunesPageUrl" :disabled="!selectedMatchUsage.itunesPageUrl" label="iTunes Page URL" />
<p v-if="mediaMetadata.itunesPageUrl" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.itunesPageUrl" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('itunesPageUrl', mediaMetadata.itunesPageUrl)">{{ mediaMetadata.itunesPageUrl }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('itunesPageUrl', mediaMetadata.itunesPageUrl)">{{ mediaMetadata.itunesPageUrl }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -206,7 +206,7 @@
<div class="flex-grow ml-4"> <div class="flex-grow ml-4">
<ui-text-input-with-label v-model="selectedMatch.releaseDate" :disabled="!selectedMatchUsage.releaseDate" :label="$strings.LabelReleaseDate" /> <ui-text-input-with-label v-model="selectedMatch.releaseDate" :disabled="!selectedMatchUsage.releaseDate" :label="$strings.LabelReleaseDate" />
<p v-if="mediaMetadata.releaseDate" class="text-xs ml-1 text-white text-opacity-60"> <p v-if="mediaMetadata.releaseDate" class="text-xs ml-1 text-white text-opacity-60">
{{ $strings.LabelCurrently }} <a title="Click to use current value" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('releaseDate', mediaMetadata.releaseDate)">{{ mediaMetadata.releaseDate }}</a> {{ $strings.LabelCurrently }} <a :title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('releaseDate', mediaMetadata.releaseDate)">{{ mediaMetadata.releaseDate }}</a>
</p> </p>
</div> </div>
</div> </div>
@@ -2,28 +2,28 @@
<div class="w-full h-full relative"> <div class="w-full h-full relative">
<div id="scheduleWrapper" class="w-full overflow-y-auto px-2 py-4 md:px-6 md:py-6"> <div id="scheduleWrapper" class="w-full overflow-y-auto px-2 py-4 md:px-6 md:py-6">
<template v-if="!feedUrl"> <template v-if="!feedUrl">
<widgets-alert type="warning" class="text-base mb-4">No RSS feed URL is set for this podcast</widgets-alert> <widgets-alert type="warning" class="text-base mb-4">{{ $strings.ToastPodcastNoRssFeed }}</widgets-alert>
</template> </template>
<template v-if="feedUrl || autoDownloadEpisodes"> <template v-if="feedUrl || autoDownloadEpisodes">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<p class="text-base md:text-xl font-semibold">Schedule Automatic Episode Downloads</p> <p class="text-base md:text-xl font-semibold">{{ $strings.HeaderScheduleEpisodeDownloads }}</p>
<ui-checkbox v-model="enableAutoDownloadEpisodes" label="Enable" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" /> <ui-checkbox v-model="enableAutoDownloadEpisodes" :label="$strings.LabelEnable" medium checkbox-bg="bg" label-class="pl-2 text-base md:text-lg" />
</div> </div>
<div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2"> <div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2">
<ui-text-input ref="maxEpisodesInput" type="number" v-model="newMaxEpisodesToKeep" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updatedMaxEpisodesToKeep" /> <ui-text-input ref="maxEpisodesInput" type="number" v-model="newMaxEpisodesToKeep" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updatedMaxEpisodesToKeep" />
<ui-tooltip text="Value of 0 sets no max limit. After a new episode is auto-downloaded this will delete the oldest episode if you have more than X episodes. <br>This will only delete 1 episode per new download."> <ui-tooltip :text="$strings.LabelMaxEpisodesToKeepHelp">
<p class="pl-4 text-base"> <p class="pl-4 text-base">
Max episodes to keep {{ $strings.LabelMaxEpisodesToKeep }}
<span class="material-symbols icon-text">info</span> <span class="material-symbols icon-text">info</span>
</p> </p>
</ui-tooltip> </ui-tooltip>
</div> </div>
<div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2"> <div v-if="enableAutoDownloadEpisodes" class="flex items-center py-2">
<ui-text-input ref="maxEpisodesToDownloadInput" type="number" v-model="newMaxNewEpisodesToDownload" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updateMaxNewEpisodesToDownload" /> <ui-text-input ref="maxEpisodesToDownloadInput" type="number" v-model="newMaxNewEpisodesToDownload" no-spinner :padding-x="1" text-center class="w-10 text-base" @change="updateMaxNewEpisodesToDownload" />
<ui-tooltip text="Value of 0 sets no max limit. When checking for new episodes this is the max number of episodes that will be downloaded."> <ui-tooltip :text="$strings.LabelUseZeroForUnlimited">
<p class="pl-4 text-base"> <p class="pl-4 text-base">
Max new episodes to download per check {{ $strings.LabelMaxEpisodesToDownloadPerCheck }}
<span class="material-symbols icon-text">info</span> <span class="material-symbols icon-text">info</span>
</p> </p>
</ui-tooltip> </ui-tooltip>
@@ -36,7 +36,7 @@
<div v-if="feedUrl || autoDownloadEpisodes" class="absolute bottom-0 left-0 w-full py-2 md:py-4 bg-bg border-t border-white border-opacity-5"> <div v-if="feedUrl || autoDownloadEpisodes" class="absolute bottom-0 left-0 w-full py-2 md:py-4 bg-bg border-t border-white border-opacity-5">
<div class="flex items-center px-2 md:px-4"> <div class="flex items-center px-2 md:px-4">
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn @click="save" :disabled="!isUpdated" :color="isUpdated ? 'success' : 'primary'" class="mx-2">{{ isUpdated ? 'Save' : 'No update necessary' }}</ui-btn> <ui-btn @click="save" :disabled="!isUpdated" :color="isUpdated ? 'success' : 'primary'" class="mx-2">{{ isUpdated ? $strings.ButtonSave : $strings.MessageNoUpdatesWereNecessary }}</ui-btn>
</div> </div>
</div> </div>
</div> </div>
@@ -111,7 +111,6 @@ export default {
}, },
updateLibrary(library) { updateLibrary(library) {
this.mapLibraryToCopy(library) this.mapLibraryToCopy(library)
console.log('Updated library', this.libraryCopy)
}, },
getNewLibraryData() { getNewLibraryData() {
return { return {
@@ -128,7 +127,9 @@ export default {
autoScanCronExpression: null, autoScanCronExpression: null,
hideSingleBookSeries: false, hideSingleBookSeries: false,
onlyShowLaterBooksInContinueSeries: false, onlyShowLaterBooksInContinueSeries: false,
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata'] metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata'],
markAsFinishedPercentComplete: null,
markAsFinishedTimeRemaining: 10
} }
} }
}, },
@@ -160,7 +161,7 @@ export default {
return false return false
} }
if (!this.libraryCopy.folders.length) { if (!this.libraryCopy.folders.length) {
this.$toast.error('Library must have at least 1 path') this.$toast.error(this.$strings.ToastMustHaveAtLeastOnePath)
return false return false
} }
@@ -236,7 +237,6 @@ export default {
this.show = false this.show = false
this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name])) this.$toast.success(this.$getString('ToastLibraryCreateSuccess', [res.name]))
if (!this.$store.state.libraries.currentLibraryId) { if (!this.$store.state.libraries.currentLibraryId) {
console.log('Setting initially library id', res.id)
// First library added // First library added
this.$store.dispatch('libraries/fetch', res.id) this.$store.dispatch('libraries/fetch', res.id)
} }
@@ -1,78 +1,94 @@
<template> <template>
<div class="w-full h-full px-1 md:px-4 py-1 mb-4"> <div class="w-full h-full px-1 md:px-4 py-1 mb-4">
<div class="flex items-center py-3"> <div class="flex flex-wrap">
<ui-toggle-switch v-model="useSquareBookCovers" @input="formUpdated" /> <div class="flex items-center p-2 w-full md:w-1/2">
<ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp"> <ui-toggle-switch v-model="useSquareBookCovers" size="sm" @input="formUpdated" />
<p class="pl-4 text-base"> <ui-tooltip :text="$strings.LabelSettingsSquareBookCoversHelp">
{{ $strings.LabelSettingsSquareBookCovers }} <p class="pl-4 text-sm">
<span class="material-symbols icon-text text-sm">info</span> {{ $strings.LabelSettingsSquareBookCovers }}
</p>
</ui-tooltip>
</div>
<div class="py-3">
<div class="flex items-center">
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" @input="formUpdated" />
<ui-toggle-switch v-else disabled :value="false" />
<p class="pl-4 text-base">{{ $strings.LabelSettingsEnableWatcherForLibrary }}</p>
</div>
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
</div>
<div v-if="isBookLibrary" class="flex items-center py-3">
<ui-toggle-switch v-model="audiobooksOnly" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsAudiobooksOnlyHelp">
<p class="pl-4 text-base">
{{ $strings.LabelSettingsAudiobooksOnly }}
<span class="material-symbols icon-text text-sm">info</span>
</p>
</ui-tooltip>
</div>
<div v-if="isBookLibrary" class="py-3">
<div class="flex items-center">
<ui-toggle-switch v-model="skipMatchingMediaWithAsin" @input="formUpdated" />
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</p>
</div>
</div>
<div v-if="isBookLibrary" class="py-3">
<div class="flex items-center">
<ui-toggle-switch v-model="skipMatchingMediaWithIsbn" @input="formUpdated" />
<p class="pl-4 text-base">{{ $strings.LabelSettingsSkipMatchingBooksWithISBN }}</p>
</div>
</div>
<div v-if="isBookLibrary" class="py-3">
<div class="flex items-center">
<ui-toggle-switch v-model="hideSingleBookSeries" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsHideSingleBookSeriesHelp">
<p class="pl-4 text-base">
{{ $strings.LabelSettingsHideSingleBookSeries }}
<span class="material-symbols icon-text text-sm">info</span> <span class="material-symbols icon-text text-sm">info</span>
</p> </p>
</ui-tooltip> </ui-tooltip>
</div> </div>
</div> <div class="p-2 w-full md:w-1/2">
<div v-if="isBookLibrary" class="py-3"> <div class="flex items-center">
<div class="flex items-center"> <ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" size="sm" @input="formUpdated" />
<ui-toggle-switch v-model="onlyShowLaterBooksInContinueSeries" @input="formUpdated" /> <ui-toggle-switch v-else disabled size="sm" :value="false" />
<ui-tooltip :text="$strings.LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp"> <p class="pl-4 text-sm">{{ $strings.LabelSettingsEnableWatcherForLibrary }}</p>
<p class="pl-4 text-base"> </div>
{{ $strings.LabelSettingsOnlyShowLaterBooksInContinueSeries }} <p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
</div>
<div v-if="isBookLibrary" class="flex items-center p-2 w-full md:w-1/2">
<ui-toggle-switch v-model="audiobooksOnly" size="sm" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsAudiobooksOnlyHelp">
<p class="pl-4 text-sm">
{{ $strings.LabelSettingsAudiobooksOnly }}
<span class="material-symbols icon-text text-sm">info</span> <span class="material-symbols icon-text text-sm">info</span>
</p> </p>
</ui-tooltip> </ui-tooltip>
</div> </div>
</div> <div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
<div v-if="isBookLibrary" class="py-3"> <div class="flex items-center">
<div class="flex items-center"> <ui-toggle-switch v-model="skipMatchingMediaWithAsin" size="sm" @input="formUpdated" />
<ui-toggle-switch v-model="epubsAllowScriptedContent" @input="formUpdated" /> <p class="pl-4 text-sm">{{ $strings.LabelSettingsSkipMatchingBooksWithASIN }}</p>
<ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp"> </div>
<p class="pl-4 text-base"> </div>
{{ $strings.LabelSettingsEpubsAllowScriptedContent }} <div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
<span class="material-symbols icon-text text-sm">info</span> <div class="flex items-center">
</p> <ui-toggle-switch v-model="skipMatchingMediaWithIsbn" size="sm" @input="formUpdated" />
</ui-tooltip> <p class="pl-4 text-sm">{{ $strings.LabelSettingsSkipMatchingBooksWithISBN }}</p>
</div>
</div>
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
<div class="flex items-center">
<ui-toggle-switch v-model="hideSingleBookSeries" size="sm" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsHideSingleBookSeriesHelp">
<p class="pl-4 text-sm">
{{ $strings.LabelSettingsHideSingleBookSeries }}
<span class="material-symbols icon-text text-sm">info</span>
</p>
</ui-tooltip>
</div>
</div>
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
<div class="flex items-center">
<ui-toggle-switch v-model="onlyShowLaterBooksInContinueSeries" size="sm" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp">
<p class="pl-4 text-sm">
{{ $strings.LabelSettingsOnlyShowLaterBooksInContinueSeries }}
<span class="material-symbols icon-text text-sm">info</span>
</p>
</ui-tooltip>
</div>
</div>
<div v-if="isBookLibrary" class="p-2 w-full md:w-1/2">
<div class="flex items-center">
<ui-toggle-switch v-model="epubsAllowScriptedContent" size="sm" @input="formUpdated" />
<ui-tooltip :text="$strings.LabelSettingsEpubsAllowScriptedContentHelp">
<p class="pl-4 text-sm">
{{ $strings.LabelSettingsEpubsAllowScriptedContent }}
<span class="material-symbols icon-text text-sm">info</span>
</p>
</ui-tooltip>
</div>
</div>
<div v-if="isPodcastLibrary" class="p-2 w-full md:w-1/2">
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
</div>
<div class="p-2 w-full flex items-center space-x-2 flex-wrap">
<div>
<ui-dropdown v-model="markAsFinishedWhen" :items="maskAsFinishedWhenItems" :label="$strings.LabelSettingsLibraryMarkAsFinishedWhen" small class="w-72 min-w-72 text-sm" menu-max-height="200px" @input="markAsFinishedWhenChanged" />
</div>
<div class="w-16">
<div>
<label class="px-1 text-sm font-semibold"></label>
<div class="relative">
<ui-text-input v-model="markAsFinishedValue" type="number" label="" no-spinner custom-input-class="pr-5" @input="markAsFinishedChanged" />
<div class="absolute top-0 bottom-0 right-4 flex items-center">{{ markAsFinishedWhen === 'timeRemaining' ? '' : '%' }}</div>
</div>
</div>
</div>
</div> </div>
</div>
<div v-if="isPodcastLibrary" class="py-3">
<ui-dropdown :label="$strings.LabelPodcastSearchRegion" v-model="podcastSearchRegion" :items="$podcastSearchRegionOptions" small class="max-w-72" menu-max-height="200px" @input="formUpdated" />
</div> </div>
</div> </div>
</template> </template>
@@ -97,7 +113,9 @@ export default {
epubsAllowScriptedContent: false, epubsAllowScriptedContent: false,
hideSingleBookSeries: false, hideSingleBookSeries: false,
onlyShowLaterBooksInContinueSeries: false, onlyShowLaterBooksInContinueSeries: false,
podcastSearchRegion: 'us' podcastSearchRegion: 'us',
markAsFinishedWhen: 'timeRemaining',
markAsFinishedValue: 10
} }
}, },
computed: { computed: {
@@ -119,10 +137,34 @@ export default {
providers() { providers() {
if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders if (this.mediaType === 'podcast') return this.$store.state.scanners.podcastProviders
return this.$store.state.scanners.providers return this.$store.state.scanners.providers
},
maskAsFinishedWhenItems() {
return [
{
text: this.$strings.LabelSettingsLibraryMarkAsFinishedTimeRemaining,
value: 'timeRemaining'
},
{
text: this.$strings.LabelSettingsLibraryMarkAsFinishedPercentComplete,
value: 'percentComplete'
}
]
} }
}, },
methods: { methods: {
markAsFinishedWhenChanged(val) {
if (val === 'percentComplete' && this.markAsFinishedValue > 100) {
this.markAsFinishedValue = 100
}
this.formUpdated()
},
markAsFinishedChanged(val) {
this.formUpdated()
},
getLibraryData() { getLibraryData() {
let markAsFinishedTimeRemaining = this.markAsFinishedWhen === 'timeRemaining' ? Number(this.markAsFinishedValue) : null
let markAsFinishedPercentComplete = this.markAsFinishedWhen === 'percentComplete' ? Number(this.markAsFinishedValue) : null
return { return {
settings: { settings: {
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD, coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
@@ -133,7 +175,9 @@ export default {
epubsAllowScriptedContent: !!this.epubsAllowScriptedContent, epubsAllowScriptedContent: !!this.epubsAllowScriptedContent,
hideSingleBookSeries: !!this.hideSingleBookSeries, hideSingleBookSeries: !!this.hideSingleBookSeries,
onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries, onlyShowLaterBooksInContinueSeries: !!this.onlyShowLaterBooksInContinueSeries,
podcastSearchRegion: this.podcastSearchRegion podcastSearchRegion: this.podcastSearchRegion,
markAsFinishedTimeRemaining: markAsFinishedTimeRemaining,
markAsFinishedPercentComplete: markAsFinishedPercentComplete
} }
} }
}, },
@@ -150,6 +194,11 @@ export default {
this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries this.hideSingleBookSeries = !!this.librarySettings.hideSingleBookSeries
this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries this.onlyShowLaterBooksInContinueSeries = !!this.librarySettings.onlyShowLaterBooksInContinueSeries
this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us' this.podcastSearchRegion = this.librarySettings.podcastSearchRegion || 'us'
this.markAsFinishedWhen = this.librarySettings.markAsFinishedTimeRemaining ? 'timeRemaining' : 'percentComplete'
if (!this.librarySettings.markAsFinishedTimeRemaining && !this.librarySettings.markAsFinishedPercentComplete) {
this.markAsFinishedWhen = 'timeRemaining'
}
this.markAsFinishedValue = this.librarySettings.markAsFinishedTimeRemaining || this.librarySettings.markAsFinishedPercentComplete || 10
} }
}, },
mounted() { mounted() {
@@ -3,13 +3,13 @@
<div class="w-full border border-black-200 p-4 my-8"> <div class="w-full border border-black-200 p-4 my-8">
<div class="flex flex-wrap items-center"> <div class="flex flex-wrap items-center">
<div> <div>
<p class="text-lg">Remove metadata files in library item folders</p> <p class="text-lg">{{ $strings.LabelRemoveMetadataFile }}</p>
<p class="max-w-sm text-sm pt-2 text-gray-300">Remove all metadata.json or metadata.abs files in your {{ mediaType }} folders</p> <p class="max-w-sm text-sm pt-2 text-gray-300">{{ $getString('LabelRemoveMetadataFileHelp', [mediaType]) }}</p>
</div> </div>
<div class="flex-grow" /> <div class="flex-grow" />
<div> <div>
<ui-btn class="mb-4 block" @click.stop="removeAllMetadataClick('json')">Remove all metadata.json</ui-btn> <ui-btn class="mb-4 block" @click.stop="removeAllMetadataClick('json')">{{ $strings.LabelRemoveAllMetadataJson }}</ui-btn>
<ui-btn @click.stop="removeAllMetadataClick('abs')">Remove all metadata.abs</ui-btn> <ui-btn @click.stop="removeAllMetadataClick('abs')">{{ $strings.LabelRemoveAllMetadataAbs }}</ui-btn>
</div> </div>
</div> </div>
</div> </div>
@@ -43,7 +43,7 @@ export default {
methods: { methods: {
removeAllMetadataClick(ext) { removeAllMetadataClick(ext) {
const payload = { const payload = {
message: `Are you sure you want to remove all metadata.${ext} files in your library item folders?`, message: this.$getString('MessageConfirmRemoveMetadataFiles', [ext]),
persistent: true, persistent: true,
callback: (confirmed) => { callback: (confirmed) => {
if (confirmed) { if (confirmed) {
@@ -60,16 +60,16 @@ export default {
.$post(`/api/libraries/${this.libraryId}/remove-metadata?ext=${ext}`) .$post(`/api/libraries/${this.libraryId}/remove-metadata?ext=${ext}`)
.then((data) => { .then((data) => {
if (!data.found) { if (!data.found) {
this.$toast.info(`No metadata.${ext} files were found in library`) this.$toast.info(this.$getString('ToastMetadataFilesRemovedNoneFound', [ext]))
} else if (!data.removed) { } else if (!data.removed) {
this.$toast.success(`No metadata.${ext} files removed`) this.$toast.success(this.$getString('ToastMetadataFilesRemovedNoneRemoved', [ext]))
} else { } else {
this.$toast.success(`Successfully removed ${data.removed} metadata.${ext} files`) this.$toast.success(this.$getString('ToastMetadataFilesRemovedSuccess', [data.removed, ext]))
} }
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to remove metadata files', error) console.error('Failed to remove metadata files', error)
this.$toast.error('Failed to remove metadata files') this.$toast.error(this.$getString('ToastMetadataFilesRemovedError', [ext]))
}) })
.finally(() => { .finally(() => {
this.$emit('update:processing', false) this.$emit('update:processing', false)
@@ -156,7 +156,12 @@ export default {
return this.selectedFolder.fullPath return this.selectedFolder.fullPath
}, },
podcastTypes() { podcastTypes() {
return this.$store.state.globals.podcastTypes || [] return this.$store.state.globals.podcastTypes.map((e) => {
return {
text: this.$strings[e.descriptionKey] || e.text,
value: e.value
}
})
} }
}, },
methods: { methods: {
@@ -33,11 +33,11 @@
</div> </div>
<div v-if="enclosureUrl" class="pb-4 pt-6"> <div v-if="enclosureUrl" class="pb-4 pt-6">
<ui-text-input-with-label :value="enclosureUrl" readonly class="text-xs"> <ui-text-input-with-label :value="enclosureUrl" readonly class="text-xs">
<label class="px-1 text-xs text-gray-200 font-semibold">Episode URL from RSS feed</label> <label class="px-1 text-xs text-gray-200 font-semibold">{{ $strings.LabelEpisodeUrlFromRssFeed }}</label>
</ui-text-input-with-label> </ui-text-input-with-label>
</div> </div>
<div v-else class="py-4"> <div v-else class="py-4">
<p class="text-xs text-gray-300 font-semibold">Episode not linked to RSS feed episode</p> <p class="text-xs text-gray-300 font-semibold">{{ $strings.LabelEpisodeNotLinkedToRssFeed }}</p>
</div> </div>
</div> </div>
</template> </template>
@@ -97,7 +97,12 @@ export default {
return this.enclosure.url return this.enclosure.url
}, },
episodeTypes() { episodeTypes() {
return this.$store.state.globals.episodeTypes || [] return this.$store.state.globals.episodeTypes.map((e) => {
return {
text: this.$strings[e.descriptionKey] || e.text,
value: e.value
}
})
} }
}, },
methods: { methods: {
@@ -152,14 +157,14 @@ export default {
const updateResult = await this.$axios.$patch(`/api/podcasts/${this.libraryItem.id}/episode/${this.episodeId}`, updatedDetails).catch((error) => { const updateResult = await this.$axios.$patch(`/api/podcasts/${this.libraryItem.id}/episode/${this.episodeId}`, updatedDetails).catch((error) => {
console.error('Failed update episode', error) console.error('Failed update episode', error)
this.isProcessing = false this.isProcessing = false
this.$toast.error(error?.response?.data || 'Failed to update episode') this.$toast.error(error?.response?.data || this.$strings.ToastFailedToUpdate)
return false return false
}) })
this.isProcessing = false this.isProcessing = false
if (updateResult) { if (updateResult) {
if (updateResult) { if (updateResult) {
this.$toast.success('Podcast episode updated') this.$toast.success(this.$strings.ToastItemUpdateSuccess)
return true return true
} else { } else {
this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary) this.$toast.info(this.$strings.MessageNoUpdatesWereNecessary)
@@ -139,7 +139,7 @@ export default {
slug: this.newFeedSlug, slug: this.newFeedSlug,
metadataDetails: this.metadataDetails metadataDetails: this.metadataDetails
} }
if (this.$isDev) payload.serverAddress = `http://localhost:3333${this.$config.routerBasePath}` if (this.$isDev) payload.serverAddress = process.env.serverUrl
console.log('Payload', payload) console.log('Payload', payload)
this.$axios this.$axios
@@ -12,10 +12,10 @@
</div> </div>
<div class="h-8 flex items-center"> <div class="h-8 flex items-center">
<div class="w-full inline-flex justify-between max-w-xl"> <div class="w-full inline-flex justify-between max-w-xl">
<p v-if="episode?.season" class="text-sm text-gray-300">Season #{{ episode.season }}</p> <p v-if="episode?.season" class="text-sm text-gray-300">{{ $getString('LabelSeasonNumber', [episode.season]) }}</p>
<p v-if="episode?.episode" class="text-sm text-gray-300">Episode #{{ episode.episode }}</p> <p v-if="episode?.episode" class="text-sm text-gray-300">{{ $getString('LabelEpisodeNumber', [episode.episode]) }}</p>
<p v-if="episode?.chapters?.length" class="text-sm text-gray-300">{{ episode.chapters.length }} Chapters</p> <p v-if="episode?.chapters?.length" class="text-sm text-gray-300">{{ $getString('LabelChapterCount', [episode.chapters.length]) }}</p>
<p v-if="publishedAt" class="text-sm text-gray-300">Published {{ $formatDate(publishedAt, dateFormat) }}</p> <p v-if="publishedAt" class="text-sm text-gray-300">{{ $getString('LabelPublishedDate', [$formatDate(publishedAt, dateFormat)]) }}</p>
</div> </div>
</div> </div>
@@ -132,13 +132,13 @@ export default {
return this.store.state.streamIsPlaying && this.isStreaming return this.store.state.streamIsPlaying && this.isStreaming
}, },
timeRemaining() { timeRemaining() {
if (this.streamIsPlaying) return 'Playing' if (this.streamIsPlaying) return this.$strings.ButtonPlaying
if (!this.itemProgress) return this.$elapsedPretty(this.episode?.duration || 0) if (!this.itemProgress) return this.$elapsedPretty(this.episode?.duration || 0)
if (this.userIsFinished) return 'Finished' if (this.userIsFinished) return this.$strings.LabelFinished
const duration = this.itemProgress.duration || this.episode?.duration || 0 const duration = this.itemProgress.duration || this.episode?.duration || 0
const remaining = Math.floor(duration - this.itemProgress.currentTime) const remaining = Math.floor(duration - this.itemProgress.currentTime)
return `${this.$elapsedPretty(remaining)} left` return this.$getString('LabelTimeLeft', [this.$elapsedPretty(remaining)])
} }
}, },
methods: { methods: {
@@ -182,7 +182,7 @@ export default {
toggleFinished(confirmed = false) { toggleFinished(confirmed = false) {
if (!this.userIsFinished && this.itemProgressPercent > 0 && !confirmed) { if (!this.userIsFinished && this.itemProgressPercent > 0 && !confirmed) {
const payload = { const payload = {
message: `Are you sure you want to mark "${this.episodeTitle}" as finished?`, message: this.$getString('MessageConfirmMarkItemFinished', [this.episodeTitle]),
callback: (confirmed) => { callback: (confirmed) => {
if (confirmed) { if (confirmed) {
this.toggleFinished(true) this.toggleFinished(true)
@@ -96,7 +96,7 @@ export default {
const menuItems = [] const menuItems = []
if (this.userIsAdminOrUp) { if (this.userIsAdminOrUp) {
menuItems.push({ menuItems.push({
text: 'Quick match all episodes', text: this.$strings.MessageQuickMatchAllEpisodes,
action: 'quick-match-episodes' action: 'quick-match-episodes'
}) })
} }
@@ -262,21 +262,21 @@ export default {
this.processing = true this.processing = true
const payload = { const payload = {
message: 'Quick matching episodes will overwrite details if a match is found. Only unmatched episodes will be updated. Are you sure?', message: this.$strings.MessageConfirmQuickMatchEpisodes,
callback: (confirmed) => { callback: (confirmed) => {
if (confirmed) { if (confirmed) {
this.$axios this.$axios
.$post(`/api/podcasts/${this.libraryItem.id}/match-episodes?override=1`) .$post(`/api/podcasts/${this.libraryItem.id}/match-episodes?override=1`)
.then((data) => { .then((data) => {
if (data.numEpisodesUpdated) { if (data.numEpisodesUpdated) {
this.$toast.success(`${data.numEpisodesUpdated} episodes updated`) this.$toast.success(this.$getString('ToastEpisodeUpdateSuccess', [data.numEpisodesUpdated]))
} else { } else {
this.$toast.info(this.$strings.ToastNoUpdatesNecessary) this.$toast.info(this.$strings.ToastNoUpdatesNecessary)
} }
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to request match episodes', error) console.error('Failed to request match episodes', error)
this.$toast.error('Failed to match episodes') this.$toast.error(this.$strings.ToastFailedToMatch)
}) })
} }
this.processing = false this.processing = false
+3 -1
View File
@@ -57,7 +57,8 @@ export default {
inputName: String, inputName: String,
showCopy: Boolean, showCopy: Boolean,
step: [String, Number], step: [String, Number],
min: [String, Number] min: [String, Number],
customInputClass: String
}, },
data() { data() {
return { return {
@@ -82,6 +83,7 @@ export default {
_list.push(`py-${this.paddingY}`) _list.push(`py-${this.paddingY}`)
if (this.noSpinner) _list.push('no-spinner') if (this.noSpinner) _list.push('no-spinner')
if (this.textCenter) _list.push('text-center') if (this.textCenter) _list.push('text-center')
if (this.customInputClass) _list.push(this.customInputClass)
return _list.join(' ') return _list.join(' ')
}, },
actualType() { actualType() {
+14 -3
View File
@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<button :aria-labelledby="labeledBy" role="checkbox" type="button" class="border rounded-full border-black-100 flex items-center cursor-pointer w-10 justify-start" :aria-checked="toggleValue" :class="className" @click="clickToggle"> <button :aria-labelledby="labeledBy" role="checkbox" type="button" class="border rounded-full border-black-100 flex items-center cursor-pointer justify-start" :style="{ width: buttonWidth + 'px' }" :aria-checked="toggleValue" :class="className" @click="clickToggle">
<span class="rounded-full border w-5 h-5 border-black-50 shadow transform transition-transform duration-100" :class="switchClassName"></span> <span class="rounded-full border border-black-50 shadow transform transition-transform duration-100" :style="{ width: cursorHeightWidth + 'px', height: cursorHeightWidth + 'px' }" :class="switchClassName"></span>
</button> </button>
</div> </div>
</template> </template>
@@ -19,7 +19,11 @@ export default {
default: 'primary' default: 'primary'
}, },
disabled: Boolean, disabled: Boolean,
labeledBy: String labeledBy: String,
size: {
type: String,
default: 'md'
}
}, },
computed: { computed: {
toggleValue: { toggleValue: {
@@ -37,6 +41,13 @@ export default {
switchClassName() { switchClassName() {
var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white' var bgColor = this.disabled ? 'bg-gray-300' : 'bg-white'
return this.toggleValue ? 'translate-x-5 ' + bgColor : bgColor return this.toggleValue ? 'translate-x-5 ' + bgColor : bgColor
},
cursorHeightWidth() {
if (this.size === 'sm') return 16
return 20
},
buttonWidth() {
return this.cursorHeightWidth * 2
} }
}, },
methods: { methods: {
@@ -101,7 +101,12 @@ export default {
return this.$store.state.libraries.filterData || {} return this.$store.state.libraries.filterData || {}
}, },
podcastTypes() { podcastTypes() {
return this.$store.state.globals.podcastTypes || [] return this.$store.state.globals.podcastTypes.map((e) => {
return {
text: this.$strings[e.descriptionKey] || e.text,
value: e.value
}
})
} }
}, },
methods: { methods: {
+2 -1
View File
@@ -357,7 +357,8 @@ export default {
teardown: false, teardown: false,
transports: ['websocket'], transports: ['websocket'],
upgrade: false, upgrade: false,
reconnection: true reconnection: true,
path: `${this.$config.routerBasePath}/socket.io`
}) })
this.$root.socket = this.socket this.$root.socket = this.socket
console.log('Socket initialized') console.log('Socket initialized')
+34 -49
View File
@@ -1,19 +1,24 @@
const pkg = require('./package.json') const pkg = require('./package.json')
const routerBasePath = process.env.ROUTER_BASE_PATH || ''
const serverHostUrl = process.env.NODE_ENV === 'production' ? '' : 'http://localhost:3333'
const serverPaths = ['api/', 'public/', 'hls/', 'auth/', 'feed/', 'status', 'login', 'logout', 'init']
const proxy = Object.fromEntries(serverPaths.map((path) => [`${routerBasePath}/${path}`, { target: process.env.NODE_ENV !== 'production' ? serverHostUrl : '/' }]))
module.exports = { module.exports = {
// Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode
ssr: false, ssr: false,
target: 'static', target: 'static',
dev: process.env.NODE_ENV !== 'production', dev: process.env.NODE_ENV !== 'production',
env: { env: {
serverUrl: process.env.NODE_ENV === 'production' ? process.env.ROUTER_BASE_PATH || '' : 'http://localhost:3333', serverUrl: serverHostUrl + routerBasePath,
chromecastReceiver: 'FD1F76C5' chromecastReceiver: 'FD1F76C5'
}, },
telemetry: false, telemetry: false,
publicRuntimeConfig: { publicRuntimeConfig: {
version: pkg.version, version: pkg.version,
routerBasePath: process.env.ROUTER_BASE_PATH || '' routerBasePath
}, },
// Global page headers: https://go.nuxtjs.dev/config-head // Global page headers: https://go.nuxtjs.dev/config-head
@@ -22,38 +27,23 @@ module.exports = {
htmlAttrs: { htmlAttrs: {
lang: 'en' lang: 'en'
}, },
meta: [ meta: [{ charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: '' }, { hid: 'robots', name: 'robots', content: 'noindex' }],
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' },
{ hid: 'robots', name: 'robots', content: 'noindex' }
],
script: [], script: [],
link: [ link: [
{ rel: 'icon', type: 'image/x-icon', href: (process.env.ROUTER_BASE_PATH || '') + '/favicon.ico' }, { rel: 'icon', type: 'image/x-icon', href: routerBasePath + '/favicon.ico' },
{ rel: 'apple-touch-icon', href: (process.env.ROUTER_BASE_PATH || '') + '/ios_icon.png' } { rel: 'apple-touch-icon', href: routerBasePath + '/ios_icon.png' }
] ]
}, },
router: { router: {
base: process.env.ROUTER_BASE_PATH || '' base: routerBasePath
}, },
// Global CSS: https://go.nuxtjs.dev/config-css // Global CSS: https://go.nuxtjs.dev/config-css
css: [ css: ['@/assets/tailwind.css', '@/assets/app.css'],
'@/assets/tailwind.css',
'@/assets/app.css'
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [ plugins: ['@/plugins/constants.js', '@/plugins/init.client.js', '@/plugins/axios.js', '@/plugins/toast.js', '@/plugins/utils.js', '@/plugins/i18n.js'],
'@/plugins/constants.js',
'@/plugins/init.client.js',
'@/plugins/axios.js',
'@/plugins/toast.js',
'@/plugins/utils.js',
'@/plugins/i18n.js'
],
// Auto import components: https://go.nuxtjs.dev/config-components // Auto import components: https://go.nuxtjs.dev/config-components
components: true, components: true,
@@ -65,30 +55,25 @@ module.exports = {
], ],
// Modules: https://go.nuxtjs.dev/config-modules // Modules: https://go.nuxtjs.dev/config-modules
modules: [ modules: ['nuxt-socket-io', '@nuxtjs/axios', '@nuxtjs/proxy'],
'nuxt-socket-io',
'@nuxtjs/axios',
'@nuxtjs/proxy'
],
proxy: { proxy,
'/api/': { target: process.env.NODE_ENV !== 'production' ? 'http://localhost:3333' : '/' },
'/dev/': { target: 'http://localhost:3333', pathRewrite: { '^/dev/': '' } }
},
io: { io: {
sockets: [{ sockets: [
name: 'dev', {
url: 'http://localhost:3333' name: 'dev',
}, url: serverHostUrl
{ },
name: 'prod' {
}] name: 'prod'
}
]
}, },
// Axios module configuration: https://go.nuxtjs.dev/config-axios // Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: { axios: {
baseURL: process.env.ROUTER_BASE_PATH || '' baseURL: routerBasePath
}, },
// nuxt/pwa https://pwa.nuxtjs.org // nuxt/pwa https://pwa.nuxtjs.org
@@ -108,11 +93,11 @@ module.exports = {
background_color: '#232323', background_color: '#232323',
icons: [ icons: [
{ {
src: (process.env.ROUTER_BASE_PATH || '') + '/icon.svg', src: routerBasePath + '/icon.svg',
sizes: 'any' sizes: 'any'
}, },
{ {
src: (process.env.ROUTER_BASE_PATH || '') + '/icon192.png', src: routerBasePath + '/icon192.png',
type: 'image/png', type: 'image/png',
sizes: 'any' sizes: 'any'
} }
@@ -132,7 +117,7 @@ module.exports = {
postcssOptions: { postcssOptions: {
plugins: { plugins: {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {}
} }
} }
} }
@@ -149,12 +134,12 @@ module.exports = {
}, },
/** /**
* Temporary workaround for @nuxt-community/tailwindcss-module. * Temporary workaround for @nuxt-community/tailwindcss-module.
* *
* Reported: 2022-05-23 * Reported: 2022-05-23
* See: [Issue tracker](https://github.com/nuxt-community/tailwindcss-module/issues/480) * See: [Issue tracker](https://github.com/nuxt-community/tailwindcss-module/issues/480)
*/ */
devServerHandlers: [], devServerHandlers: [],
ignore: ["**/*.test.*", "**/*.cy.*"] ignore: ['**/*.test.*', '**/*.cy.*']
} }
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.15.0", "version": "2.16.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.15.0", "version": "2.16.2",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.15.0", "version": "2.16.2",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast client", "description": "Self-hosted audiobook and podcast client",
"main": "index.js", "main": "index.js",
+97 -1
View File
@@ -32,9 +32,48 @@
</form> </form>
</div> </div>
<div v-if="showEreaderTable">
<div class="w-full h-px bg-white/10 my-4" />
<app-settings-content :header-text="$strings.HeaderEreaderDevices">
<template #header-items>
<div class="flex-grow" />
<ui-btn color="primary" small @click="addNewDeviceClick">{{ $strings.ButtonAddDevice }}</ui-btn>
</template>
<table v-if="ereaderDevices.length" class="tracksTable mt-4">
<tr>
<th class="text-left">{{ $strings.LabelName }}</th>
<th class="text-left">{{ $strings.LabelEmail }}</th>
<th class="w-40"></th>
</tr>
<tr v-for="device in ereaderDevices" :key="device.name">
<td>
<p class="text-sm md:text-base text-gray-100">{{ device.name }}</p>
</td>
<td class="text-left">
<p class="text-sm md:text-base text-gray-100">{{ device.email }}</p>
</td>
<td class="w-40">
<div class="flex justify-end items-center h-10">
<ui-icon-btn icon="edit" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name || device.users?.length !== 1" class="mx-1" @click="editDeviceClick(device)" />
<ui-icon-btn icon="delete" borderless :size="8" icon-font-size="1.1rem" :disabled="deletingDeviceName === device.name || device.users?.length !== 1" @click="deleteDeviceClick(device)" />
</div>
</td>
</tr>
</table>
<div v-else-if="!loading" class="text-center py-4">
<p class="text-lg text-gray-100">{{ $strings.MessageNoDevices }}</p>
</div>
</app-settings-content>
</div>
<div class="py-4 mt-8 flex"> <div class="py-4 mt-8 flex">
<ui-btn color="primary flex items-center text-lg" @click="logout"><span class="material-symbols mr-4 icon-text">logout</span>{{ $strings.ButtonLogout }}</ui-btn> <ui-btn color="primary flex items-center text-lg" @click="logout"><span class="material-symbols mr-4 icon-text">logout</span>{{ $strings.ButtonLogout }}</ui-btn>
</div> </div>
<modals-emails-user-e-reader-device-modal v-model="showEReaderDeviceModal" :existing-devices="revisedEreaderDevices" :ereader-device="selectedEReaderDevice" @update="ereaderDevicesUpdated" />
</div> </div>
</div> </div>
</template> </template>
@@ -43,11 +82,20 @@
export default { export default {
data() { data() {
return { return {
loading: false,
password: null, password: null,
newPassword: null, newPassword: null,
confirmPassword: null, confirmPassword: null,
changingPassword: false, changingPassword: false,
selectedLanguage: '' selectedLanguage: '',
newEReaderDevice: {
name: '',
email: ''
},
ereaderDevices: [],
deletingDeviceName: null,
selectedEReaderDevice: null,
showEReaderDeviceModal: false
} }
}, },
computed: { computed: {
@@ -75,6 +123,12 @@ export default {
}, },
showChangePasswordForm() { showChangePasswordForm() {
return !this.isGuest && this.isPasswordAuthEnabled return !this.isGuest && this.isPasswordAuthEnabled
},
showEreaderTable() {
return this.usertype !== 'root' && this.usertype !== 'admin' && this.user.permissions?.createEreader
},
revisedEreaderDevices() {
return this.ereaderDevices.filter((device) => device.users?.length === 1)
} }
}, },
methods: { methods: {
@@ -142,10 +196,52 @@ export default {
this.$toast.error(this.$strings.ToastUnknownError) this.$toast.error(this.$strings.ToastUnknownError)
this.changingPassword = false this.changingPassword = false
}) })
},
addNewDeviceClick() {
this.selectedEReaderDevice = null
this.showEReaderDeviceModal = true
},
editDeviceClick(device) {
this.selectedEReaderDevice = device
this.showEReaderDeviceModal = true
},
deleteDeviceClick(device) {
const payload = {
message: this.$getString('MessageConfirmDeleteDevice', [device.name]),
callback: (confirmed) => {
if (confirmed) {
this.deleteDevice(device)
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
},
deleteDevice(device) {
const payload = {
ereaderDevices: this.revisedEreaderDevices.filter((d) => d.name !== device.name)
}
this.deletingDeviceName = device.name
this.$axios
.$post(`/api/me/ereader-devices`, payload)
.then((data) => {
this.ereaderDevicesUpdated(data.ereaderDevices)
})
.catch((error) => {
console.error('Failed to delete device', error)
this.$toast.error(this.$strings.ToastRemoveFailed)
})
.finally(() => {
this.deletingDeviceName = null
})
},
ereaderDevicesUpdated(ereaderDevices) {
this.ereaderDevices = ereaderDevices
} }
}, },
mounted() { mounted() {
this.selectedLanguage = this.$languageCodes.current this.selectedLanguage = this.$languageCodes.current
this.ereaderDevices = this.$store.state.libraries.ereaderDevices || []
} }
} }
</script> </script>
+3 -3
View File
@@ -415,7 +415,7 @@ export default {
const audioEl = this.audioEl || document.createElement('audio') const audioEl = this.audioEl || document.createElement('audio')
var src = audioTrack.contentUrl + `?token=${this.userToken}` var src = audioTrack.contentUrl + `?token=${this.userToken}`
if (this.$isDev) { if (this.$isDev) {
src = `http://localhost:3333${this.$config.routerBasePath}${src}` src = `${process.env.serverUrl}${src}`
} }
audioEl.src = src audioEl.src = src
@@ -486,7 +486,7 @@ export default {
.then((data) => { .then((data) => {
this.saving = false this.saving = false
if (data.updated) { if (data.updated) {
this.$toast.success('Chapters updated') this.$toast.success(this.$strings.ToastChaptersUpdated)
if (this.previousRoute) { if (this.previousRoute) {
this.$router.push(this.previousRoute) this.$router.push(this.previousRoute)
} else { } else {
@@ -533,7 +533,7 @@ export default {
}, },
findChapters() { findChapters() {
if (!this.asinInput) { if (!this.asinInput) {
this.$toast.error('Must input an ASIN') this.$toast.error(this.$strings.ToastAsinRequired)
return return
} }
+2 -2
View File
@@ -88,7 +88,7 @@
<ui-dropdown v-model="itemsPerPage" :items="itemsPerPageOptions" small class="w-24 mx-2" @input="updatedItemsPerPage" /> <ui-dropdown v-model="itemsPerPage" :items="itemsPerPageOptions" small class="w-24 mx-2" @input="updatedItemsPerPage" />
</div> </div>
<div class="inline-flex items-center"> <div class="inline-flex items-center">
<p class="text-sm mx-2">Page {{ currentPage + 1 }} of {{ numPages }}</p> <p class="text-sm mx-2">{{ $getString('LabelPaginationPageXOfY', [currentPage + 1, numPages]) }}</p>
<ui-icon-btn icon="arrow_back_ios_new" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" /> <ui-icon-btn icon="arrow_back_ios_new" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
<ui-icon-btn icon="arrow_forward_ios" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" /> <ui-icon-btn icon="arrow_forward_ios" :size="9" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
</div> </div>
@@ -103,7 +103,7 @@
<div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" /> <div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
<!-- open listening sessions table --> <!-- open listening sessions table -->
<p v-if="openListeningSessions.length" class="text-lg my-4">Open Listening Sessions</p> <p v-if="openListeningSessions.length" class="text-lg my-4">{{ $strings.HeaderOpenListeningSessions }}</p>
<div v-if="openListeningSessions.length" class="block max-w-full"> <div v-if="openListeningSessions.length" class="block max-w-full">
<table class="userSessionsTable"> <table class="userSessionsTable">
<tr class="bg-primary bg-opacity-40"> <tr class="bg-primary bg-opacity-40">
+1 -1
View File
@@ -14,7 +14,7 @@
<h1 class="text-xl pl-2">{{ username }}</h1> <h1 class="text-xl pl-2">{{ username }}</h1>
</div> </div>
<div v-if="userToken" class="flex text-xs mt-4"> <div v-if="userToken" class="flex text-xs mt-4">
<ui-text-input-with-label label="API Token" :value="userToken" readonly /> <ui-text-input-with-label :label="$strings.LabelApiToken" :value="userToken" readonly />
<div class="px-1 mt-8 cursor-pointer" @click="copyToClipboard(userToken)"> <div class="px-1 mt-8 cursor-pointer" @click="copyToClipboard(userToken)">
<span class="material-symbols pl-2 text-base">content_copy</span> <span class="material-symbols pl-2 text-base">content_copy</span>
+1 -1
View File
@@ -54,7 +54,7 @@
</table> </table>
<div class="flex items-center justify-end py-1"> <div class="flex items-center justify-end py-1">
<ui-icon-btn icon="arrow_back_ios_new" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" /> <ui-icon-btn icon="arrow_back_ios_new" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage === 0" @click="prevPage" />
<p class="text-sm mx-1">Page {{ currentPage + 1 }} of {{ numPages }}</p> <p class="text-sm mx-1">{{ $getString('LabelPaginationPageXOfY', [currentPage + 1, numPages]) }}</p>
<ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" /> <ui-icon-btn icon="arrow_forward_ios" :size="7" icon-font-size="1rem" class="mx-1" :disabled="currentPage >= numPages - 1" @click="nextPage" />
</div> </div>
</div> </div>
+1 -1
View File
@@ -120,7 +120,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to updated narrator', error) console.error('Failed to updated narrator', error)
this.$toast.error('Failed to update narrator') this.$toast.error(this.$strings.ToastFailedToUpdate)
this.loading = false this.loading = false
}) })
}, },
+8 -9
View File
@@ -10,7 +10,7 @@
<p v-if="mediaItemShare.playbackSession.displayAuthor" class="text-lg lg:text-xl text-slate-400 font-semibold text-center mb-1 truncate">{{ mediaItemShare.playbackSession.displayAuthor }}</p> <p v-if="mediaItemShare.playbackSession.displayAuthor" class="text-lg lg:text-xl text-slate-400 font-semibold text-center mb-1 truncate">{{ mediaItemShare.playbackSession.displayAuthor }}</p>
<div class="w-full pt-16"> <div class="w-full pt-16">
<player-ui ref="audioPlayer" :chapters="chapters" :paused="isPaused" :loading="!hasLoaded" :is-podcast="false" hide-bookmarks hide-sleep-timer @playPause="playPause" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setVolume="setVolume" @setPlaybackRate="setPlaybackRate" @seek="seek" /> <player-ui ref="audioPlayer" :chapters="chapters" :current-chapter="currentChapter" :paused="isPaused" :loading="!hasLoaded" :is-podcast="false" hide-bookmarks hide-sleep-timer @playPause="playPause" @jumpForward="jumpForward" @jumpBackward="jumpBackward" @setVolume="setVolume" @setPlaybackRate="setPlaybackRate" @seek="seek" />
</div> </div>
</div> </div>
</div> </div>
@@ -51,7 +51,8 @@ export default {
windowHeight: 0, windowHeight: 0,
listeningTimeSinceSync: 0, listeningTimeSinceSync: 0,
coverRgb: null, coverRgb: null,
coverBgIsLight: false coverBgIsLight: false,
currentTime: 0
} }
}, },
computed: { computed: {
@@ -60,16 +61,10 @@ export default {
}, },
coverUrl() { coverUrl() {
if (!this.playbackSession.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg` if (!this.playbackSession.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg`
if (process.env.NODE_ENV === 'development') { return `${this.$config.routerBasePath}/public/share/${this.mediaItemShare.slug}/cover`
return `http://localhost:3333/public/share/${this.mediaItemShare.slug}/cover`
}
return `/public/share/${this.mediaItemShare.slug}/cover`
}, },
audioTracks() { audioTracks() {
return (this.playbackSession.audioTracks || []).map((track) => { return (this.playbackSession.audioTracks || []).map((track) => {
if (process.env.NODE_ENV === 'development') {
track.contentUrl = `${process.env.serverUrl}${track.contentUrl}`
}
track.relativeContentUrl = track.contentUrl track.relativeContentUrl = track.contentUrl
return track return track
}) })
@@ -83,6 +78,9 @@ export default {
chapters() { chapters() {
return this.playbackSession.chapters || [] return this.playbackSession.chapters || []
}, },
currentChapter() {
return this.chapters.find((chapter) => chapter.start <= this.currentTime && this.currentTime < chapter.end)
},
coverAspectRatio() { coverAspectRatio() {
const coverAspectRatio = this.playbackSession.coverAspectRatio const coverAspectRatio = this.playbackSession.coverAspectRatio
return coverAspectRatio === this.$constants.BookCoverAspectRatio.STANDARD ? 1.6 : 1 return coverAspectRatio === this.$constants.BookCoverAspectRatio.STANDARD ? 1.6 : 1
@@ -154,6 +152,7 @@ export default {
// Update UI // Update UI
this.$refs.audioPlayer.setCurrentTime(time) this.$refs.audioPlayer.setCurrentTime(time)
this.currentTime = time
}, },
setDuration() { setDuration() {
if (!this.localAudioPlayer) return if (!this.localAudioPlayer) return
-4
View File
@@ -23,10 +23,6 @@ export default class AudioTrack {
get relativeContentUrl() { get relativeContentUrl() {
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
if (process.env.NODE_ENV === 'development') {
return `${process.env.serverUrl}${this.contentUrl}?token=${this.userToken}`
}
return this.contentUrl + `?token=${this.userToken}` return this.contentUrl + `?token=${this.userToken}`
} }
} }
-2
View File
@@ -297,7 +297,6 @@ export default class PlayerHandler {
if (listeningTimeToAdd > 20) { if (listeningTimeToAdd > 20) {
syncData = { syncData = {
timeListened: listeningTimeToAdd, timeListened: listeningTimeToAdd,
duration: this.getDuration(),
currentTime: this.getCurrentTime() currentTime: this.getCurrentTime()
} }
} }
@@ -317,7 +316,6 @@ export default class PlayerHandler {
const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync)) const listeningTimeToAdd = Math.max(0, Math.floor(this.listeningTimeSinceSync))
const syncData = { const syncData = {
timeListened: listeningTimeToAdd, timeListened: listeningTimeToAdd,
duration: this.getDuration(),
currentTime currentTime
} }
+2 -3
View File
@@ -1,5 +1,5 @@
export default function ({ $axios, store, $config }) { export default function ({ $axios, store, $config }) {
$axios.onRequest(config => { $axios.onRequest((config) => {
if (!config.url) { if (!config.url) {
console.error('Axios request invalid config', config) console.error('Axios request invalid config', config)
return return
@@ -13,12 +13,11 @@ export default function ({ $axios, store, $config }) {
} }
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
config.url = `/dev${config.url}`
console.log('Making request to ' + config.url) console.log('Making request to ' + config.url)
} }
}) })
$axios.onError(error => { $axios.onError((error) => {
const code = parseInt(error.response && error.response.status) const code = parseInt(error.response && error.response.status)
const message = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error' const message = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error'
console.error('Axios error', code, message) console.error('Axios error', code, message)
+5 -15
View File
@@ -72,13 +72,13 @@ export const state = () => ({
} }
], ],
podcastTypes: [ podcastTypes: [
{ text: 'Episodic', value: 'episodic' }, { text: 'Episodic', value: 'episodic', descriptionKey: 'LabelEpisodic' },
{ text: 'Serial', value: 'serial' } { text: 'Serial', value: 'serial', descriptionKey: 'LabelSerial' }
], ],
episodeTypes: [ episodeTypes: [
{ text: 'Full', value: 'full' }, { text: 'Full', value: 'full', descriptionKey: 'LabelFull' },
{ text: 'Trailer', value: 'trailer' }, { text: 'Trailer', value: 'trailer', descriptionKey: 'LabelTrailer' },
{ text: 'Bonus', value: 'bonus' } { text: 'Bonus', value: 'bonus', descriptionKey: 'LabelBonus' }
], ],
libraryIcons: ['database', 'audiobookshelf', 'books-1', 'books-2', 'book-1', 'microphone-1', 'microphone-3', 'radio', 'podcast', 'rss', 'headphones', 'music', 'file-picture', 'rocket', 'power', 'star', 'heart'] libraryIcons: ['database', 'audiobookshelf', 'books-1', 'books-2', 'book-1', 'microphone-1', 'microphone-3', 'radio', 'podcast', 'rss', 'headphones', 'music', 'file-picture', 'rocket', 'power', 'star', 'heart']
}) })
@@ -98,12 +98,6 @@ export const getters = {
const userToken = rootGetters['user/getToken'] const userToken = rootGetters['user/getToken']
const lastUpdate = libraryItem.updatedAt || Date.now() const lastUpdate = libraryItem.updatedAt || Date.now()
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
if (process.env.NODE_ENV !== 'production') {
// Testing
return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
}
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}` return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
}, },
getLibraryItemCoverSrcById: getLibraryItemCoverSrcById:
@@ -112,10 +106,6 @@ export const getters = {
const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg` const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
if (!libraryItemId) return placeholder if (!libraryItemId) return placeholder
const userToken = rootGetters['user/getToken'] const userToken = rootGetters['user/getToken']
if (process.env.NODE_ENV !== 'production') {
// Testing
return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}`
}
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}` return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}`
}, },
getIsBatchSelectingMediaItems: (state) => { getIsBatchSelectingMediaItems: (state) => {
+2 -2
View File
@@ -309,9 +309,9 @@ export const mutations = {
} }
// Add publishedDecades // Add publishedDecades
if (mediaMetadata.publishedYear) { if (mediaMetadata.publishedYear && !isNaN(mediaMetadata.publishedYear)) {
const publishedYear = parseInt(mediaMetadata.publishedYear, 10) const publishedYear = parseInt(mediaMetadata.publishedYear, 10)
const decade = Math.floor(publishedYear / 10) * 10 const decade = (Math.floor(publishedYear / 10) * 10).toString()
if (!state.filterData.publishedDecades.includes(decade)) { if (!state.filterData.publishedDecades.includes(decade)) {
state.filterData.publishedDecades.push(decade) state.filterData.publishedDecades.push(decade)
state.filterData.publishedDecades.sort((a, b) => a - b) state.filterData.publishedDecades.sort((a, b) => a - b)
+12
View File
@@ -19,6 +19,7 @@
"ButtonChooseFiles": "Vybrat soubory", "ButtonChooseFiles": "Vybrat soubory",
"ButtonClearFilter": "Vymazat filtr", "ButtonClearFilter": "Vymazat filtr",
"ButtonCloseFeed": "Zavřít kanál", "ButtonCloseFeed": "Zavřít kanál",
"ButtonCloseSession": "Zavřít otevřenou relaci",
"ButtonCollections": "Kolekce", "ButtonCollections": "Kolekce",
"ButtonConfigureScanner": "Konfigurovat Prohledávání", "ButtonConfigureScanner": "Konfigurovat Prohledávání",
"ButtonCreate": "Vytvořit", "ButtonCreate": "Vytvořit",
@@ -29,6 +30,8 @@
"ButtonEditChapters": "Upravit kapitoly", "ButtonEditChapters": "Upravit kapitoly",
"ButtonEditPodcast": "Upravit podcast", "ButtonEditPodcast": "Upravit podcast",
"ButtonEnable": "Povolit", "ButtonEnable": "Povolit",
"ButtonFireAndFail": "Spustit a selhat",
"ButtonFireOnTest": "Spustit událost onTest",
"ButtonForceReScan": "Vynutit opětovné prohledání", "ButtonForceReScan": "Vynutit opětovné prohledání",
"ButtonFullPath": "Úplná cesta", "ButtonFullPath": "Úplná cesta",
"ButtonHide": "Skrýt", "ButtonHide": "Skrýt",
@@ -58,10 +61,12 @@
"ButtonPlaylists": "Seznamy skladeb", "ButtonPlaylists": "Seznamy skladeb",
"ButtonPrevious": "Předchozí", "ButtonPrevious": "Předchozí",
"ButtonPreviousChapter": "Předchozí Kapitola", "ButtonPreviousChapter": "Předchozí Kapitola",
"ButtonProbeAudioFile": "Prozkoumat audio soubor",
"ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť", "ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť",
"ButtonPurgeItemsCache": "Vyčistit mezipaměť položek", "ButtonPurgeItemsCache": "Vyčistit mezipaměť položek",
"ButtonQueueAddItem": "Přidat do fronty", "ButtonQueueAddItem": "Přidat do fronty",
"ButtonQueueRemoveItem": "Odstranit z fronty", "ButtonQueueRemoveItem": "Odstranit z fronty",
"ButtonQuickEmbed": "Rychle Zapsat",
"ButtonQuickEmbedMetadata": "Rychle Zapsat Metadata", "ButtonQuickEmbedMetadata": "Rychle Zapsat Metadata",
"ButtonQuickMatch": "Rychlé přiřazení", "ButtonQuickMatch": "Rychlé přiřazení",
"ButtonReScan": "Znovu prohledat", "ButtonReScan": "Znovu prohledat",
@@ -175,6 +180,7 @@
"HeaderRemoveEpisodes": "Odstranit {0} epizody", "HeaderRemoveEpisodes": "Odstranit {0} epizody",
"HeaderSavedMediaProgress": "Průběh uložených médií", "HeaderSavedMediaProgress": "Průběh uložených médií",
"HeaderSchedule": "Plán", "HeaderSchedule": "Plán",
"HeaderScheduleEpisodeDownloads": "Naplánovat automatické stahování epizod",
"HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven", "HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven",
"HeaderSession": "Relace", "HeaderSession": "Relace",
"HeaderSetBackupSchedule": "Nastavit plán zálohování", "HeaderSetBackupSchedule": "Nastavit plán zálohování",
@@ -220,7 +226,11 @@
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů", "LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů", "LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
"LabelAlreadyInYourLibrary": "Již ve vaší knihovně", "LabelAlreadyInYourLibrary": "Již ve vaší knihovně",
"LabelApiToken": "API Token",
"LabelAppend": "Připojit", "LabelAppend": "Připojit",
"LabelAudioBitrate": "Bitový tok zvuku (např. 128k)",
"LabelAudioChannels": "Zvukové kanály (1 nebo 2)",
"LabelAudioCodec": "Kodek audia",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (jméno a příjmení)", "LabelAuthorFirstLast": "Autor (jméno a příjmení)",
"LabelAuthorLastFirst": "Autor (příjmení a jméno)", "LabelAuthorLastFirst": "Autor (příjmení a jméno)",
@@ -233,6 +243,7 @@
"LabelAutoRegister": "Automatická registrace", "LabelAutoRegister": "Automatická registrace",
"LabelAutoRegisterDescription": "Automaticky vytvářet nové uživatele po přihlášení", "LabelAutoRegisterDescription": "Automaticky vytvářet nové uživatele po přihlášení",
"LabelBackToUser": "Zpět k uživateli", "LabelBackToUser": "Zpět k uživateli",
"LabelBackupAudioFiles": "Zálohovat zvukové soubory",
"LabelBackupLocation": "Umístění zálohy", "LabelBackupLocation": "Umístění zálohy",
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování", "LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
@@ -241,6 +252,7 @@
"LabelBackupsNumberToKeep": "Počet záloh, které se mají uchovat", "LabelBackupsNumberToKeep": "Počet záloh, které se mají uchovat",
"LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.", "LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.",
"LabelBitrate": "Datový tok", "LabelBitrate": "Datový tok",
"LabelBonus": "Bonus",
"LabelBooks": "Knihy", "LabelBooks": "Knihy",
"LabelButtonText": "Text tlačítka", "LabelButtonText": "Text tlačítka",
"LabelByAuthor": "od {0}", "LabelByAuthor": "od {0}",
+78 -1
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Lösche Medien-Cache", "ButtonPurgeItemsCache": "Lösche Medien-Cache",
"ButtonQueueAddItem": "Zur Warteschlange hinzufügen", "ButtonQueueAddItem": "Zur Warteschlange hinzufügen",
"ButtonQueueRemoveItem": "Aus der Warteschlange entfernen", "ButtonQueueRemoveItem": "Aus der Warteschlange entfernen",
"ButtonQuickEmbed": "Schnelles Hinzufügen",
"ButtonQuickEmbedMetadata": "Schnelles Hinzufügen von Metadaten", "ButtonQuickEmbedMetadata": "Schnelles Hinzufügen von Metadaten",
"ButtonQuickMatch": "Schnellabgleich", "ButtonQuickMatch": "Schnellabgleich",
"ButtonReScan": "Neu scannen", "ButtonReScan": "Neu scannen",
@@ -162,6 +163,7 @@
"HeaderNotificationUpdate": "Benachrichtigung bearbeiten", "HeaderNotificationUpdate": "Benachrichtigung bearbeiten",
"HeaderNotifications": "Benachrichtigungen", "HeaderNotifications": "Benachrichtigungen",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung", "HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
"HeaderOpenListeningSessions": "Aktive Hörbuch-Sitzungen",
"HeaderOpenRSSFeed": "RSS-Feed öffnen", "HeaderOpenRSSFeed": "RSS-Feed öffnen",
"HeaderOtherFiles": "Sonstige Dateien", "HeaderOtherFiles": "Sonstige Dateien",
"HeaderPasswordAuthentication": "Passwortauthentifizierung", "HeaderPasswordAuthentication": "Passwortauthentifizierung",
@@ -179,6 +181,7 @@
"HeaderRemoveEpisodes": "Entferne {0} Episoden", "HeaderRemoveEpisodes": "Entferne {0} Episoden",
"HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte", "HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte",
"HeaderSchedule": "Zeitplan", "HeaderSchedule": "Zeitplan",
"HeaderScheduleEpisodeDownloads": "Automatische Episoden-Downloads planen",
"HeaderScheduleLibraryScans": "Automatische Bibliotheksscans", "HeaderScheduleLibraryScans": "Automatische Bibliotheksscans",
"HeaderSession": "Sitzung", "HeaderSession": "Sitzung",
"HeaderSetBackupSchedule": "Zeitplan für die Datensicherung festlegen", "HeaderSetBackupSchedule": "Zeitplan für die Datensicherung festlegen",
@@ -224,7 +227,11 @@
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen", "LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
"LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste", "LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste",
"LabelAlreadyInYourLibrary": "Bereits in der Bibliothek", "LabelAlreadyInYourLibrary": "Bereits in der Bibliothek",
"LabelApiToken": "API Schlüssel",
"LabelAppend": "Anhängen", "LabelAppend": "Anhängen",
"LabelAudioBitrate": "Audiobitrate (z. B. 128 kbit/s)",
"LabelAudioChannels": "Audiokanäle (1 oder 2)",
"LabelAudioCodec": "Audiocodec",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Vorname Nachname)", "LabelAuthorFirstLast": "Autor (Vorname Nachname)",
"LabelAuthorLastFirst": "Autor (Nachname, Vorname)", "LabelAuthorLastFirst": "Autor (Nachname, Vorname)",
@@ -237,6 +244,7 @@
"LabelAutoRegister": "Automatische Registrierung", "LabelAutoRegister": "Automatische Registrierung",
"LabelAutoRegisterDescription": "Automatische neue Neutzer anlegen nach dem Registrieren", "LabelAutoRegisterDescription": "Automatische neue Neutzer anlegen nach dem Registrieren",
"LabelBackToUser": "Zurück zum Benutzer", "LabelBackToUser": "Zurück zum Benutzer",
"LabelBackupAudioFiles": "Audio-Dateien sichern",
"LabelBackupLocation": "Backup-Ort", "LabelBackupLocation": "Backup-Ort",
"LabelBackupsEnableAutomaticBackups": "Automatische Sicherung aktivieren", "LabelBackupsEnableAutomaticBackups": "Automatische Sicherung aktivieren",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups werden in /metadata/backups gespeichert", "LabelBackupsEnableAutomaticBackupsHelp": "Backups werden in /metadata/backups gespeichert",
@@ -245,15 +253,18 @@
"LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen", "LabelBackupsNumberToKeep": "Anzahl der aufzubewahrenden Sicherungen",
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn du bereits mehrere Sicherungen als die definierte max. Anzahl hast, solltest du diese manuell entfernen.", "LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn du bereits mehrere Sicherungen als die definierte max. Anzahl hast, solltest du diese manuell entfernen.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBonus": "Bonus",
"LabelBooks": "Bücher", "LabelBooks": "Bücher",
"LabelButtonText": "Knopftext", "LabelButtonText": "Knopftext",
"LabelByAuthor": "von {0}", "LabelByAuthor": "von {0}",
"LabelChangePassword": "Passwort ändern", "LabelChangePassword": "Passwort ändern",
"LabelChannels": "Kanäle", "LabelChannels": "Kanäle",
"LabelChapterCount": "{0} Kapitel",
"LabelChapterTitle": "Kapitelüberschrift", "LabelChapterTitle": "Kapitelüberschrift",
"LabelChapters": "Kapitel", "LabelChapters": "Kapitel",
"LabelChaptersFound": "Gefundene Kapitel", "LabelChaptersFound": "Gefundene Kapitel",
"LabelClickForMoreInfo": "Klicken für mehr Informationen", "LabelClickForMoreInfo": "Klicken für mehr Informationen",
"LabelClickToUseCurrentValue": "Anklicken um aktuellen Wert zu verwenden",
"LabelClosePlayer": "Player schließen", "LabelClosePlayer": "Player schließen",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Serien einklappen", "LabelCollapseSeries": "Serien einklappen",
@@ -303,12 +314,25 @@
"LabelEmailSettingsTestAddress": "Test-Adresse", "LabelEmailSettingsTestAddress": "Test-Adresse",
"LabelEmbeddedCover": "Eingebettetes Cover", "LabelEmbeddedCover": "Eingebettetes Cover",
"LabelEnable": "Aktivieren", "LabelEnable": "Aktivieren",
"LabelEncodingBackupLocation": "Eine Sicherungskopie der originalen Audiodateien wird gespeichert in:",
"LabelEncodingChaptersNotEmbedded": "Kapitel sind in mehrspurigen Hörbüchern nicht eingebettet.",
"LabelEncodingClearItemCache": "Stelle sicher, dass der Cache regelmäßig geleert wird.",
"LabelEncodingFinishedM4B": "Die fertige M4B-Datei wird im Hörbuch-Ordner unter folgendem Pfad abgelegt:",
"LabelEncodingInfoEmbedded": "Metadaten werden in die Audiodateien innerhalb des Audiobook Ordners eingebunden.",
"LabelEncodingStartedNavigation": "Sobald die Aufgabe gestartet ist, kann die Seite verlassen werden.",
"LabelEncodingTimeWarning": "Kodierung kann bis zu 30 Minuten dauern.",
"LabelEncodingWarningAdvancedSettings": "Achtung: Ändere diese Einstellungen nur, wenn du dich mit ffmpeg Kodierung auskennst.",
"LabelEncodingWatcherDisabled": "Wenn der Watcher deaktiviert ist musst du das Hörbuch danach erneut scannen.",
"LabelEnd": "Ende", "LabelEnd": "Ende",
"LabelEndOfChapter": "Ende des Kapitels", "LabelEndOfChapter": "Ende des Kapitels",
"LabelEpisode": "Episode", "LabelEpisode": "Episode",
"LabelEpisodeNotLinkedToRssFeed": "Episode nicht mit RSS-Feed verknüpft",
"LabelEpisodeNumber": "Episode #{0}",
"LabelEpisodeTitle": "Episodentitel", "LabelEpisodeTitle": "Episodentitel",
"LabelEpisodeType": "Episodentyp", "LabelEpisodeType": "Episodentyp",
"LabelEpisodeUrlFromRssFeed": "Episoden URL vom RSS-Feed",
"LabelEpisodes": "Episoden", "LabelEpisodes": "Episoden",
"LabelEpisodic": "Episodisch",
"LabelExample": "Beispiel", "LabelExample": "Beispiel",
"LabelExpandSeries": "Serie ausklappen", "LabelExpandSeries": "Serie ausklappen",
"LabelExpandSubSeries": "Unterserie ausklappen", "LabelExpandSubSeries": "Unterserie ausklappen",
@@ -336,6 +360,7 @@
"LabelFontScale": "Schriftgröße", "LabelFontScale": "Schriftgröße",
"LabelFontStrikethrough": "Durchgestrichen", "LabelFontStrikethrough": "Durchgestrichen",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelFull": "Voll",
"LabelGenre": "Kategorie", "LabelGenre": "Kategorie",
"LabelGenres": "Kategorien", "LabelGenres": "Kategorien",
"LabelHardDeleteFile": "Datei dauerhaft löschen", "LabelHardDeleteFile": "Datei dauerhaft löschen",
@@ -391,6 +416,10 @@
"LabelLowestPriority": "Niedrigste Priorität", "LabelLowestPriority": "Niedrigste Priorität",
"LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit", "LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit",
"LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID vom SSO-Anbieter zugeordnet", "LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID vom SSO-Anbieter zugeordnet",
"LabelMaxEpisodesToDownload": "Max. Anzahl an Episoden zum Herunterladen, 0 für unbegrenzte Episoden.",
"LabelMaxEpisodesToDownloadPerCheck": "Max. Anzahl neuer Episoden zum Herunterladen pro Abfrage",
"LabelMaxEpisodesToKeep": "Max. Anzahl zu behaltender Episoden",
"LabelMaxEpisodesToKeepHelp": "0 setzt keine Begrenzung. Wenn eine neue Episode automatisch heruntergeladen wird, wird die älteste Episode gelöscht, wenn du mehr als X Episoden gespeichert hast. Es wird nur eine Episode pro neuem Download gelöscht.",
"LabelMediaPlayer": "Mediaplayer", "LabelMediaPlayer": "Mediaplayer",
"LabelMediaType": "Medientyp", "LabelMediaType": "Medientyp",
"LabelMetaTag": "Meta Schlagwort", "LabelMetaTag": "Meta Schlagwort",
@@ -436,12 +465,14 @@
"LabelOpenIDGroupClaimDescription": "Name des OpenID-Claims, der eine Liste der Benutzergruppen enthält. Wird häufig als <code>groups</code> bezeichnet. <b>Wenn konfiguriert</b>, wird die Anwendung automatisch Rollen basierend auf den Gruppenmitgliedschaften des Benutzers zuweisen, vorausgesetzt, dass diese Gruppen im Claim als 'admin', 'user' oder 'guest' benannt sind (Groß/Kleinschreibung ist irrelevant). Der Claim eine Liste sein, und wenn ein Benutzer mehreren Gruppen angehört, wird die Anwendung die Rolle zuordnen, die dem höchsten Zugriffslevel entspricht. Wenn keine Gruppe übereinstimmt, wird der Zugang verweigert.", "LabelOpenIDGroupClaimDescription": "Name des OpenID-Claims, der eine Liste der Benutzergruppen enthält. Wird häufig als <code>groups</code> bezeichnet. <b>Wenn konfiguriert</b>, wird die Anwendung automatisch Rollen basierend auf den Gruppenmitgliedschaften des Benutzers zuweisen, vorausgesetzt, dass diese Gruppen im Claim als 'admin', 'user' oder 'guest' benannt sind (Groß/Kleinschreibung ist irrelevant). Der Claim eine Liste sein, und wenn ein Benutzer mehreren Gruppen angehört, wird die Anwendung die Rolle zuordnen, die dem höchsten Zugriffslevel entspricht. Wenn keine Gruppe übereinstimmt, wird der Zugang verweigert.",
"LabelOpenRSSFeed": "Öffne RSS-Feed", "LabelOpenRSSFeed": "Öffne RSS-Feed",
"LabelOverwrite": "Überschreiben", "LabelOverwrite": "Überschreiben",
"LabelPaginationPageXOfY": "Seite {0} von {1}",
"LabelPassword": "Passwort", "LabelPassword": "Passwort",
"LabelPath": "Pfad", "LabelPath": "Pfad",
"LabelPermanent": "Dauerhaft", "LabelPermanent": "Dauerhaft",
"LabelPermissionsAccessAllLibraries": "Zugriff auf alle Bibliotheken", "LabelPermissionsAccessAllLibraries": "Zugriff auf alle Bibliotheken",
"LabelPermissionsAccessAllTags": "Zugriff auf alle Schlagwörter", "LabelPermissionsAccessAllTags": "Zugriff auf alle Schlagwörter",
"LabelPermissionsAccessExplicitContent": "Zugriff auf explizite (alterbeschränkte) Inhalte", "LabelPermissionsAccessExplicitContent": "Zugriff auf explizite (alterbeschränkte) Inhalte",
"LabelPermissionsCreateEreader": "Kann E-Reader erstellen",
"LabelPermissionsDelete": "Darf Löschen", "LabelPermissionsDelete": "Darf Löschen",
"LabelPermissionsDownload": "Herunterladen", "LabelPermissionsDownload": "Herunterladen",
"LabelPermissionsUpdate": "Aktualisieren", "LabelPermissionsUpdate": "Aktualisieren",
@@ -486,12 +517,17 @@
"LabelRedo": "Wiederholen", "LabelRedo": "Wiederholen",
"LabelRegion": "Region", "LabelRegion": "Region",
"LabelReleaseDate": "Veröffentlichungsdatum", "LabelReleaseDate": "Veröffentlichungsdatum",
"LabelRemoveAllMetadataAbs": "Alle metadata.abs Dateien löschen",
"LabelRemoveAllMetadataJson": "Alle metadata.json Dateien löschen",
"LabelRemoveCover": "Entferne Titelbild", "LabelRemoveCover": "Entferne Titelbild",
"LabelRemoveMetadataFile": "Metadaten-Dateien in Bibliotheksordnern löschen",
"LabelRemoveMetadataFileHelp": "Alle metadata.json und metadata.abs Dateien aus den Ordnern {0} löschen.",
"LabelRowsPerPage": "Zeilen pro Seite", "LabelRowsPerPage": "Zeilen pro Seite",
"LabelSearchTerm": "Begriff suchen", "LabelSearchTerm": "Begriff suchen",
"LabelSearchTitle": "Titel suchen", "LabelSearchTitle": "Titel suchen",
"LabelSearchTitleOrASIN": "Titel oder ASIN suchen", "LabelSearchTitleOrASIN": "Titel oder ASIN suchen",
"LabelSeason": "Staffel", "LabelSeason": "Staffel",
"LabelSeasonNumber": "Staffel #{0}",
"LabelSelectAll": "Alles auswählen", "LabelSelectAll": "Alles auswählen",
"LabelSelectAllEpisodes": "Alle Episoden auswählen", "LabelSelectAllEpisodes": "Alle Episoden auswählen",
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt", "LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
@@ -501,6 +537,7 @@
"LabelSeries": "Serien", "LabelSeries": "Serien",
"LabelSeriesName": "Serienname", "LabelSeriesName": "Serienname",
"LabelSeriesProgress": "Serienfortschritt", "LabelSeriesProgress": "Serienfortschritt",
"LabelServerLogLevel": "Server Log Level",
"LabelServerYearReview": "Server Jahr in Übersicht ({0})", "LabelServerYearReview": "Server Jahr in Übersicht ({0})",
"LabelSetEbookAsPrimary": "Als Hauptbuch setzen", "LabelSetEbookAsPrimary": "Als Hauptbuch setzen",
"LabelSetEbookAsSupplementary": "Als Ergänzung setzen", "LabelSetEbookAsSupplementary": "Als Ergänzung setzen",
@@ -525,6 +562,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "Serien, die nur ein einzelnes Buch enthalten, werden auf der Startseite und in der Serienansicht ausgeblendet.", "LabelSettingsHideSingleBookSeriesHelp": "Serien, die nur ein einzelnes Buch enthalten, werden auf der Startseite und in der Serienansicht ausgeblendet.",
"LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht", "LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht",
"LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht", "LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "In Prozent gehört größer als",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Verbleibende Zeit ist weniger als (Sekunden)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Markiere Mediendateien als fertig, wenn",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Überspringe vorherige Bücher in fortführender Serie", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Überspringe vorherige Bücher in fortführender Serie",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Die Startseite von \"Fortführende Serien\" zeigt das erste noch nicht begonnene Buch in Serien an, die mindestens ein Buch abgeschlossen und keine Bücher begonnen haben. Wenn diese Einstellung aktiviert wird, werden Serien ab dem letzten abgeschlossenen Buch fortgesetzt und nicht ab dem ersten nicht begonnenen Buch.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Die Startseite von \"Fortführende Serien\" zeigt das erste noch nicht begonnene Buch in Serien an, die mindestens ein Buch abgeschlossen und keine Bücher begonnen haben. Wenn diese Einstellung aktiviert wird, werden Serien ab dem letzten abgeschlossenen Buch fortgesetzt und nicht ab dem ersten nicht begonnenen Buch.",
"LabelSettingsParseSubtitles": "Analysiere Untertitel", "LabelSettingsParseSubtitles": "Analysiere Untertitel",
@@ -569,7 +609,7 @@
"LabelStatsMinutesListening": "Gehörte Minuten", "LabelStatsMinutesListening": "Gehörte Minuten",
"LabelStatsOverallDays": "Gesamte Tage", "LabelStatsOverallDays": "Gesamte Tage",
"LabelStatsOverallHours": "Gesamte Stunden", "LabelStatsOverallHours": "Gesamte Stunden",
"LabelStatsWeekListening": "7-Tage-Durchschnitt", "LabelStatsWeekListening": "Wochenhördauer",
"LabelSubtitle": "Untertitel", "LabelSubtitle": "Untertitel",
"LabelSupportedFileTypes": "Unterstützte Dateitypen", "LabelSupportedFileTypes": "Unterstützte Dateitypen",
"LabelTag": "Schlagwort", "LabelTag": "Schlagwort",
@@ -589,6 +629,7 @@
"LabelTimeDurationXMinutes": "{0} Minuten", "LabelTimeDurationXMinutes": "{0} Minuten",
"LabelTimeDurationXSeconds": "{0} Sekunden", "LabelTimeDurationXSeconds": "{0} Sekunden",
"LabelTimeInMinutes": "Zeit in Minuten", "LabelTimeInMinutes": "Zeit in Minuten",
"LabelTimeLeft": "{0} verbleibend",
"LabelTimeListened": "Gehörte Zeit", "LabelTimeListened": "Gehörte Zeit",
"LabelTimeListenedToday": "Heute gehörte Zeit", "LabelTimeListenedToday": "Heute gehörte Zeit",
"LabelTimeRemaining": "{0} verbleibend", "LabelTimeRemaining": "{0} verbleibend",
@@ -596,6 +637,7 @@
"LabelTitle": "Titel", "LabelTitle": "Titel",
"LabelToolsEmbedMetadata": "Metadaten einbetten", "LabelToolsEmbedMetadata": "Metadaten einbetten",
"LabelToolsEmbedMetadataDescription": "Bettet die Metadaten einschließlich des Titelbildes und der Kapitel in die Audiodatein ein.", "LabelToolsEmbedMetadataDescription": "Bettet die Metadaten einschließlich des Titelbildes und der Kapitel in die Audiodatein ein.",
"LabelToolsM4bEncoder": "M4B Kodierer",
"LabelToolsMakeM4b": "M4B-Datei erstellen", "LabelToolsMakeM4b": "M4B-Datei erstellen",
"LabelToolsMakeM4bDescription": "Erstellt eine M4B-Datei (Endung \".m4b\") welche mehrere mp3-Dateien in einer einzigen Datei inkl. derer Metadaten (Beschreibung, Titelbild, Kapitel, ...) zusammenfasst. M4B-Datei können darüber hinaus Lesezeichen speichern und mit einem Abspielschutz (Passwort) versehen werden.", "LabelToolsMakeM4bDescription": "Erstellt eine M4B-Datei (Endung \".m4b\") welche mehrere mp3-Dateien in einer einzigen Datei inkl. derer Metadaten (Beschreibung, Titelbild, Kapitel, ...) zusammenfasst. M4B-Datei können darüber hinaus Lesezeichen speichern und mit einem Abspielschutz (Passwort) versehen werden.",
"LabelToolsSplitM4b": "M4B in MP3s aufteilen", "LabelToolsSplitM4b": "M4B in MP3s aufteilen",
@@ -608,6 +650,7 @@
"LabelTracksMultiTrack": "Mehrfachdatei", "LabelTracksMultiTrack": "Mehrfachdatei",
"LabelTracksNone": "Keine Dateien", "LabelTracksNone": "Keine Dateien",
"LabelTracksSingleTrack": "Einzeldatei", "LabelTracksSingleTrack": "Einzeldatei",
"LabelTrailer": "Vorschau",
"LabelType": "Typ", "LabelType": "Typ",
"LabelUnabridged": "Ungekürzt", "LabelUnabridged": "Ungekürzt",
"LabelUndo": "Rückgängig machen", "LabelUndo": "Rückgängig machen",
@@ -621,8 +664,10 @@
"LabelUploaderDragAndDrop": "Ziehen und Ablegen von Dateien oder Ordnern", "LabelUploaderDragAndDrop": "Ziehen und Ablegen von Dateien oder Ordnern",
"LabelUploaderDropFiles": "Dateien löschen", "LabelUploaderDropFiles": "Dateien löschen",
"LabelUploaderItemFetchMetadataHelp": "Automatisches Aktualisieren von Titel, Autor und Serie", "LabelUploaderItemFetchMetadataHelp": "Automatisches Aktualisieren von Titel, Autor und Serie",
"LabelUseAdvancedOptions": "Nutze Erweiterte Optionen",
"LabelUseChapterTrack": "Kapiteldatei verwenden", "LabelUseChapterTrack": "Kapiteldatei verwenden",
"LabelUseFullTrack": "Gesamte Datei verwenden", "LabelUseFullTrack": "Gesamte Datei verwenden",
"LabelUseZeroForUnlimited": "0 für unbegrenzt",
"LabelUser": "Benutzer", "LabelUser": "Benutzer",
"LabelUsername": "Benutzername", "LabelUsername": "Benutzername",
"LabelValue": "Wert", "LabelValue": "Wert",
@@ -669,6 +714,7 @@
"MessageConfirmDeleteMetadataProvider": "Möchtest du den benutzerdefinierten Metadatenanbieter \"{0}\" wirklich löschen?", "MessageConfirmDeleteMetadataProvider": "Möchtest du den benutzerdefinierten Metadatenanbieter \"{0}\" wirklich löschen?",
"MessageConfirmDeleteNotification": "Möchtest du diese Benachrichtigung wirklich löschen?", "MessageConfirmDeleteNotification": "Möchtest du diese Benachrichtigung wirklich löschen?",
"MessageConfirmDeleteSession": "Sitzung wird gelöscht! Bist du dir sicher?", "MessageConfirmDeleteSession": "Sitzung wird gelöscht! Bist du dir sicher?",
"MessageConfirmEmbedMetadataInAudioFiles": "Bist du dir sicher, dass die Metadaten in {0} Audiodateien eingebettet werden sollen?",
"MessageConfirmForceReScan": "Scanvorgang erzwingen! Bist du dir sicher?", "MessageConfirmForceReScan": "Scanvorgang erzwingen! Bist du dir sicher?",
"MessageConfirmMarkAllEpisodesFinished": "Alle Episoden werden als abgeschlossen markiert! Bist du dir sicher?", "MessageConfirmMarkAllEpisodesFinished": "Alle Episoden werden als abgeschlossen markiert! Bist du dir sicher?",
"MessageConfirmMarkAllEpisodesNotFinished": "Alle Episoden werden als nicht abgeschlossen markiert! Bist du dir sicher?", "MessageConfirmMarkAllEpisodesNotFinished": "Alle Episoden werden als nicht abgeschlossen markiert! Bist du dir sicher?",
@@ -680,6 +726,7 @@
"MessageConfirmPurgeCache": "Cache leeren wird das ganze Verzeichnis <code>/metadata/cache</code> löschen. <br /><br />Bist du dir sicher, dass das Cache Verzeichnis gelöscht werden soll?", "MessageConfirmPurgeCache": "Cache leeren wird das ganze Verzeichnis <code>/metadata/cache</code> löschen. <br /><br />Bist du dir sicher, dass das Cache Verzeichnis gelöscht werden soll?",
"MessageConfirmPurgeItemsCache": "Durch Elementcache leeren wird das gesamte Verzeichnis unter <code>/metadata/cache/items</code> gelöscht.<br />Bist du dir sicher?", "MessageConfirmPurgeItemsCache": "Durch Elementcache leeren wird das gesamte Verzeichnis unter <code>/metadata/cache/items</code> gelöscht.<br />Bist du dir sicher?",
"MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achte darauf, dass du eine Sicherungskopie der Audiodateien besitzt. <br><br>Möchtest du fortfahren?", "MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achte darauf, dass du eine Sicherungskopie der Audiodateien besitzt. <br><br>Möchtest du fortfahren?",
"MessageConfirmQuickMatchEpisodes": "Schnelles Zuordnen von Episoden überschreibt die Details, wenn eine Übereinstimmung gefunden wird. Nur nicht zugeordnete Episoden werden aktualisiert. Bist du sicher?",
"MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Bist du dir sicher?", "MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Bist du dir sicher?",
"MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?", "MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?",
"MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?", "MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?",
@@ -687,6 +734,7 @@
"MessageConfirmRemoveEpisode": "Episode \"{0}\" wird entfernt! Bist du dir sicher?", "MessageConfirmRemoveEpisode": "Episode \"{0}\" wird entfernt! Bist du dir sicher?",
"MessageConfirmRemoveEpisodes": "{0} Episoden werden entfernt! Bist du dir sicher?", "MessageConfirmRemoveEpisodes": "{0} Episoden werden entfernt! Bist du dir sicher?",
"MessageConfirmRemoveListeningSessions": "Bist du dir sicher, dass du {0} Hörsitzungen enfernen möchtest?", "MessageConfirmRemoveListeningSessions": "Bist du dir sicher, dass du {0} Hörsitzungen enfernen möchtest?",
"MessageConfirmRemoveMetadataFiles": "Bist du sicher, dass du alle metadata.{0} Dateien in deinen Bibliotheksordnern löschen willst?",
"MessageConfirmRemoveNarrator": "Erzähler \"{0}\" wird entfernt! Bist du dir sicher?", "MessageConfirmRemoveNarrator": "Erzähler \"{0}\" wird entfernt! Bist du dir sicher?",
"MessageConfirmRemovePlaylist": "Wiedergabeliste \"{0}\" wird entfernt! Bist du dir sicher?", "MessageConfirmRemovePlaylist": "Wiedergabeliste \"{0}\" wird entfernt! Bist du dir sicher?",
"MessageConfirmRenameGenre": "Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Bist du dir sicher?", "MessageConfirmRenameGenre": "Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Bist du dir sicher?",
@@ -702,6 +750,7 @@
"MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge", "MessageDragFilesIntoTrackOrder": "Verschiebe die Dateien in die richtige Reihenfolge",
"MessageEmbedFailed": "Einbetten fehlgeschlagen!", "MessageEmbedFailed": "Einbetten fehlgeschlagen!",
"MessageEmbedFinished": "Einbettung abgeschlossen!", "MessageEmbedFinished": "Einbettung abgeschlossen!",
"MessageEmbedQueue": "Eingereiht zum einbinden von Metadaten ({0} in Warteschlange)",
"MessageEpisodesQueuedForDownload": "{0} Episode(n) in der Warteschlange zum Herunterladen", "MessageEpisodesQueuedForDownload": "{0} Episode(n) in der Warteschlange zum Herunterladen",
"MessageEreaderDevices": "Um die Zustellung von E-Büchern sicherzustellen, musst du eventuell die oben genannte E-Mail-Adresse als gültigen Absender für jedes unten aufgeführte Gerät hinzufügen.", "MessageEreaderDevices": "Um die Zustellung von E-Büchern sicherzustellen, musst du eventuell die oben genannte E-Mail-Adresse als gültigen Absender für jedes unten aufgeführte Gerät hinzufügen.",
"MessageFeedURLWillBe": "Feed-URL wird {0} sein", "MessageFeedURLWillBe": "Feed-URL wird {0} sein",
@@ -746,6 +795,7 @@
"MessageNoLogs": "Keine Protokolle", "MessageNoLogs": "Keine Protokolle",
"MessageNoMediaProgress": "Kein Medienfortschritt", "MessageNoMediaProgress": "Kein Medienfortschritt",
"MessageNoNotifications": "Keine Benachrichtigungen", "MessageNoNotifications": "Keine Benachrichtigungen",
"MessageNoPodcastFeed": "Ungültiger Podcast: Kein Feed",
"MessageNoPodcastsFound": "Keine Podcasts gefunden", "MessageNoPodcastsFound": "Keine Podcasts gefunden",
"MessageNoResults": "Keine Ergebnisse", "MessageNoResults": "Keine Ergebnisse",
"MessageNoSearchResultsFor": "Keine Suchergebnisse für \"{0}\"", "MessageNoSearchResultsFor": "Keine Suchergebnisse für \"{0}\"",
@@ -762,6 +812,10 @@
"MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung", "MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung",
"MessagePleaseWait": "Bitte warten...", "MessagePleaseWait": "Bitte warten...",
"MessagePodcastHasNoRSSFeedForMatching": "Der Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann", "MessagePodcastHasNoRSSFeedForMatching": "Der Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann",
"MessagePodcastSearchField": "Suchbegriff oder RSS-Feed URL eingeben",
"MessageQuickEmbedInProgress": "Schnellabgleich läuft",
"MessageQuickEmbedQueue": "In Warteschlange für Schnelles einbinden ({0} eingereiht)",
"MessageQuickMatchAllEpisodes": "Quick Match aller Episoden",
"MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.", "MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.",
"MessageRemoveChapter": "Kapitel entfernen", "MessageRemoveChapter": "Kapitel entfernen",
"MessageRemoveEpisodes": "Entferne {0} Episode(n)", "MessageRemoveEpisodes": "Entferne {0} Episode(n)",
@@ -804,6 +858,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Der Podcast ist bereits im Pfad vorhanden", "MessageTaskOpmlImportFeedPodcastExists": "Der Podcast ist bereits im Pfad vorhanden",
"MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen", "MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen",
"MessageTaskOpmlImportFinished": "{0} Podcasts hinzugefügt", "MessageTaskOpmlImportFinished": "{0} Podcasts hinzugefügt",
"MessageTaskOpmlParseFailed": "Fehler beim lesen der OPML Datei",
"MessageTaskOpmlParseFastFail": "Ungültie OPML Datei: <opml> ODER <outline> tag wurde nicht gefunden",
"MessageTaskOpmlParseNoneFound": "Keine feeds in der OPML Datei gefunden",
"MessageTaskScanItemsAdded": "{0} hinzugefügt", "MessageTaskScanItemsAdded": "{0} hinzugefügt",
"MessageTaskScanItemsMissing": "{0} fehlend", "MessageTaskScanItemsMissing": "{0} fehlend",
"MessageTaskScanItemsUpdated": "{0} aktualisiert", "MessageTaskScanItemsUpdated": "{0} aktualisiert",
@@ -828,6 +885,10 @@
"NoteUploaderFoldersWithMediaFiles": "Ordner mit Mediendateien werden als separate Bibliothekselemente behandelt.", "NoteUploaderFoldersWithMediaFiles": "Ordner mit Mediendateien werden als separate Bibliothekselemente behandelt.",
"NoteUploaderOnlyAudioFiles": "Wenn du nur Audiodateien hochlädst, wird jede Audiodatei als ein separates Medium behandelt.", "NoteUploaderOnlyAudioFiles": "Wenn du nur Audiodateien hochlädst, wird jede Audiodatei als ein separates Medium behandelt.",
"NoteUploaderUnsupportedFiles": "Nicht unterstützte Dateien werden ignoriert. Bei der Auswahl oder dem Löschen eines Ordners werden andere Dateien, die sich nicht in einem Elementordner befinden, ignoriert.", "NoteUploaderUnsupportedFiles": "Nicht unterstützte Dateien werden ignoriert. Bei der Auswahl oder dem Löschen eines Ordners werden andere Dateien, die sich nicht in einem Elementordner befinden, ignoriert.",
"NotificationOnBackupCompletedDescription": "Wird ausgeführt wenn ein Backup erstellt wurde",
"NotificationOnBackupFailedDescription": "Wird ausgeführt wenn ein Backup fehlgeschlagen ist",
"NotificationOnEpisodeDownloadedDescription": "Wird ausgeführt wenn eine Podcast Folge automatisch heruntergeladen wird",
"NotificationOnTestDescription": "Wird ausgeführt wenn das Benachrichtigungssystem getestet wird",
"PlaceholderNewCollection": "Neuer Sammlungsname", "PlaceholderNewCollection": "Neuer Sammlungsname",
"PlaceholderNewFolderPath": "Neuer Ordnerpfad", "PlaceholderNewFolderPath": "Neuer Ordnerpfad",
"PlaceholderNewPlaylist": "Neuer Wiedergabelistenname", "PlaceholderNewPlaylist": "Neuer Wiedergabelistenname",
@@ -853,6 +914,7 @@
"StatsYearInReview": "DAS JAHR IM RÜCKBLICK", "StatsYearInReview": "DAS JAHR IM RÜCKBLICK",
"ToastAccountUpdateSuccess": "Konto aktualisiert", "ToastAccountUpdateSuccess": "Konto aktualisiert",
"ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig", "ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig",
"ToastAsinRequired": "ASIN ist erforderlich",
"ToastAuthorImageRemoveSuccess": "Autorenbild entfernt", "ToastAuthorImageRemoveSuccess": "Autorenbild entfernt",
"ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden", "ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden",
"ToastAuthorRemoveSuccess": "Autor entfernt", "ToastAuthorRemoveSuccess": "Autor entfernt",
@@ -872,6 +934,8 @@
"ToastBackupUploadSuccess": "Sicherung hochgeladen", "ToastBackupUploadSuccess": "Sicherung hochgeladen",
"ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen", "ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen",
"ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich", "ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich",
"ToastBatchQuickMatchFailed": "Batch-Schnellabgleich fehlgeschlagen!",
"ToastBatchQuickMatchStarted": "Batch-Schnellabgleich für {0} Bücher gestartet!",
"ToastBatchUpdateFailed": "Stapelaktualisierung fehlgeschlagen", "ToastBatchUpdateFailed": "Stapelaktualisierung fehlgeschlagen",
"ToastBatchUpdateSuccess": "Stapelaktualisierung erfolgreich", "ToastBatchUpdateSuccess": "Stapelaktualisierung erfolgreich",
"ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden", "ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden",
@@ -883,6 +947,7 @@
"ToastChaptersHaveErrors": "Kapitel sind fehlerhaft", "ToastChaptersHaveErrors": "Kapitel sind fehlerhaft",
"ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen", "ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen",
"ToastChaptersRemoved": "Kapitel entfernt", "ToastChaptersRemoved": "Kapitel entfernt",
"ToastChaptersUpdated": "Kapitel aktualisiert",
"ToastCollectionItemsAddFailed": "Das Hinzufügen von Element(en) zur Sammlung ist fehlgeschlagen", "ToastCollectionItemsAddFailed": "Das Hinzufügen von Element(en) zur Sammlung ist fehlgeschlagen",
"ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt", "ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt",
"ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt", "ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt",
@@ -900,11 +965,14 @@
"ToastEncodeCancelSucces": "Encoding abgebrochen", "ToastEncodeCancelSucces": "Encoding abgebrochen",
"ToastEpisodeDownloadQueueClearFailed": "Warteschlange konnte nicht gelöscht werden", "ToastEpisodeDownloadQueueClearFailed": "Warteschlange konnte nicht gelöscht werden",
"ToastEpisodeDownloadQueueClearSuccess": "Warteschlange für Episoden-Downloads gelöscht", "ToastEpisodeDownloadQueueClearSuccess": "Warteschlange für Episoden-Downloads gelöscht",
"ToastEpisodeUpdateSuccess": "{0} Episoden aktualisiert",
"ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden", "ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden",
"ToastFailedToLoadData": "Daten laden fehlgeschlagen", "ToastFailedToLoadData": "Daten laden fehlgeschlagen",
"ToastFailedToMatch": "Fehler beim Abgleich",
"ToastFailedToShare": "Fehler beim Teilen", "ToastFailedToShare": "Fehler beim Teilen",
"ToastFailedToUpdate": "Aktualisierung ist fehlgeschlagen", "ToastFailedToUpdate": "Aktualisierung ist fehlgeschlagen",
"ToastInvalidImageUrl": "Ungültiger Bild URL", "ToastInvalidImageUrl": "Ungültiger Bild URL",
"ToastInvalidMaxEpisodesToDownload": "Ungültige Max. Anzahl an Episoden zum Herunterladen",
"ToastInvalidUrl": "Ungültiger URL", "ToastInvalidUrl": "Ungültiger URL",
"ToastItemCoverUpdateSuccess": "Titelbild aktualisiert", "ToastItemCoverUpdateSuccess": "Titelbild aktualisiert",
"ToastItemDeletedFailed": "Fehler beim löschen des Artikels", "ToastItemDeletedFailed": "Fehler beim löschen des Artikels",
@@ -923,14 +991,21 @@
"ToastLibraryScanStarted": "Bibliotheksscan gestartet", "ToastLibraryScanStarted": "Bibliotheksscan gestartet",
"ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert", "ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert",
"ToastMatchAllAuthorsFailed": "Nicht alle Autoren konnten zugeordnet werden", "ToastMatchAllAuthorsFailed": "Nicht alle Autoren konnten zugeordnet werden",
"ToastMetadataFilesRemovedError": "Fehler beim löschen von metadata.{0} Dateien",
"ToastMetadataFilesRemovedNoneFound": "Keine metadata.{0} Dateien in Bibliothek gefunden",
"ToastMetadataFilesRemovedNoneRemoved": "Keine metadata.{0} Dateien gelöscht",
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} Datei(en) gelöscht",
"ToastMustHaveAtLeastOnePath": "Es muss mindestens ein Pfad angegeben werden",
"ToastNameEmailRequired": "Name und E-Mail sind erforderlich", "ToastNameEmailRequired": "Name und E-Mail sind erforderlich",
"ToastNameRequired": "Name ist erforderlich", "ToastNameRequired": "Name ist erforderlich",
"ToastNewEpisodesFound": "{0} neue Episoden gefunden",
"ToastNewUserCreatedFailed": "Fehler beim erstellen des Accounts: \"{ 0}\"", "ToastNewUserCreatedFailed": "Fehler beim erstellen des Accounts: \"{ 0}\"",
"ToastNewUserCreatedSuccess": "Neuer Account erstellt", "ToastNewUserCreatedSuccess": "Neuer Account erstellt",
"ToastNewUserLibraryError": "Mindestens eine Bibliothek muss ausgewählt werden", "ToastNewUserLibraryError": "Mindestens eine Bibliothek muss ausgewählt werden",
"ToastNewUserPasswordError": "Passwort erforderlich, nur der root Benutzer darf ein leeres Passwort haben", "ToastNewUserPasswordError": "Passwort erforderlich, nur der root Benutzer darf ein leeres Passwort haben",
"ToastNewUserTagError": "Mindestens ein Tag muss ausgewählt sein", "ToastNewUserTagError": "Mindestens ein Tag muss ausgewählt sein",
"ToastNewUserUsernameError": "Nutzername eingeben", "ToastNewUserUsernameError": "Nutzername eingeben",
"ToastNoNewEpisodesFound": "Keine neuen Episoden gefunden",
"ToastNoUpdatesNecessary": "Keine Änderungen nötig", "ToastNoUpdatesNecessary": "Keine Änderungen nötig",
"ToastNotificationCreateFailed": "Fehler beim erstellen der Benachrichtig", "ToastNotificationCreateFailed": "Fehler beim erstellen der Benachrichtig",
"ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung", "ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung",
@@ -949,6 +1024,7 @@
"ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast Feeds", "ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast Feeds",
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden", "ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed", "ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
"ToastProgressIsNotBeingSynced": "Fortschritt wird nicht synchronisiert, Wiedergabe wird neu gestartet",
"ToastProviderCreatedFailed": "Fehler beim hinzufügen des Anbieters", "ToastProviderCreatedFailed": "Fehler beim hinzufügen des Anbieters",
"ToastProviderCreatedSuccess": "Neuer Anbieter hinzugefügt", "ToastProviderCreatedSuccess": "Neuer Anbieter hinzugefügt",
"ToastProviderNameAndUrlRequired": "Name und URL notwendig", "ToastProviderNameAndUrlRequired": "Name und URL notwendig",
@@ -975,6 +1051,7 @@
"ToastSessionCloseFailed": "Fehler beim schließen der Sitzung", "ToastSessionCloseFailed": "Fehler beim schließen der Sitzung",
"ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden", "ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden",
"ToastSessionDeleteSuccess": "Sitzung gelöscht", "ToastSessionDeleteSuccess": "Sitzung gelöscht",
"ToastSleepTimerDone": "Einschlaf-Timer aktiviert... zZzzZz",
"ToastSlugMustChange": "URL-Schlüssel enthält ungültige Zeichen", "ToastSlugMustChange": "URL-Schlüssel enthält ungültige Zeichen",
"ToastSlugRequired": "URL-Schlüssel erforderlich", "ToastSlugRequired": "URL-Schlüssel erforderlich",
"ToastSocketConnected": "Verbindung zum WebSocket hergestellt", "ToastSocketConnected": "Verbindung zum WebSocket hergestellt",
+48
View File
@@ -163,6 +163,7 @@
"HeaderNotificationUpdate": "Update Notification", "HeaderNotificationUpdate": "Update Notification",
"HeaderNotifications": "Notifications", "HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication", "HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenListeningSessions": "Open Listening Sessions",
"HeaderOpenRSSFeed": "Open RSS Feed", "HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files", "HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication", "HeaderPasswordAuthentication": "Password Authentication",
@@ -180,6 +181,7 @@
"HeaderRemoveEpisodes": "Remove {0} Episodes", "HeaderRemoveEpisodes": "Remove {0} Episodes",
"HeaderSavedMediaProgress": "Saved Media Progress", "HeaderSavedMediaProgress": "Saved Media Progress",
"HeaderSchedule": "Schedule", "HeaderSchedule": "Schedule",
"HeaderScheduleEpisodeDownloads": "Schedule Automatic Episode Downloads",
"HeaderScheduleLibraryScans": "Schedule Automatic Library Scans", "HeaderScheduleLibraryScans": "Schedule Automatic Library Scans",
"HeaderSession": "Session", "HeaderSession": "Session",
"HeaderSetBackupSchedule": "Set Backup Schedule", "HeaderSetBackupSchedule": "Set Backup Schedule",
@@ -225,6 +227,7 @@
"LabelAllUsersExcludingGuests": "All users excluding guests", "LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests", "LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Already in your library", "LabelAlreadyInYourLibrary": "Already in your library",
"LabelApiToken": "API Token",
"LabelAppend": "Append", "LabelAppend": "Append",
"LabelAudioBitrate": "Audio Bitrate (e.g. 128k)", "LabelAudioBitrate": "Audio Bitrate (e.g. 128k)",
"LabelAudioChannels": "Audio Channels (1 or 2)", "LabelAudioChannels": "Audio Channels (1 or 2)",
@@ -250,15 +253,18 @@
"LabelBackupsNumberToKeep": "Number of backups to keep", "LabelBackupsNumberToKeep": "Number of backups to keep",
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.", "LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBonus": "Bonus",
"LabelBooks": "Books", "LabelBooks": "Books",
"LabelButtonText": "Button Text", "LabelButtonText": "Button Text",
"LabelByAuthor": "by {0}", "LabelByAuthor": "by {0}",
"LabelChangePassword": "Change Password", "LabelChangePassword": "Change Password",
"LabelChannels": "Channels", "LabelChannels": "Channels",
"LabelChapterCount": "{0} Chapters",
"LabelChapterTitle": "Chapter Title", "LabelChapterTitle": "Chapter Title",
"LabelChapters": "Chapters", "LabelChapters": "Chapters",
"LabelChaptersFound": "chapters found", "LabelChaptersFound": "chapters found",
"LabelClickForMoreInfo": "Click for more info", "LabelClickForMoreInfo": "Click for more info",
"LabelClickToUseCurrentValue": "Click to use current value",
"LabelClosePlayer": "Close player", "LabelClosePlayer": "Close player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Collapse Series", "LabelCollapseSeries": "Collapse Series",
@@ -320,9 +326,13 @@
"LabelEnd": "End", "LabelEnd": "End",
"LabelEndOfChapter": "End of Chapter", "LabelEndOfChapter": "End of Chapter",
"LabelEpisode": "Episode", "LabelEpisode": "Episode",
"LabelEpisodeNotLinkedToRssFeed": "Episode not linked to RSS feed",
"LabelEpisodeNumber": "Episode #{0}",
"LabelEpisodeTitle": "Episode Title", "LabelEpisodeTitle": "Episode Title",
"LabelEpisodeType": "Episode Type", "LabelEpisodeType": "Episode Type",
"LabelEpisodeUrlFromRssFeed": "Episode URL from RSS feed",
"LabelEpisodes": "Episodes", "LabelEpisodes": "Episodes",
"LabelEpisodic": "Episodic",
"LabelExample": "Example", "LabelExample": "Example",
"LabelExpandSeries": "Expand Series", "LabelExpandSeries": "Expand Series",
"LabelExpandSubSeries": "Expand Sub Series", "LabelExpandSubSeries": "Expand Sub Series",
@@ -350,6 +360,7 @@
"LabelFontScale": "Font scale", "LabelFontScale": "Font scale",
"LabelFontStrikethrough": "Strikethrough", "LabelFontStrikethrough": "Strikethrough",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelFull": "Full",
"LabelGenre": "Genre", "LabelGenre": "Genre",
"LabelGenres": "Genres", "LabelGenres": "Genres",
"LabelHardDeleteFile": "Hard delete file", "LabelHardDeleteFile": "Hard delete file",
@@ -405,6 +416,10 @@
"LabelLowestPriority": "Lowest Priority", "LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by", "LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider", "LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMaxEpisodesToDownload": "Max # of episodes to download. Use 0 for unlimited.",
"LabelMaxEpisodesToDownloadPerCheck": "Max # of new episodes to download per check",
"LabelMaxEpisodesToKeep": "Max # of episodes to keep",
"LabelMaxEpisodesToKeepHelp": "Value of 0 sets no max limit. After a new episode is auto-downloaded this will delete the oldest episode if you have more than X episodes. This will only delete 1 episode per new download.",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
@@ -450,12 +465,14 @@
"LabelOpenIDGroupClaimDescription": "Name of the OpenID claim that contains a list of the user's groups. Commonly referred to as <code>groups</code>. <b>If configured</b>, the application will automatically assign roles based on the user's group memberships, provided that these groups are named case-insensitively 'admin', 'user', or 'guest' in the claim. The claim should contain a list, and if a user belongs to multiple groups, the application will assign the role corresponding to the highest level of access. If no group matches, access will be denied.", "LabelOpenIDGroupClaimDescription": "Name of the OpenID claim that contains a list of the user's groups. Commonly referred to as <code>groups</code>. <b>If configured</b>, the application will automatically assign roles based on the user's group memberships, provided that these groups are named case-insensitively 'admin', 'user', or 'guest' in the claim. The claim should contain a list, and if a user belongs to multiple groups, the application will assign the role corresponding to the highest level of access. If no group matches, access will be denied.",
"LabelOpenRSSFeed": "Open RSS Feed", "LabelOpenRSSFeed": "Open RSS Feed",
"LabelOverwrite": "Overwrite", "LabelOverwrite": "Overwrite",
"LabelPaginationPageXOfY": "Page {0} of {1}",
"LabelPassword": "Password", "LabelPassword": "Password",
"LabelPath": "Path", "LabelPath": "Path",
"LabelPermanent": "Permanent", "LabelPermanent": "Permanent",
"LabelPermissionsAccessAllLibraries": "Can Access All Libraries", "LabelPermissionsAccessAllLibraries": "Can Access All Libraries",
"LabelPermissionsAccessAllTags": "Can Access All Tags", "LabelPermissionsAccessAllTags": "Can Access All Tags",
"LabelPermissionsAccessExplicitContent": "Can Access Explicit Content", "LabelPermissionsAccessExplicitContent": "Can Access Explicit Content",
"LabelPermissionsCreateEreader": "Can Create Ereader",
"LabelPermissionsDelete": "Can Delete", "LabelPermissionsDelete": "Can Delete",
"LabelPermissionsDownload": "Can Download", "LabelPermissionsDownload": "Can Download",
"LabelPermissionsUpdate": "Can Update", "LabelPermissionsUpdate": "Can Update",
@@ -500,18 +517,24 @@
"LabelRedo": "Redo", "LabelRedo": "Redo",
"LabelRegion": "Region", "LabelRegion": "Region",
"LabelReleaseDate": "Release Date", "LabelReleaseDate": "Release Date",
"LabelRemoveAllMetadataAbs": "Remove all metadata.abs files",
"LabelRemoveAllMetadataJson": "Remove all metadata.json files",
"LabelRemoveCover": "Remove cover", "LabelRemoveCover": "Remove cover",
"LabelRemoveMetadataFile": "Remove metadata files in library item folders",
"LabelRemoveMetadataFileHelp": "Remove all metadata.json and metadata.abs files in your {0} folders.",
"LabelRowsPerPage": "Rows per page", "LabelRowsPerPage": "Rows per page",
"LabelSearchTerm": "Search Term", "LabelSearchTerm": "Search Term",
"LabelSearchTitle": "Search Title", "LabelSearchTitle": "Search Title",
"LabelSearchTitleOrASIN": "Search Title or ASIN", "LabelSearchTitleOrASIN": "Search Title or ASIN",
"LabelSeason": "Season", "LabelSeason": "Season",
"LabelSeasonNumber": "Season #{0}",
"LabelSelectAll": "Select all", "LabelSelectAll": "Select all",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Select all episodes",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Select {0} episodes showing",
"LabelSelectUsers": "Select users", "LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSendEbookToDevice": "Send Ebook to...",
"LabelSequence": "Sequence", "LabelSequence": "Sequence",
"LabelSerial": "Serial",
"LabelSeries": "Series", "LabelSeries": "Series",
"LabelSeriesName": "Series Name", "LabelSeriesName": "Series Name",
"LabelSeriesProgress": "Series Progress", "LabelSeriesProgress": "Series Progress",
@@ -540,6 +563,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view", "LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view", "LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Percent complete is greater than",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Time remaining is less than (seconds)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Mark media item as finished when",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Skip earlier books in Continue Series",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "The Continue Series home page shelf shows the first book not started in series that have at least one book finished and no books in progress. Enabling this setting will continue series from the furthest completed book instead of the first book not started.",
"LabelSettingsParseSubtitles": "Parse subtitles", "LabelSettingsParseSubtitles": "Parse subtitles",
@@ -604,6 +630,7 @@
"LabelTimeDurationXMinutes": "{0} minutes", "LabelTimeDurationXMinutes": "{0} minutes",
"LabelTimeDurationXSeconds": "{0} seconds", "LabelTimeDurationXSeconds": "{0} seconds",
"LabelTimeInMinutes": "Time in minutes", "LabelTimeInMinutes": "Time in minutes",
"LabelTimeLeft": "{0} left",
"LabelTimeListened": "Time Listened", "LabelTimeListened": "Time Listened",
"LabelTimeListenedToday": "Time Listened Today", "LabelTimeListenedToday": "Time Listened Today",
"LabelTimeRemaining": "{0} remaining", "LabelTimeRemaining": "{0} remaining",
@@ -624,6 +651,7 @@
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksNone": "No tracks", "LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Single-track", "LabelTracksSingleTrack": "Single-track",
"LabelTrailer": "Trailer",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "Unabridged",
"LabelUndo": "Undo", "LabelUndo": "Undo",
@@ -640,6 +668,7 @@
"LabelUseAdvancedOptions": "Use Advanced Options", "LabelUseAdvancedOptions": "Use Advanced Options",
"LabelUseChapterTrack": "Use chapter track", "LabelUseChapterTrack": "Use chapter track",
"LabelUseFullTrack": "Use full track", "LabelUseFullTrack": "Use full track",
"LabelUseZeroForUnlimited": "Use 0 for unlimited",
"LabelUser": "User", "LabelUser": "User",
"LabelUsername": "Username", "LabelUsername": "Username",
"LabelValue": "Value", "LabelValue": "Value",
@@ -698,6 +727,7 @@
"MessageConfirmPurgeCache": "Purge cache will delete the entire directory at <code>/metadata/cache</code>. <br /><br />Are you sure you want to remove the cache directory?", "MessageConfirmPurgeCache": "Purge cache will delete the entire directory at <code>/metadata/cache</code>. <br /><br />Are you sure you want to remove the cache directory?",
"MessageConfirmPurgeItemsCache": "Purge items cache will delete the entire directory at <code>/metadata/cache/items</code>.<br />Are you sure?", "MessageConfirmPurgeItemsCache": "Purge items cache will delete the entire directory at <code>/metadata/cache/items</code>.<br />Are you sure?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?", "MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmQuickMatchEpisodes": "Quick matching episodes will overwrite details if a match is found. Only unmatched episodes will be updated. Are you sure?",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?", "MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?", "MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?", "MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
@@ -705,6 +735,7 @@
"MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?", "MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?", "MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?",
"MessageConfirmRemoveListeningSessions": "Are you sure you want to remove {0} listening sessions?", "MessageConfirmRemoveListeningSessions": "Are you sure you want to remove {0} listening sessions?",
"MessageConfirmRemoveMetadataFiles": "Are you sure you want to remove all metadata.{0} files in your library item folders?",
"MessageConfirmRemoveNarrator": "Are you sure you want to remove narrator \"{0}\"?", "MessageConfirmRemoveNarrator": "Are you sure you want to remove narrator \"{0}\"?",
"MessageConfirmRemovePlaylist": "Are you sure you want to remove your playlist \"{0}\"?", "MessageConfirmRemovePlaylist": "Are you sure you want to remove your playlist \"{0}\"?",
"MessageConfirmRenameGenre": "Are you sure you want to rename genre \"{0}\" to \"{1}\" for all items?", "MessageConfirmRenameGenre": "Are you sure you want to rename genre \"{0}\" to \"{1}\" for all items?",
@@ -785,6 +816,7 @@
"MessagePodcastSearchField": "Enter search term or RSS feed URL", "MessagePodcastSearchField": "Enter search term or RSS feed URL",
"MessageQuickEmbedInProgress": "Quick embed in progress", "MessageQuickEmbedInProgress": "Quick embed in progress",
"MessageQuickEmbedQueue": "Queued for quick embed ({0} in queue)", "MessageQuickEmbedQueue": "Queued for quick embed ({0} in queue)",
"MessageQuickMatchAllEpisodes": "Quick Match All Episodes",
"MessageQuickMatchDescription": "Populate empty item details & cover with first match result from '{0}'. Does not overwrite details unless 'Prefer matched metadata' server setting is enabled.", "MessageQuickMatchDescription": "Populate empty item details & cover with first match result from '{0}'. Does not overwrite details unless 'Prefer matched metadata' server setting is enabled.",
"MessageRemoveChapter": "Remove chapter", "MessageRemoveChapter": "Remove chapter",
"MessageRemoveEpisodes": "Remove {0} episode(s)", "MessageRemoveEpisodes": "Remove {0} episode(s)",
@@ -883,6 +915,7 @@
"StatsYearInReview": "YEAR IN REVIEW", "StatsYearInReview": "YEAR IN REVIEW",
"ToastAccountUpdateSuccess": "Account updated", "ToastAccountUpdateSuccess": "Account updated",
"ToastAppriseUrlRequired": "Must enter an Apprise URL", "ToastAppriseUrlRequired": "Must enter an Apprise URL",
"ToastAsinRequired": "ASIN is required",
"ToastAuthorImageRemoveSuccess": "Author image removed", "ToastAuthorImageRemoveSuccess": "Author image removed",
"ToastAuthorNotFound": "Author \"{0}\" not found", "ToastAuthorNotFound": "Author \"{0}\" not found",
"ToastAuthorRemoveSuccess": "Author removed", "ToastAuthorRemoveSuccess": "Author removed",
@@ -902,6 +935,8 @@
"ToastBackupUploadSuccess": "Backup uploaded", "ToastBackupUploadSuccess": "Backup uploaded",
"ToastBatchDeleteFailed": "Batch delete failed", "ToastBatchDeleteFailed": "Batch delete failed",
"ToastBatchDeleteSuccess": "Batch delete success", "ToastBatchDeleteSuccess": "Batch delete success",
"ToastBatchQuickMatchFailed": "Batch Quick Match failed!",
"ToastBatchQuickMatchStarted": "Batch Quick Match of {0} books started!",
"ToastBatchUpdateFailed": "Batch update failed", "ToastBatchUpdateFailed": "Batch update failed",
"ToastBatchUpdateSuccess": "Batch update success", "ToastBatchUpdateSuccess": "Batch update success",
"ToastBookmarkCreateFailed": "Failed to create bookmark", "ToastBookmarkCreateFailed": "Failed to create bookmark",
@@ -913,6 +948,7 @@
"ToastChaptersHaveErrors": "Chapters have errors", "ToastChaptersHaveErrors": "Chapters have errors",
"ToastChaptersMustHaveTitles": "Chapters must have titles", "ToastChaptersMustHaveTitles": "Chapters must have titles",
"ToastChaptersRemoved": "Chapters removed", "ToastChaptersRemoved": "Chapters removed",
"ToastChaptersUpdated": "Chapters updated",
"ToastCollectionItemsAddFailed": "Item(s) added to collection failed", "ToastCollectionItemsAddFailed": "Item(s) added to collection failed",
"ToastCollectionItemsAddSuccess": "Item(s) added to collection success", "ToastCollectionItemsAddSuccess": "Item(s) added to collection success",
"ToastCollectionItemsRemoveSuccess": "Item(s) removed from collection", "ToastCollectionItemsRemoveSuccess": "Item(s) removed from collection",
@@ -930,11 +966,14 @@
"ToastEncodeCancelSucces": "Encode canceled", "ToastEncodeCancelSucces": "Encode canceled",
"ToastEpisodeDownloadQueueClearFailed": "Failed to clear queue", "ToastEpisodeDownloadQueueClearFailed": "Failed to clear queue",
"ToastEpisodeDownloadQueueClearSuccess": "Episode download queue cleared", "ToastEpisodeDownloadQueueClearSuccess": "Episode download queue cleared",
"ToastEpisodeUpdateSuccess": "{0} episodes updated",
"ToastErrorCannotShare": "Cannot share natively on this device", "ToastErrorCannotShare": "Cannot share natively on this device",
"ToastFailedToLoadData": "Failed to load data", "ToastFailedToLoadData": "Failed to load data",
"ToastFailedToMatch": "Failed to match",
"ToastFailedToShare": "Failed to share", "ToastFailedToShare": "Failed to share",
"ToastFailedToUpdate": "Failed to update", "ToastFailedToUpdate": "Failed to update",
"ToastInvalidImageUrl": "Invalid image URL", "ToastInvalidImageUrl": "Invalid image URL",
"ToastInvalidMaxEpisodesToDownload": "Invalid max episodes to download",
"ToastInvalidUrl": "Invalid URL", "ToastInvalidUrl": "Invalid URL",
"ToastItemCoverUpdateSuccess": "Item cover updated", "ToastItemCoverUpdateSuccess": "Item cover updated",
"ToastItemDeletedFailed": "Failed to delete item", "ToastItemDeletedFailed": "Failed to delete item",
@@ -953,14 +992,21 @@
"ToastLibraryScanStarted": "Library scan started", "ToastLibraryScanStarted": "Library scan started",
"ToastLibraryUpdateSuccess": "Library \"{0}\" updated", "ToastLibraryUpdateSuccess": "Library \"{0}\" updated",
"ToastMatchAllAuthorsFailed": "Failed to match all authors", "ToastMatchAllAuthorsFailed": "Failed to match all authors",
"ToastMetadataFilesRemovedError": "Error removing metadata.{0} files",
"ToastMetadataFilesRemovedNoneFound": "No metadata.{0} files found in library",
"ToastMetadataFilesRemovedNoneRemoved": "No metadata.{0} files removed",
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} files removed",
"ToastMustHaveAtLeastOnePath": "Must have at least one path",
"ToastNameEmailRequired": "Name and email are required", "ToastNameEmailRequired": "Name and email are required",
"ToastNameRequired": "Name is required", "ToastNameRequired": "Name is required",
"ToastNewEpisodesFound": "{0} new episodes found",
"ToastNewUserCreatedFailed": "Failed to create account: \"{0}\"", "ToastNewUserCreatedFailed": "Failed to create account: \"{0}\"",
"ToastNewUserCreatedSuccess": "New account created", "ToastNewUserCreatedSuccess": "New account created",
"ToastNewUserLibraryError": "Must select at least one library", "ToastNewUserLibraryError": "Must select at least one library",
"ToastNewUserPasswordError": "Must have a password, only root user can have an empty password", "ToastNewUserPasswordError": "Must have a password, only root user can have an empty password",
"ToastNewUserTagError": "Must select at least one tag", "ToastNewUserTagError": "Must select at least one tag",
"ToastNewUserUsernameError": "Enter a username", "ToastNewUserUsernameError": "Enter a username",
"ToastNoNewEpisodesFound": "No new episodes found",
"ToastNoUpdatesNecessary": "No updates necessary", "ToastNoUpdatesNecessary": "No updates necessary",
"ToastNotificationCreateFailed": "Failed to create notification", "ToastNotificationCreateFailed": "Failed to create notification",
"ToastNotificationDeleteFailed": "Failed to delete notification", "ToastNotificationDeleteFailed": "Failed to delete notification",
@@ -979,6 +1025,7 @@
"ToastPodcastGetFeedFailed": "Failed to get podcast feed", "ToastPodcastGetFeedFailed": "Failed to get podcast feed",
"ToastPodcastNoEpisodesInFeed": "No episodes found in RSS feed", "ToastPodcastNoEpisodesInFeed": "No episodes found in RSS feed",
"ToastPodcastNoRssFeed": "Podcast does not have an RSS feed", "ToastPodcastNoRssFeed": "Podcast does not have an RSS feed",
"ToastProgressIsNotBeingSynced": "Progress is not being synced, restart playback",
"ToastProviderCreatedFailed": "Failed to add provider", "ToastProviderCreatedFailed": "Failed to add provider",
"ToastProviderCreatedSuccess": "New provider added", "ToastProviderCreatedSuccess": "New provider added",
"ToastProviderNameAndUrlRequired": "Name and Url required", "ToastProviderNameAndUrlRequired": "Name and Url required",
@@ -1005,6 +1052,7 @@
"ToastSessionCloseFailed": "Failed to close session", "ToastSessionCloseFailed": "Failed to close session",
"ToastSessionDeleteFailed": "Failed to delete session", "ToastSessionDeleteFailed": "Failed to delete session",
"ToastSessionDeleteSuccess": "Session deleted", "ToastSessionDeleteSuccess": "Session deleted",
"ToastSleepTimerDone": "Sleep timer done... zZzzZz",
"ToastSlugMustChange": "Slug contains invalid characters", "ToastSlugMustChange": "Slug contains invalid characters",
"ToastSlugRequired": "Slug is required", "ToastSlugRequired": "Slug is required",
"ToastSocketConnected": "Socket connected", "ToastSocketConnected": "Socket connected",
+41 -1
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Purgar Elementos de Cache", "ButtonPurgeItemsCache": "Purgar Elementos de Cache",
"ButtonQueueAddItem": "Agregar a la Fila", "ButtonQueueAddItem": "Agregar a la Fila",
"ButtonQueueRemoveItem": "Remover de la Fila", "ButtonQueueRemoveItem": "Remover de la Fila",
"ButtonQuickEmbed": "Inserción rápida",
"ButtonQuickEmbedMetadata": "Agregue metadatos rápidamente", "ButtonQuickEmbedMetadata": "Agregue metadatos rápidamente",
"ButtonQuickMatch": "Encontrar Rápido", "ButtonQuickMatch": "Encontrar Rápido",
"ButtonReScan": "Re-Escanear", "ButtonReScan": "Re-Escanear",
@@ -179,6 +180,7 @@
"HeaderRemoveEpisodes": "Remover {0} Episodios", "HeaderRemoveEpisodes": "Remover {0} Episodios",
"HeaderSavedMediaProgress": "Guardar Progreso de Multimedia", "HeaderSavedMediaProgress": "Guardar Progreso de Multimedia",
"HeaderSchedule": "Horario", "HeaderSchedule": "Horario",
"HeaderScheduleEpisodeDownloads": "Programar descargas automáticas de episodios",
"HeaderScheduleLibraryScans": "Programar Escaneo Automático de Biblioteca", "HeaderScheduleLibraryScans": "Programar Escaneo Automático de Biblioteca",
"HeaderSession": "Sesión", "HeaderSession": "Sesión",
"HeaderSetBackupSchedule": "Programar Respaldo", "HeaderSetBackupSchedule": "Programar Respaldo",
@@ -225,6 +227,9 @@
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados", "LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
"LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca", "LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca",
"LabelAppend": "Adjuntar", "LabelAppend": "Adjuntar",
"LabelAudioBitrate": "Tasa de bits del audio (por ejemplo, 128k)",
"LabelAudioChannels": "Canales de audio (1 o 2)",
"LabelAudioCodec": "Códec de audio",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Nombre Apellido)", "LabelAuthorFirstLast": "Autor (Nombre Apellido)",
"LabelAuthorLastFirst": "Autor (Apellido, Nombre)", "LabelAuthorLastFirst": "Autor (Apellido, Nombre)",
@@ -237,6 +242,7 @@
"LabelAutoRegister": "Registro automático", "LabelAutoRegister": "Registro automático",
"LabelAutoRegisterDescription": "Crear usuarios automáticamente tras iniciar sesión", "LabelAutoRegisterDescription": "Crear usuarios automáticamente tras iniciar sesión",
"LabelBackToUser": "Regresar a Usuario", "LabelBackToUser": "Regresar a Usuario",
"LabelBackupAudioFiles": "Copia de seguridad de archivos de audio",
"LabelBackupLocation": "Ubicación del Respaldo", "LabelBackupLocation": "Ubicación del Respaldo",
"LabelBackupsEnableAutomaticBackups": "Habilitar Respaldo Automático", "LabelBackupsEnableAutomaticBackups": "Habilitar Respaldo Automático",
"LabelBackupsEnableAutomaticBackupsHelp": "Respaldo Guardado en /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Respaldo Guardado en /metadata/backups",
@@ -245,15 +251,18 @@
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar", "LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.", "LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
"LabelBitrate": "Tasa de bits", "LabelBitrate": "Tasa de bits",
"LabelBonus": "Bonus",
"LabelBooks": "Libros", "LabelBooks": "Libros",
"LabelButtonText": "Texto del botón", "LabelButtonText": "Texto del botón",
"LabelByAuthor": "por {0}", "LabelByAuthor": "por {0}",
"LabelChangePassword": "Cambiar Contraseña", "LabelChangePassword": "Cambiar Contraseña",
"LabelChannels": "Canales", "LabelChannels": "Canales",
"LabelChapterCount": "{0} capítulos",
"LabelChapterTitle": "Titulo del Capítulo", "LabelChapterTitle": "Titulo del Capítulo",
"LabelChapters": "Capítulos", "LabelChapters": "Capítulos",
"LabelChaptersFound": "Capítulo Encontrado", "LabelChaptersFound": "Capítulo Encontrado",
"LabelClickForMoreInfo": "Click para más información", "LabelClickForMoreInfo": "Click para más información",
"LabelClickToUseCurrentValue": "Haz clic para utilizar el valor actual",
"LabelClosePlayer": "Cerrar reproductor", "LabelClosePlayer": "Cerrar reproductor",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Colapsar serie", "LabelCollapseSeries": "Colapsar serie",
@@ -303,12 +312,25 @@
"LabelEmailSettingsTestAddress": "Probar Dirección", "LabelEmailSettingsTestAddress": "Probar Dirección",
"LabelEmbeddedCover": "Portada Integrada", "LabelEmbeddedCover": "Portada Integrada",
"LabelEnable": "Habilitar", "LabelEnable": "Habilitar",
"LabelEncodingBackupLocation": "Se guardará una copia de seguridad de tus archivos de audio originales en:",
"LabelEncodingChaptersNotEmbedded": "Los capítulos no se incrustan en los audiolibros multipista.",
"LabelEncodingClearItemCache": "Asegúrese de purgar periódicamente la caché.",
"LabelEncodingFinishedM4B": "El M4B terminado se colocará en su carpeta de audiolibros en:",
"LabelEncodingInfoEmbedded": "Los metadatos se integrarán en las pistas de audio dentro de la carpeta de audiolibros.",
"LabelEncodingStartedNavigation": "Una vez iniciada la tarea, puedes salir de esta página.",
"LabelEncodingTimeWarning": "La codificación puede tardar hasta 30 minutos.",
"LabelEncodingWarningAdvancedSettings": "Advertencia: No actualice esta configuración a menos que esté familiarizado con las opciones de codificación de ffmpeg.",
"LabelEncodingWatcherDisabled": "Si ha desactivado la supervisión de los archivos, deberá volver a escanear este audiolibro más adelante.",
"LabelEnd": "Fin", "LabelEnd": "Fin",
"LabelEndOfChapter": "Fin del capítulo", "LabelEndOfChapter": "Fin del capítulo",
"LabelEpisode": "Episodio", "LabelEpisode": "Episodio",
"LabelEpisodeNotLinkedToRssFeed": "Episodio no enlazado al feed RSS",
"LabelEpisodeNumber": "Episodio #{0}",
"LabelEpisodeTitle": "Titulo de Episodio", "LabelEpisodeTitle": "Titulo de Episodio",
"LabelEpisodeType": "Tipo de Episodio", "LabelEpisodeType": "Tipo de Episodio",
"LabelEpisodeUrlFromRssFeed": "URL del episodio del feed RSS",
"LabelEpisodes": "Episodios", "LabelEpisodes": "Episodios",
"LabelEpisodic": "Episodios",
"LabelExample": "Ejemplo", "LabelExample": "Ejemplo",
"LabelExpandSeries": "Ampliar serie", "LabelExpandSeries": "Ampliar serie",
"LabelExpandSubSeries": "Expandir la subserie", "LabelExpandSubSeries": "Expandir la subserie",
@@ -336,6 +358,7 @@
"LabelFontScale": "Tamaño de fuente", "LabelFontScale": "Tamaño de fuente",
"LabelFontStrikethrough": "Tachado", "LabelFontStrikethrough": "Tachado",
"LabelFormat": "Formato", "LabelFormat": "Formato",
"LabelFull": "Completo",
"LabelGenre": "Genero", "LabelGenre": "Genero",
"LabelGenres": "Géneros", "LabelGenres": "Géneros",
"LabelHardDeleteFile": "Eliminar Definitivamente", "LabelHardDeleteFile": "Eliminar Definitivamente",
@@ -391,6 +414,7 @@
"LabelLowestPriority": "Menor prioridad", "LabelLowestPriority": "Menor prioridad",
"LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por", "LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por",
"LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO", "LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO",
"LabelMaxEpisodesToDownload": "Número máximo # de episodios para descargar. Usa 0 para descargar una cantidad ilimitada.",
"LabelMediaPlayer": "Reproductor de Medios", "LabelMediaPlayer": "Reproductor de Medios",
"LabelMediaType": "Tipo de multimedia", "LabelMediaType": "Tipo de multimedia",
"LabelMetaTag": "Metaetiqueta", "LabelMetaTag": "Metaetiqueta",
@@ -465,7 +489,7 @@
"LabelPubDate": "Fecha de publicación", "LabelPubDate": "Fecha de publicación",
"LabelPublishYear": "Año de publicación", "LabelPublishYear": "Año de publicación",
"LabelPublishedDate": "Publicado {0}", "LabelPublishedDate": "Publicado {0}",
"LabelPublishedDecade": "Una década de publicaciones", "LabelPublishedDecade": "Década de publicación",
"LabelPublishedDecades": "Décadas publicadas", "LabelPublishedDecades": "Décadas publicadas",
"LabelPublisher": "Editor", "LabelPublisher": "Editor",
"LabelPublishers": "Editores", "LabelPublishers": "Editores",
@@ -501,6 +525,7 @@
"LabelSeries": "Series", "LabelSeries": "Series",
"LabelSeriesName": "Nombre de la Serie", "LabelSeriesName": "Nombre de la Serie",
"LabelSeriesProgress": "Progreso de la Serie", "LabelSeriesProgress": "Progreso de la Serie",
"LabelServerLogLevel": "Nivel de registro del servidor",
"LabelServerYearReview": "Resumen del año del servidor ({0})", "LabelServerYearReview": "Resumen del año del servidor ({0})",
"LabelSetEbookAsPrimary": "Establecer como primario", "LabelSetEbookAsPrimary": "Establecer como primario",
"LabelSetEbookAsSupplementary": "Establecer como suplementario", "LabelSetEbookAsSupplementary": "Establecer como suplementario",
@@ -596,6 +621,7 @@
"LabelTitle": "Título", "LabelTitle": "Título",
"LabelToolsEmbedMetadata": "Incrustar Metadatos", "LabelToolsEmbedMetadata": "Incrustar Metadatos",
"LabelToolsEmbedMetadataDescription": "Incrusta metadatos en los archivos de audio, incluyendo la portada y capítulos.", "LabelToolsEmbedMetadataDescription": "Incrusta metadatos en los archivos de audio, incluyendo la portada y capítulos.",
"LabelToolsM4bEncoder": "Codificador M4B",
"LabelToolsMakeM4b": "Hacer Archivo de Audiolibro M4B", "LabelToolsMakeM4b": "Hacer Archivo de Audiolibro M4B",
"LabelToolsMakeM4bDescription": "Generar archivo de audiolibro .M4B con metadatos, imágenes de portada y capítulos incorporados.", "LabelToolsMakeM4bDescription": "Generar archivo de audiolibro .M4B con metadatos, imágenes de portada y capítulos incorporados.",
"LabelToolsSplitM4b": "Dividir M4B en Archivos MP3", "LabelToolsSplitM4b": "Dividir M4B en Archivos MP3",
@@ -621,6 +647,7 @@
"LabelUploaderDragAndDrop": "Arrastre y suelte archivos o carpetas", "LabelUploaderDragAndDrop": "Arrastre y suelte archivos o carpetas",
"LabelUploaderDropFiles": "Suelte los Archivos", "LabelUploaderDropFiles": "Suelte los Archivos",
"LabelUploaderItemFetchMetadataHelp": "Buscar título, autor y series automáticamente", "LabelUploaderItemFetchMetadataHelp": "Buscar título, autor y series automáticamente",
"LabelUseAdvancedOptions": "Usar opciones avanzadas",
"LabelUseChapterTrack": "Usar pista por capitulo", "LabelUseChapterTrack": "Usar pista por capitulo",
"LabelUseFullTrack": "Usar pista completa", "LabelUseFullTrack": "Usar pista completa",
"LabelUser": "Usuario", "LabelUser": "Usuario",
@@ -669,6 +696,7 @@
"MessageConfirmDeleteMetadataProvider": "¿Estás seguro de que deseas eliminar el proveedor de metadatos personalizado \"{0}\"?", "MessageConfirmDeleteMetadataProvider": "¿Estás seguro de que deseas eliminar el proveedor de metadatos personalizado \"{0}\"?",
"MessageConfirmDeleteNotification": "¿Estás seguro de que deseas eliminar esta notificación?", "MessageConfirmDeleteNotification": "¿Estás seguro de que deseas eliminar esta notificación?",
"MessageConfirmDeleteSession": "¿Está seguro de que desea eliminar esta sesión?", "MessageConfirmDeleteSession": "¿Está seguro de que desea eliminar esta sesión?",
"MessageConfirmEmbedMetadataInAudioFiles": "¿Está seguro de que desea incrustar metadatos en {0} archivos de audio?",
"MessageConfirmForceReScan": "¿Está seguro de que desea forzar un re-escaneo?", "MessageConfirmForceReScan": "¿Está seguro de que desea forzar un re-escaneo?",
"MessageConfirmMarkAllEpisodesFinished": "¿Está seguro de que desea marcar todos los episodios como terminados?", "MessageConfirmMarkAllEpisodesFinished": "¿Está seguro de que desea marcar todos los episodios como terminados?",
"MessageConfirmMarkAllEpisodesNotFinished": "¿Está seguro de que desea marcar todos los episodios como no terminados?", "MessageConfirmMarkAllEpisodesNotFinished": "¿Está seguro de que desea marcar todos los episodios como no terminados?",
@@ -702,6 +730,7 @@
"MessageDragFilesIntoTrackOrder": "Arrastra los archivos al orden correcto de las pistas", "MessageDragFilesIntoTrackOrder": "Arrastra los archivos al orden correcto de las pistas",
"MessageEmbedFailed": "¡Error al insertar!", "MessageEmbedFailed": "¡Error al insertar!",
"MessageEmbedFinished": "Incrustación Terminada!", "MessageEmbedFinished": "Incrustación Terminada!",
"MessageEmbedQueue": "En cola para incrustar metadatos ({0} en cola)",
"MessageEpisodesQueuedForDownload": "{0} Episodio(s) en cola para descargar", "MessageEpisodesQueuedForDownload": "{0} Episodio(s) en cola para descargar",
"MessageEreaderDevices": "Para garantizar la entrega de libros electrónicos, es posible que tenga que agregar la dirección de correo electrónico anterior como remitente válido para cada dispositivo enumerado a continuación.", "MessageEreaderDevices": "Para garantizar la entrega de libros electrónicos, es posible que tenga que agregar la dirección de correo electrónico anterior como remitente válido para cada dispositivo enumerado a continuación.",
"MessageFeedURLWillBe": "URL de la fuente será {0}", "MessageFeedURLWillBe": "URL de la fuente será {0}",
@@ -746,6 +775,7 @@
"MessageNoLogs": "No hay logs", "MessageNoLogs": "No hay logs",
"MessageNoMediaProgress": "Multimedia sin Progreso", "MessageNoMediaProgress": "Multimedia sin Progreso",
"MessageNoNotifications": "Ninguna Notificación", "MessageNoNotifications": "Ninguna Notificación",
"MessageNoPodcastFeed": "Podcast no válido: Sin feed",
"MessageNoPodcastsFound": "Ningún podcast encontrado", "MessageNoPodcastsFound": "Ningún podcast encontrado",
"MessageNoResults": "Sin Resultados", "MessageNoResults": "Sin Resultados",
"MessageNoSearchResultsFor": "No hay resultados para la búsqueda \"{0}\"", "MessageNoSearchResultsFor": "No hay resultados para la búsqueda \"{0}\"",
@@ -762,6 +792,9 @@
"MessagePlaylistCreateFromCollection": "Crear una lista de reproducción a partir de una colección", "MessagePlaylistCreateFromCollection": "Crear una lista de reproducción a partir de una colección",
"MessagePleaseWait": "Por favor, espera...", "MessagePleaseWait": "Por favor, espera...",
"MessagePodcastHasNoRSSFeedForMatching": "El podcast no tiene una URL de fuente RSS que pueda usar", "MessagePodcastHasNoRSSFeedForMatching": "El podcast no tiene una URL de fuente RSS que pueda usar",
"MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS",
"MessageQuickEmbedInProgress": "Integración rápida en proceso",
"MessageQuickEmbedQueue": "En cola para inserción rápida ({0} en cola)",
"MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la opción \"Preferir Metadatos Encontrados\" del servidor esté habilitada.", "MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la opción \"Preferir Metadatos Encontrados\" del servidor esté habilitada.",
"MessageRemoveChapter": "Remover capítulos", "MessageRemoveChapter": "Remover capítulos",
"MessageRemoveEpisodes": "Remover {0} episodio(s)", "MessageRemoveEpisodes": "Remover {0} episodio(s)",
@@ -804,6 +837,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Podcast ya existe en la ruta", "MessageTaskOpmlImportFeedPodcastExists": "Podcast ya existe en la ruta",
"MessageTaskOpmlImportFeedPodcastFailed": "Error al crear podcast", "MessageTaskOpmlImportFeedPodcastFailed": "Error al crear podcast",
"MessageTaskOpmlImportFinished": "Añadido {0} podcasts", "MessageTaskOpmlImportFinished": "Añadido {0} podcasts",
"MessageTaskOpmlParseFailed": "No se pudo analizar el archivo OPML",
"MessageTaskOpmlParseFastFail": "No se encontró la etiqueta <opml> del archivo OPML no válido O no se encontró la etiqueta <outline>",
"MessageTaskOpmlParseNoneFound": "No se encontraron fuentes en el archivo OPML",
"MessageTaskScanItemsAdded": "{0} añadido", "MessageTaskScanItemsAdded": "{0} añadido",
"MessageTaskScanItemsMissing": "Falta {0}", "MessageTaskScanItemsMissing": "Falta {0}",
"MessageTaskScanItemsUpdated": "{0} actualizado", "MessageTaskScanItemsUpdated": "{0} actualizado",
@@ -828,6 +864,10 @@
"NoteUploaderFoldersWithMediaFiles": "Las carpetas con archivos multimedia se manejarán como elementos separados en la biblioteca.", "NoteUploaderFoldersWithMediaFiles": "Las carpetas con archivos multimedia se manejarán como elementos separados en la biblioteca.",
"NoteUploaderOnlyAudioFiles": "Si sube solamente archivos de audio, cada archivo se manejará como un audiolibro por separado.", "NoteUploaderOnlyAudioFiles": "Si sube solamente archivos de audio, cada archivo se manejará como un audiolibro por separado.",
"NoteUploaderUnsupportedFiles": "Se ignorarán los archivos no soportados. Al elegir o arrastrar una carpeta, los archivos que no estén dentro de una subcarpeta serán ignorados.", "NoteUploaderUnsupportedFiles": "Se ignorarán los archivos no soportados. Al elegir o arrastrar una carpeta, los archivos que no estén dentro de una subcarpeta serán ignorados.",
"NotificationOnBackupCompletedDescription": "Se activa cuando se completa una copia de seguridad",
"NotificationOnBackupFailedDescription": "Se activa cuando falla una copia de seguridad",
"NotificationOnEpisodeDownloadedDescription": "Se activa cuando se descarga automáticamente un episodio de un podcast",
"NotificationOnTestDescription": "Evento para probar el sistema de notificaciones",
"PlaceholderNewCollection": "Nuevo nombre de la colección", "PlaceholderNewCollection": "Nuevo nombre de la colección",
"PlaceholderNewFolderPath": "Nueva ruta de carpeta", "PlaceholderNewFolderPath": "Nueva ruta de carpeta",
"PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción", "PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción",
+32
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Purger le cache des éléments", "ButtonPurgeItemsCache": "Purger le cache des éléments",
"ButtonQueueAddItem": "Ajouter à la liste de lecture", "ButtonQueueAddItem": "Ajouter à la liste de lecture",
"ButtonQueueRemoveItem": "Supprimer de la liste de lecture", "ButtonQueueRemoveItem": "Supprimer de la liste de lecture",
"ButtonQuickEmbed": "Intégration rapide",
"ButtonQuickEmbedMetadata": "Ajouter rapidement des métadonnées", "ButtonQuickEmbedMetadata": "Ajouter rapidement des métadonnées",
"ButtonQuickMatch": "Recherche rapide", "ButtonQuickMatch": "Recherche rapide",
"ButtonReScan": "Nouvelle analyse", "ButtonReScan": "Nouvelle analyse",
@@ -225,6 +226,9 @@
"LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités", "LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités",
"LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque", "LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque",
"LabelAppend": "Ajouter", "LabelAppend": "Ajouter",
"LabelAudioBitrate": "Débit audio (par exemple 128k)",
"LabelAudioChannels": "Canaux audio (1 ou 2)",
"LabelAudioCodec": "Codec audio",
"LabelAuthor": "Auteur", "LabelAuthor": "Auteur",
"LabelAuthorFirstLast": "Auteur (Prénom Nom)", "LabelAuthorFirstLast": "Auteur (Prénom Nom)",
"LabelAuthorLastFirst": "Auteur (Nom, Prénom)", "LabelAuthorLastFirst": "Auteur (Nom, Prénom)",
@@ -237,6 +241,7 @@
"LabelAutoRegister": "Enregistrement automatique", "LabelAutoRegister": "Enregistrement automatique",
"LabelAutoRegisterDescription": "Créer automatiquement de nouveaux utilisateurs après la connexion", "LabelAutoRegisterDescription": "Créer automatiquement de nouveaux utilisateurs après la connexion",
"LabelBackToUser": "Retour à lutilisateur", "LabelBackToUser": "Retour à lutilisateur",
"LabelBackupAudioFiles": "Sauvegarder les fichiers audio",
"LabelBackupLocation": "Emplacement de la sauvegarde", "LabelBackupLocation": "Emplacement de la sauvegarde",
"LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques", "LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques",
"LabelBackupsEnableAutomaticBackupsHelp": "Sauvegardes enregistrées dans /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Sauvegardes enregistrées dans /metadata/backups",
@@ -245,11 +250,13 @@
"LabelBackupsNumberToKeep": "Nombre de sauvegardes à conserver", "LabelBackupsNumberToKeep": "Nombre de sauvegardes à conserver",
"LabelBackupsNumberToKeepHelp": "Seule une sauvegarde sera supprimée à la fois. Si vous avez déjà plus de sauvegardes à effacer, vous devez les supprimer manuellement.", "LabelBackupsNumberToKeepHelp": "Seule une sauvegarde sera supprimée à la fois. Si vous avez déjà plus de sauvegardes à effacer, vous devez les supprimer manuellement.",
"LabelBitrate": "Débit binaire", "LabelBitrate": "Débit binaire",
"LabelBonus": "Bonus",
"LabelBooks": "Livres", "LabelBooks": "Livres",
"LabelButtonText": "Texte du bouton", "LabelButtonText": "Texte du bouton",
"LabelByAuthor": "par {0}", "LabelByAuthor": "par {0}",
"LabelChangePassword": "Modifier le mot de passe", "LabelChangePassword": "Modifier le mot de passe",
"LabelChannels": "Canaux", "LabelChannels": "Canaux",
"LabelChapterCount": "{0} Chapitres",
"LabelChapterTitle": "Titre du chapitre", "LabelChapterTitle": "Titre du chapitre",
"LabelChapters": "Chapitres", "LabelChapters": "Chapitres",
"LabelChaptersFound": "chapitres trouvés", "LabelChaptersFound": "chapitres trouvés",
@@ -303,6 +310,15 @@
"LabelEmailSettingsTestAddress": "Adresse de test", "LabelEmailSettingsTestAddress": "Adresse de test",
"LabelEmbeddedCover": "Couverture du livre intégrée", "LabelEmbeddedCover": "Couverture du livre intégrée",
"LabelEnable": "Activer", "LabelEnable": "Activer",
"LabelEncodingBackupLocation": "Une sauvegarde de vos fichiers audio originaux sera stockée dans :",
"LabelEncodingChaptersNotEmbedded": "Les chapitres ne sont pas intégrés dans les livres audio multipistes.",
"LabelEncodingClearItemCache": "Assurez-vous de purger périodiquement le cache des éléments.",
"LabelEncodingFinishedM4B": "Le fichier M4B terminé sera placé dans votre dossier de livre audio à l'adresse suivante :",
"LabelEncodingInfoEmbedded": "Les métadonnées seront intégrées dans les pistes audio de votre dossier de livre audio.",
"LabelEncodingStartedNavigation": "Une fois la tâche démarrée, vous pouvez quitter cette page.",
"LabelEncodingTimeWarning": "Lencodage peut prendre jusqu’à 30 minutes.",
"LabelEncodingWarningAdvancedSettings": "Avertissement : ne mettez pas à jour ces paramètres à moins que vous ne soyez familier avec les options d'encodage « ffmpeg ».",
"LabelEncodingWatcherDisabled": "Si l'observateur est désactivé, vous devrez ensuite réanalyser ce livre audio.",
"LabelEnd": "Fin", "LabelEnd": "Fin",
"LabelEndOfChapter": "Fin du chapitre", "LabelEndOfChapter": "Fin du chapitre",
"LabelEpisode": "Épisode", "LabelEpisode": "Épisode",
@@ -501,6 +517,7 @@
"LabelSeries": "Séries", "LabelSeries": "Séries",
"LabelSeriesName": "Nom de la série", "LabelSeriesName": "Nom de la série",
"LabelSeriesProgress": "Progression de séries", "LabelSeriesProgress": "Progression de séries",
"LabelServerLogLevel": "Niveau de journalisation du serveur",
"LabelServerYearReview": "Bilan de lannée du serveur ({0})", "LabelServerYearReview": "Bilan de lannée du serveur ({0})",
"LabelSetEbookAsPrimary": "Définir comme principale", "LabelSetEbookAsPrimary": "Définir comme principale",
"LabelSetEbookAsSupplementary": "Définir comme supplémentaire", "LabelSetEbookAsSupplementary": "Définir comme supplémentaire",
@@ -596,6 +613,7 @@
"LabelTitle": "Titre", "LabelTitle": "Titre",
"LabelToolsEmbedMetadata": "Métadonnées intégrées", "LabelToolsEmbedMetadata": "Métadonnées intégrées",
"LabelToolsEmbedMetadataDescription": "Intègre les métadonnées au fichier audio avec la couverture et les chapitres.", "LabelToolsEmbedMetadataDescription": "Intègre les métadonnées au fichier audio avec la couverture et les chapitres.",
"LabelToolsM4bEncoder": "Encodeur M4B",
"LabelToolsMakeM4b": "Créer un fichier livre audio M4B", "LabelToolsMakeM4b": "Créer un fichier livre audio M4B",
"LabelToolsMakeM4bDescription": "Générer un fichier de livre audio .M4B avec des métadonnées intégrées, une image de couverture et des chapitres.", "LabelToolsMakeM4bDescription": "Générer un fichier de livre audio .M4B avec des métadonnées intégrées, une image de couverture et des chapitres.",
"LabelToolsSplitM4b": "Scinde le fichier M4B en fichiers MP3", "LabelToolsSplitM4b": "Scinde le fichier M4B en fichiers MP3",
@@ -621,6 +639,7 @@
"LabelUploaderDragAndDrop": "Glisser et déposer des fichiers ou dossiers", "LabelUploaderDragAndDrop": "Glisser et déposer des fichiers ou dossiers",
"LabelUploaderDropFiles": "Déposer des fichiers", "LabelUploaderDropFiles": "Déposer des fichiers",
"LabelUploaderItemFetchMetadataHelp": "Récupérer automatiquement le titre, lauteur et la série", "LabelUploaderItemFetchMetadataHelp": "Récupérer automatiquement le titre, lauteur et la série",
"LabelUseAdvancedOptions": "Utiliser les options avancées",
"LabelUseChapterTrack": "Utiliser la piste du chapitre", "LabelUseChapterTrack": "Utiliser la piste du chapitre",
"LabelUseFullTrack": "Utiliser la piste complète", "LabelUseFullTrack": "Utiliser la piste complète",
"LabelUser": "Utilisateur", "LabelUser": "Utilisateur",
@@ -669,6 +688,7 @@
"MessageConfirmDeleteMetadataProvider": "Êtes-vous sûr·e de vouloir supprimer le fournisseur de métadonnées personnalisées « {0} » ?", "MessageConfirmDeleteMetadataProvider": "Êtes-vous sûr·e de vouloir supprimer le fournisseur de métadonnées personnalisées « {0} » ?",
"MessageConfirmDeleteNotification": "Êtes-vous sûr·e de vouloir supprimer cette notification?", "MessageConfirmDeleteNotification": "Êtes-vous sûr·e de vouloir supprimer cette notification?",
"MessageConfirmDeleteSession": "Êtes-vous sûr·e de vouloir supprimer cette session?", "MessageConfirmDeleteSession": "Êtes-vous sûr·e de vouloir supprimer cette session?",
"MessageConfirmEmbedMetadataInAudioFiles": "Souhaitez-vous vraiment intégrer des métadonnées dans {0} fichiers audio?",
"MessageConfirmForceReScan": "Êtes-vous sûr·e de vouloir lancer une analyse forcée?", "MessageConfirmForceReScan": "Êtes-vous sûr·e de vouloir lancer une analyse forcée?",
"MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr·e de marquer tous les épisodes comme terminés?", "MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr·e de marquer tous les épisodes comme terminés?",
"MessageConfirmMarkAllEpisodesNotFinished": "Êtes-vous sûr·e de vouloir marquer tous les épisodes comme non terminés?", "MessageConfirmMarkAllEpisodesNotFinished": "Êtes-vous sûr·e de vouloir marquer tous les épisodes comme non terminés?",
@@ -702,6 +722,7 @@
"MessageDragFilesIntoTrackOrder": "Faites glisser les fichiers dans lordre correct des pistes", "MessageDragFilesIntoTrackOrder": "Faites glisser les fichiers dans lordre correct des pistes",
"MessageEmbedFailed": "Échec de lintégration!", "MessageEmbedFailed": "Échec de lintégration!",
"MessageEmbedFinished": "Intégration terminée !", "MessageEmbedFinished": "Intégration terminée !",
"MessageEmbedQueue": "En file d'attente pour l'intégration des métadonnées ({0} dans la file d'attente)",
"MessageEpisodesQueuedForDownload": "{0} épisode(s) mis en file pour téléchargement", "MessageEpisodesQueuedForDownload": "{0} épisode(s) mis en file pour téléchargement",
"MessageEreaderDevices": "Pour garantir lenvoi des livres électroniques, vous devrez peut-être ajouter le courriel ci-dessus comme expéditeur valide pour chaque appareil répertorié ci-dessous.", "MessageEreaderDevices": "Pour garantir lenvoi des livres électroniques, vous devrez peut-être ajouter le courriel ci-dessus comme expéditeur valide pour chaque appareil répertorié ci-dessous.",
"MessageFeedURLWillBe": "LURL du flux sera {0}", "MessageFeedURLWillBe": "LURL du flux sera {0}",
@@ -746,6 +767,7 @@
"MessageNoLogs": "Aucun journaux", "MessageNoLogs": "Aucun journaux",
"MessageNoMediaProgress": "Aucun média en cours", "MessageNoMediaProgress": "Aucun média en cours",
"MessageNoNotifications": "Aucune notification", "MessageNoNotifications": "Aucune notification",
"MessageNoPodcastFeed": "Podcast invalide : pas de flux",
"MessageNoPodcastsFound": "Aucun podcast trouvé", "MessageNoPodcastsFound": "Aucun podcast trouvé",
"MessageNoResults": "Aucun résultat", "MessageNoResults": "Aucun résultat",
"MessageNoSearchResultsFor": "Aucun résultat pour la recherche « {0} »", "MessageNoSearchResultsFor": "Aucun résultat pour la recherche « {0} »",
@@ -762,6 +784,9 @@
"MessagePlaylistCreateFromCollection": "Créer une liste de lecture depuis la collection", "MessagePlaylistCreateFromCollection": "Créer une liste de lecture depuis la collection",
"MessagePleaseWait": "Merci de patienter…", "MessagePleaseWait": "Merci de patienter…",
"MessagePodcastHasNoRSSFeedForMatching": "Le Podcast na pas dURL de flux RSS à utiliser pour la correspondance", "MessagePodcastHasNoRSSFeedForMatching": "Le Podcast na pas dURL de flux RSS à utiliser pour la correspondance",
"MessagePodcastSearchField": "Saisissez le terme de recherche ou l'URL du flux RSS",
"MessageQuickEmbedInProgress": "Intégration rapide en cours",
"MessageQuickEmbedQueue": "En file d'attente pour une intégration rapide ({0} dans la file d'attente)",
"MessageQuickMatchDescription": "Renseigne les détails manquants ainsi que la couverture avec la première correspondance de « {0} ». N’écrase pas les données présentes à moins que le paramètre « Préférer les Métadonnées par correspondance » soit activé.", "MessageQuickMatchDescription": "Renseigne les détails manquants ainsi que la couverture avec la première correspondance de « {0} ». N’écrase pas les données présentes à moins que le paramètre « Préférer les Métadonnées par correspondance » soit activé.",
"MessageRemoveChapter": "Supprimer le chapitre", "MessageRemoveChapter": "Supprimer le chapitre",
"MessageRemoveEpisodes": "Suppression de {0} épisode(s)", "MessageRemoveEpisodes": "Suppression de {0} épisode(s)",
@@ -804,6 +829,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Le podcast existe déjà à cet emplacement", "MessageTaskOpmlImportFeedPodcastExists": "Le podcast existe déjà à cet emplacement",
"MessageTaskOpmlImportFeedPodcastFailed": "Échec de la création du podcast", "MessageTaskOpmlImportFeedPodcastFailed": "Échec de la création du podcast",
"MessageTaskOpmlImportFinished": "Ajout de {0} podcasts", "MessageTaskOpmlImportFinished": "Ajout de {0} podcasts",
"MessageTaskOpmlParseFailed": "Échec de l'analyse du fichier OPML",
"MessageTaskOpmlParseFastFail": "Balise <opml> de fichier OPML non valide introuvable OU une balise <outline> na pas été trouvée",
"MessageTaskOpmlParseNoneFound": "Aucun flux trouvé dans le fichier OPML",
"MessageTaskScanItemsAdded": "{0} ajouté", "MessageTaskScanItemsAdded": "{0} ajouté",
"MessageTaskScanItemsMissing": "{0} manquant", "MessageTaskScanItemsMissing": "{0} manquant",
"MessageTaskScanItemsUpdated": "{0} mis à jour", "MessageTaskScanItemsUpdated": "{0} mis à jour",
@@ -828,6 +856,10 @@
"NoteUploaderFoldersWithMediaFiles": "Les dossiers contenant des fichiers multimédias seront traités comme des éléments distincts de la bibliothèque.", "NoteUploaderFoldersWithMediaFiles": "Les dossiers contenant des fichiers multimédias seront traités comme des éléments distincts de la bibliothèque.",
"NoteUploaderOnlyAudioFiles": "Si vous téléversez uniquement des fichiers audio, chaque fichier audio sera traité comme un livre audio distinct.", "NoteUploaderOnlyAudioFiles": "Si vous téléversez uniquement des fichiers audio, chaque fichier audio sera traité comme un livre audio distinct.",
"NoteUploaderUnsupportedFiles": "Les fichiers non pris en charge sont ignorés. Lorsque vous choisissez ou déposez un dossier, les autres fichiers qui ne sont pas dans un dossier d’élément sont ignorés.", "NoteUploaderUnsupportedFiles": "Les fichiers non pris en charge sont ignorés. Lorsque vous choisissez ou déposez un dossier, les autres fichiers qui ne sont pas dans un dossier d’élément sont ignorés.",
"NotificationOnBackupCompletedDescription": "Déclenché lorsquune sauvegarde est terminée",
"NotificationOnBackupFailedDescription": "Déclenché lorsqu'une sauvegarde échoue",
"NotificationOnEpisodeDownloadedDescription": "Déclenché lorsquun épisode de podcast est téléchargé automatiquement",
"NotificationOnTestDescription": "Événement pour tester le système de notification",
"PlaceholderNewCollection": "Nom de la nouvelle collection", "PlaceholderNewCollection": "Nom de la nouvelle collection",
"PlaceholderNewFolderPath": "Nouveau chemin de dossier", "PlaceholderNewFolderPath": "Nouveau chemin de dossier",
"PlaceholderNewPlaylist": "Nouveau nom de liste de lecture", "PlaceholderNewPlaylist": "Nouveau nom de liste de lecture",
+91 -13
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Isprazni predmemoriju stavki", "ButtonPurgeItemsCache": "Isprazni predmemoriju stavki",
"ButtonQueueAddItem": "Dodaj u red", "ButtonQueueAddItem": "Dodaj u red",
"ButtonQueueRemoveItem": "Ukloni iz reda", "ButtonQueueRemoveItem": "Ukloni iz reda",
"ButtonQuickEmbed": "Brzo ugrađivanje",
"ButtonQuickEmbedMetadata": "Brzo ugrađivanje meta-podataka", "ButtonQuickEmbedMetadata": "Brzo ugrađivanje meta-podataka",
"ButtonQuickMatch": "Brzo prepoznavanje", "ButtonQuickMatch": "Brzo prepoznavanje",
"ButtonReScan": "Ponovno skeniraj", "ButtonReScan": "Ponovno skeniraj",
@@ -81,7 +82,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Ukloni seriju iz Nastavi seriju", "ButtonRemoveSeriesFromContinueSeries": "Ukloni seriju iz Nastavi seriju",
"ButtonReset": "Poništi", "ButtonReset": "Poništi",
"ButtonResetToDefault": "Vrati na početne postavke", "ButtonResetToDefault": "Vrati na početne postavke",
"ButtonRestore": "Povrati", "ButtonRestore": "Vraćanje",
"ButtonSave": "Spremi", "ButtonSave": "Spremi",
"ButtonSaveAndClose": "Spremi i zatvori", "ButtonSaveAndClose": "Spremi i zatvori",
"ButtonSaveTracklist": "Spremi popis zvučnih zapisa", "ButtonSaveTracklist": "Spremi popis zvučnih zapisa",
@@ -162,6 +163,7 @@
"HeaderNotificationUpdate": "Ažuriraj obavijest", "HeaderNotificationUpdate": "Ažuriraj obavijest",
"HeaderNotifications": "Obavijesti", "HeaderNotifications": "Obavijesti",
"HeaderOpenIDConnectAuthentication": "Prijava na OpenID Connect", "HeaderOpenIDConnectAuthentication": "Prijava na OpenID Connect",
"HeaderOpenListeningSessions": "Otvorene sesije slušanja",
"HeaderOpenRSSFeed": "Otvori RSS izvor", "HeaderOpenRSSFeed": "Otvori RSS izvor",
"HeaderOtherFiles": "Druge datoteke", "HeaderOtherFiles": "Druge datoteke",
"HeaderPasswordAuthentication": "Provjera autentičnosti zaporkom", "HeaderPasswordAuthentication": "Provjera autentičnosti zaporkom",
@@ -179,6 +181,7 @@
"HeaderRemoveEpisodes": "Ukloni {0} nastavaka", "HeaderRemoveEpisodes": "Ukloni {0} nastavaka",
"HeaderSavedMediaProgress": "Spremljen napredak medija", "HeaderSavedMediaProgress": "Spremljen napredak medija",
"HeaderSchedule": "Zakazivanje", "HeaderSchedule": "Zakazivanje",
"HeaderScheduleEpisodeDownloads": "Zakazivanje automatskog preuzimanja nastavaka",
"HeaderScheduleLibraryScans": "Zakaži automatsko skeniranje knjižnice", "HeaderScheduleLibraryScans": "Zakaži automatsko skeniranje knjižnice",
"HeaderSession": "Sesija", "HeaderSession": "Sesija",
"HeaderSetBackupSchedule": "Zakazivanje sigurnosne pohrane", "HeaderSetBackupSchedule": "Zakazivanje sigurnosne pohrane",
@@ -224,7 +227,11 @@
"LabelAllUsersExcludingGuests": "Svi korisnici osim gostiju", "LabelAllUsersExcludingGuests": "Svi korisnici osim gostiju",
"LabelAllUsersIncludingGuests": "Svi korisnici uključujući i goste", "LabelAllUsersIncludingGuests": "Svi korisnici uključujući i goste",
"LabelAlreadyInYourLibrary": "Već u vašoj knjižnici", "LabelAlreadyInYourLibrary": "Već u vašoj knjižnici",
"LabelApiToken": "API Token",
"LabelAppend": "Pridodaj", "LabelAppend": "Pridodaj",
"LabelAudioBitrate": "Kvaliteta zvučnog zapisa (npr. 128k)",
"LabelAudioChannels": "Broj zvučnih kanala (1 ili 2)",
"LabelAudioCodec": "Zvučni kodek",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Ime Prezime)", "LabelAuthorFirstLast": "Autor (Ime Prezime)",
"LabelAuthorLastFirst": "Autor (Prezime, Ime)", "LabelAuthorLastFirst": "Autor (Prezime, Ime)",
@@ -237,29 +244,33 @@
"LabelAutoRegister": "Automatska registracija", "LabelAutoRegister": "Automatska registracija",
"LabelAutoRegisterDescription": "Automatski izradi nove korisnike nakon prijave", "LabelAutoRegisterDescription": "Automatski izradi nove korisnike nakon prijave",
"LabelBackToUser": "Povratak na korisnika", "LabelBackToUser": "Povratak na korisnika",
"LabelBackupAudioFiles": "Sigurnosno kopiranje zvučnih datoteka",
"LabelBackupLocation": "Lokacija sigurnosnih kopija", "LabelBackupLocation": "Lokacija sigurnosnih kopija",
"LabelBackupsEnableAutomaticBackups": "Uključi automatsku izradu sigurnosnih kopija", "LabelBackupsEnableAutomaticBackups": "Omogući automatsku izradu sigurnosnih kopija",
"LabelBackupsEnableAutomaticBackupsHelp": "Sigurnosne kopije spremaju se u /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Sigurnosne kopije spremaju se u /metadata/backups",
"LabelBackupsMaxBackupSize": "Maksimalna veličina sigurnosne kopije (u GB) (0 za neograničeno)", "LabelBackupsMaxBackupSize": "Maksimalna veličina sigurnosne kopije (u GB) (0 za neograničeno)",
"LabelBackupsMaxBackupSizeHelp": "U svrhu sprečavanja izrade krive konfiguracije, sigurnosne kopije neće se izraditi ako su veće od zadane veličine.", "LabelBackupsMaxBackupSizeHelp": "U svrhu sprečavanja izrade krive konfiguracije, sigurnosne kopije neće se izraditi ako su veće od zadane veličine.",
"LabelBackupsNumberToKeep": "Broj sigurnosnih kopija za čuvanje", "LabelBackupsNumberToKeep": "Broj sigurnosnih kopija za čuvanje",
"LabelBackupsNumberToKeepHelp": "Moguće je izbrisati samo jednu po jednu sigurnosnu kopiju, ako ih već imate više trebat ćete ih ručno ukloniti.", "LabelBackupsNumberToKeepHelp": "Moguće je izbrisati samo jednu po jednu sigurnosnu kopiju, ako ih već imate više trebat ćete ih ručno ukloniti.",
"LabelBitrate": "Protok", "LabelBitrate": "Protok",
"LabelBooks": "knjiga/e", "LabelBonus": "Bonus",
"LabelBooks": "Knjige",
"LabelButtonText": "Tekst gumba", "LabelButtonText": "Tekst gumba",
"LabelByAuthor": "po {0}", "LabelByAuthor": "autor: {0}",
"LabelChangePassword": "Promijeni zaporku", "LabelChangePassword": "Promijeni zaporku",
"LabelChannels": "Kanali", "LabelChannels": "Kanali",
"LabelChapterCount": "{0} Poglavlje/a",
"LabelChapterTitle": "Naslov poglavlja", "LabelChapterTitle": "Naslov poglavlja",
"LabelChapters": "Poglavlja", "LabelChapters": "Poglavlja",
"LabelChaptersFound": "poglavlja pronađeno", "LabelChaptersFound": "poglavlja pronađeno",
"LabelClickForMoreInfo": "Kliknite za više informacija", "LabelClickForMoreInfo": "Kliknite za više informacija",
"LabelClickToUseCurrentValue": "Kliknite za trenutnu vrijednost",
"LabelClosePlayer": "Zatvori reproduktor", "LabelClosePlayer": "Zatvori reproduktor",
"LabelCodec": "Kodek", "LabelCodec": "Kodek",
"LabelCollapseSeries": "Serijale prikaži sažeto", "LabelCollapseSeries": "Serijale prikaži sažeto",
"LabelCollapseSubSeries": "Podserijale prikaži sažeto", "LabelCollapseSubSeries": "Podserijale prikaži sažeto",
"LabelCollection": "Zbirka", "LabelCollection": "Zbirka",
"LabelCollections": "Zbirka/i", "LabelCollections": "Zbirke",
"LabelComplete": "Dovršeno", "LabelComplete": "Dovršeno",
"LabelConfirmPassword": "Potvrda zaporke", "LabelConfirmPassword": "Potvrda zaporke",
"LabelContinueListening": "Nastavi slušati", "LabelContinueListening": "Nastavi slušati",
@@ -303,12 +314,25 @@
"LabelEmailSettingsTestAddress": "Probna adresa", "LabelEmailSettingsTestAddress": "Probna adresa",
"LabelEmbeddedCover": "Ugrađena naslovnica", "LabelEmbeddedCover": "Ugrađena naslovnica",
"LabelEnable": "Omogući", "LabelEnable": "Omogući",
"LabelEncodingBackupLocation": "Sigurnosna kopija vaših izvornih zvučnih datoteka čuvat će se u mapi:",
"LabelEncodingChaptersNotEmbedded": "Poglavlja se ne ugrađuju u zvučne knjige koje se sastoje od više zvučnih zapisa.",
"LabelEncodingClearItemCache": "Svakako redovito praznite predmemoriju stavki.",
"LabelEncodingFinishedM4B": "Stvorene M4B datoteke spremit će se u vašu mapu sa zvučnim knjigama:",
"LabelEncodingInfoEmbedded": "Meta-podatci će se ugraditi u zvučne zapise u vašoj mapi sa zvučnim knjigama.",
"LabelEncodingStartedNavigation": "Nakon pokretanja zadatka možete napustiti ovu stranicu.",
"LabelEncodingTimeWarning": "Kodiranje može potrajati do 30 minuta.",
"LabelEncodingWarningAdvancedSettings": "Pažnja: Ne mijenjajte ove postavke ako niste temeljito upoznati s opcijama kodiranja u ffmpegu.",
"LabelEncodingWatcherDisabled": "Ako vam je onemogućeno praćenje mape, ovu ćete zvučnu knjigu poslije morati ponovno skenirati.",
"LabelEnd": "Kraj", "LabelEnd": "Kraj",
"LabelEndOfChapter": "Kraj poglavlja", "LabelEndOfChapter": "Kraj poglavlja",
"LabelEpisode": "Nastavak", "LabelEpisode": "Nastavak",
"LabelEpisodeNotLinkedToRssFeed": "Nastavak nije povezan s RSS izvorom",
"LabelEpisodeNumber": "{0}. nastavak",
"LabelEpisodeTitle": "Naslov nastavka", "LabelEpisodeTitle": "Naslov nastavka",
"LabelEpisodeType": "Vrsta nastavka", "LabelEpisodeType": "Vrsta nastavka",
"LabelEpisodeUrlFromRssFeed": "URL nastavka iz RSS izvora",
"LabelEpisodes": "Nastavci", "LabelEpisodes": "Nastavci",
"LabelEpisodic": "U nastavcima",
"LabelExample": "Primjer", "LabelExample": "Primjer",
"LabelExpandSeries": "Serijal prikaži prošireno", "LabelExpandSeries": "Serijal prikaži prošireno",
"LabelExpandSubSeries": "Podserijal prikaži prošireno", "LabelExpandSubSeries": "Podserijal prikaži prošireno",
@@ -336,6 +360,7 @@
"LabelFontScale": "Veličina slova", "LabelFontScale": "Veličina slova",
"LabelFontStrikethrough": "Precrtano", "LabelFontStrikethrough": "Precrtano",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelFull": "Cijeli",
"LabelGenre": "Žanr", "LabelGenre": "Žanr",
"LabelGenres": "Žanrovi", "LabelGenres": "Žanrovi",
"LabelHardDeleteFile": "Obriši datoteku zauvijek", "LabelHardDeleteFile": "Obriši datoteku zauvijek",
@@ -391,6 +416,10 @@
"LabelLowestPriority": "Najniži prioritet", "LabelLowestPriority": "Najniži prioritet",
"LabelMatchExistingUsersBy": "Prepoznaj postojeće korisnike pomoću", "LabelMatchExistingUsersBy": "Prepoznaj postojeće korisnike pomoću",
"LabelMatchExistingUsersByDescription": "Rabi se za povezivanje postojećih korisnika. Nakon što se spoje, korisnike se prepoznaje temeljem jedinstvene oznake vašeg pružatelja SSO usluga", "LabelMatchExistingUsersByDescription": "Rabi se za povezivanje postojećih korisnika. Nakon što se spoje, korisnike se prepoznaje temeljem jedinstvene oznake vašeg pružatelja SSO usluga",
"LabelMaxEpisodesToDownload": "Najveći broj nastavaka za preuzimanje. 0 za neograničeno.",
"LabelMaxEpisodesToDownloadPerCheck": "Najviše novih nastavaka za preuzimanje po provjeri",
"LabelMaxEpisodesToKeep": "Najviše nastavaka za čuvanje",
"LabelMaxEpisodesToKeepHelp": "Ako je vrijednost 0, nema ograničenja broja. Nakon automatskog preuzimanja novog nastavka ova funkcija briše najstariji nastavak ako ih ima više od zadanog broja. Ovo briše samo jedan nastavak po novom preuzetom nastavku.",
"LabelMediaPlayer": "Reproduktor medijskih sadržaja", "LabelMediaPlayer": "Reproduktor medijskih sadržaja",
"LabelMediaType": "Vrsta medija", "LabelMediaType": "Vrsta medija",
"LabelMetaTag": "Meta oznaka", "LabelMetaTag": "Meta oznaka",
@@ -413,7 +442,7 @@
"LabelNewPassword": "Nova zaporka", "LabelNewPassword": "Nova zaporka",
"LabelNewestAuthors": "Najnoviji autori", "LabelNewestAuthors": "Najnoviji autori",
"LabelNewestEpisodes": "Najnovije epizode", "LabelNewestEpisodes": "Najnovije epizode",
"LabelNextBackupDate": "Sljedeće izrada sigurnosne kopije", "LabelNextBackupDate": "Sljedeća izrada sigurnosne kopije",
"LabelNextScheduledRun": "Sljedeće zakazano izvođenje", "LabelNextScheduledRun": "Sljedeće zakazano izvođenje",
"LabelNoCustomMetadataProviders": "Nema prilagođenih pružatelja meta-podataka", "LabelNoCustomMetadataProviders": "Nema prilagođenih pružatelja meta-podataka",
"LabelNoEpisodesSelected": "Nema odabranih nastavaka", "LabelNoEpisodesSelected": "Nema odabranih nastavaka",
@@ -436,12 +465,14 @@
"LabelOpenIDGroupClaimDescription": "Naziv OpenID zahtjeva koji sadrži popis korisnikovih grupa. Često se naziva <code>groups</code>. <b>Ako se konfigurira</b>, aplikacija će automatski dodijeliti uloge temeljem korisnikovih članstava u grupama, pod uvjetom da se iste zovu 'admin', 'user' ili 'guest' u zahtjevu (ne razlikuju se velika i mala slova). Zahtjev treba sadržavati popis i ako je korisnik član više grupa, aplikacija će dodijeliti ulogu koja odgovara najvišoj razini pristupa. Ukoliko se niti jedna grupa ne podudara, pristup će biti onemogućen.", "LabelOpenIDGroupClaimDescription": "Naziv OpenID zahtjeva koji sadrži popis korisnikovih grupa. Često se naziva <code>groups</code>. <b>Ako se konfigurira</b>, aplikacija će automatski dodijeliti uloge temeljem korisnikovih članstava u grupama, pod uvjetom da se iste zovu 'admin', 'user' ili 'guest' u zahtjevu (ne razlikuju se velika i mala slova). Zahtjev treba sadržavati popis i ako je korisnik član više grupa, aplikacija će dodijeliti ulogu koja odgovara najvišoj razini pristupa. Ukoliko se niti jedna grupa ne podudara, pristup će biti onemogućen.",
"LabelOpenRSSFeed": "Otvori RSS Feed", "LabelOpenRSSFeed": "Otvori RSS Feed",
"LabelOverwrite": "Prepiši", "LabelOverwrite": "Prepiši",
"LabelPaginationPageXOfY": "Stranica {0} od {1}",
"LabelPassword": "Zaporka", "LabelPassword": "Zaporka",
"LabelPath": "Putanja", "LabelPath": "Putanja",
"LabelPermanent": "Trajno", "LabelPermanent": "Trajno",
"LabelPermissionsAccessAllLibraries": "Ima pristup svim knjižnicama", "LabelPermissionsAccessAllLibraries": "Ima pristup svim knjižnicama",
"LabelPermissionsAccessAllTags": "Ima pristup svim oznakama", "LabelPermissionsAccessAllTags": "Ima pristup svim oznakama",
"LabelPermissionsAccessExplicitContent": "Ima pristup eksplicitnom sadržzaju", "LabelPermissionsAccessExplicitContent": "Ima pristup eksplicitnom sadržaju",
"LabelPermissionsCreateEreader": "Može stvoriti e-čitač",
"LabelPermissionsDelete": "Smije brisati", "LabelPermissionsDelete": "Smije brisati",
"LabelPermissionsDownload": "Smije preuzimati", "LabelPermissionsDownload": "Smije preuzimati",
"LabelPermissionsUpdate": "Smije ažurirati", "LabelPermissionsUpdate": "Smije ažurirati",
@@ -465,8 +496,8 @@
"LabelPubDate": "Datum izdavanja", "LabelPubDate": "Datum izdavanja",
"LabelPublishYear": "Godina objavljivanja", "LabelPublishYear": "Godina objavljivanja",
"LabelPublishedDate": "Objavljeno {0}", "LabelPublishedDate": "Objavljeno {0}",
"LabelPublishedDecade": "Desetljeće objavljivanja", "LabelPublishedDecade": "Desetljeće izdanja",
"LabelPublishedDecades": "Desetljeća objavljivanja", "LabelPublishedDecades": "Desetljeća izdanja",
"LabelPublisher": "Izdavač", "LabelPublisher": "Izdavač",
"LabelPublishers": "Izdavači", "LabelPublishers": "Izdavači",
"LabelRSSFeedCustomOwnerEmail": "Prilagođena adresa e-pošte vlasnika", "LabelRSSFeedCustomOwnerEmail": "Prilagođena adresa e-pošte vlasnika",
@@ -486,21 +517,28 @@
"LabelRedo": "Ponovi", "LabelRedo": "Ponovi",
"LabelRegion": "Regija", "LabelRegion": "Regija",
"LabelReleaseDate": "Datum izlaska", "LabelReleaseDate": "Datum izlaska",
"LabelRemoveAllMetadataAbs": "Ukloni sve datoteke metadata.abs",
"LabelRemoveAllMetadataJson": "Ukloni sve datoteke metadata.json",
"LabelRemoveCover": "Ukloni naslovnicu", "LabelRemoveCover": "Ukloni naslovnicu",
"LabelRemoveMetadataFile": "Ukloni datoteke s meta-podatcima iz mapa knjižničkih stavki",
"LabelRemoveMetadataFileHelp": "Uklanjanje svih datoteka metadata.json i metadata.abs u vaših {0} mapa.",
"LabelRowsPerPage": "Redaka po stranici", "LabelRowsPerPage": "Redaka po stranici",
"LabelSearchTerm": "Traži pojam", "LabelSearchTerm": "Traži pojam",
"LabelSearchTitle": "Traži naslov", "LabelSearchTitle": "Traži naslov",
"LabelSearchTitleOrASIN": "Traži naslov ili ASIN", "LabelSearchTitleOrASIN": "Traži naslov ili ASIN",
"LabelSeason": "Sezona", "LabelSeason": "Sezona",
"LabelSeasonNumber": "{0}. sezona",
"LabelSelectAll": "Označi sve", "LabelSelectAll": "Označi sve",
"LabelSelectAllEpisodes": "Označi sve nastavke", "LabelSelectAllEpisodes": "Označi sve nastavke",
"LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka", "LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka",
"LabelSelectUsers": "Označi korisnike", "LabelSelectUsers": "Označi korisnike",
"LabelSendEbookToDevice": "Pošalji e-knjigu", "LabelSendEbookToDevice": "Pošalji e-knjigu",
"LabelSequence": "Slijed", "LabelSequence": "Slijed",
"LabelSeries": "Serijal/a", "LabelSerial": "Serijal",
"LabelSeries": "Serijal",
"LabelSeriesName": "Ime serijala", "LabelSeriesName": "Ime serijala",
"LabelSeriesProgress": "Napredak u serijalu", "LabelSeriesProgress": "Napredak u serijalu",
"LabelServerLogLevel": "Razina zapisa poslužitelja",
"LabelServerYearReview": "Godišnji pregled poslužitelja ({0})", "LabelServerYearReview": "Godišnji pregled poslužitelja ({0})",
"LabelSetEbookAsPrimary": "Postavi kao primarno", "LabelSetEbookAsPrimary": "Postavi kao primarno",
"LabelSetEbookAsSupplementary": "Postavi kao dopunsko", "LabelSetEbookAsSupplementary": "Postavi kao dopunsko",
@@ -525,6 +563,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "Serijali koji se sastoje od samo jedne knjige neće se prikazivati na stranici serijala i na policama početne stranice.", "LabelSettingsHideSingleBookSeriesHelp": "Serijali koji se sastoje od samo jedne knjige neće se prikazivati na stranici serijala i na policama početne stranice.",
"LabelSettingsHomePageBookshelfView": "Prikaži početnu stranicu kao policu s knjigama", "LabelSettingsHomePageBookshelfView": "Prikaži početnu stranicu kao policu s knjigama",
"LabelSettingsLibraryBookshelfView": "Prikaži knjižnicu kao policu s knjigama", "LabelSettingsLibraryBookshelfView": "Prikaži knjižnicu kao policu s knjigama",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Postotak dovršenosti veći od",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Preostalo vrijeme je manje od (sekundi)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Označi medij dovršenim kada",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči ranije knjige u funkciji Nastavi serijal", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči ranije knjige u funkciji Nastavi serijal",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako uključite ovu opciju, serijal će vam se nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako uključite ovu opciju, serijal će vam se nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.",
"LabelSettingsParseSubtitles": "Raščlani podnaslove", "LabelSettingsParseSubtitles": "Raščlani podnaslove",
@@ -589,6 +630,7 @@
"LabelTimeDurationXMinutes": "{0} minuta", "LabelTimeDurationXMinutes": "{0} minuta",
"LabelTimeDurationXSeconds": "{0} sekundi", "LabelTimeDurationXSeconds": "{0} sekundi",
"LabelTimeInMinutes": "Vrijeme u minutama", "LabelTimeInMinutes": "Vrijeme u minutama",
"LabelTimeLeft": "{0} preostalo",
"LabelTimeListened": "Vremena odslušano", "LabelTimeListened": "Vremena odslušano",
"LabelTimeListenedToday": "Vremena odslušano danas", "LabelTimeListenedToday": "Vremena odslušano danas",
"LabelTimeRemaining": "{0} preostalo", "LabelTimeRemaining": "{0} preostalo",
@@ -596,6 +638,7 @@
"LabelTitle": "Naslov", "LabelTitle": "Naslov",
"LabelToolsEmbedMetadata": "Ugradi meta-podatke", "LabelToolsEmbedMetadata": "Ugradi meta-podatke",
"LabelToolsEmbedMetadataDescription": "Ugradi meta-podatke u zvučne datoteke zajedno s naslovnicom i poglavljima.", "LabelToolsEmbedMetadataDescription": "Ugradi meta-podatke u zvučne datoteke zajedno s naslovnicom i poglavljima.",
"LabelToolsM4bEncoder": "M4B kodiranje",
"LabelToolsMakeM4b": "Stvori M4B datoteku audioknjige", "LabelToolsMakeM4b": "Stvori M4B datoteku audioknjige",
"LabelToolsMakeM4bDescription": "Izrađuje zvučnu knjigu u .M4B formatu s ugrađenim meta-podatcima, naslovnicom i poglavljima.", "LabelToolsMakeM4bDescription": "Izrađuje zvučnu knjigu u .M4B formatu s ugrađenim meta-podatcima, naslovnicom i poglavljima.",
"LabelToolsSplitM4b": "Podijeli M4B datoteke u MP3 datoteke", "LabelToolsSplitM4b": "Podijeli M4B datoteke u MP3 datoteke",
@@ -604,10 +647,11 @@
"LabelTotalTimeListened": "Sveukupno vrijeme slušanja", "LabelTotalTimeListened": "Sveukupno vrijeme slušanja",
"LabelTrackFromFilename": "Naslov iz imena datoteke", "LabelTrackFromFilename": "Naslov iz imena datoteke",
"LabelTrackFromMetadata": "Naslov iz meta-podataka", "LabelTrackFromMetadata": "Naslov iz meta-podataka",
"LabelTracks": "Naslovi", "LabelTracks": "Zvučni zapisi",
"LabelTracksMultiTrack": "Više zvučnih zapisa", "LabelTracksMultiTrack": "Više zvučnih zapisa",
"LabelTracksNone": "Nema zapisa", "LabelTracksNone": "Nema zapisa",
"LabelTracksSingleTrack": "Jedan zvučni zapis", "LabelTracksSingleTrack": "Jedan zvučni zapis",
"LabelTrailer": "Najava",
"LabelType": "Vrsta", "LabelType": "Vrsta",
"LabelUnabridged": "Neskraćeno", "LabelUnabridged": "Neskraćeno",
"LabelUndo": "Vrati", "LabelUndo": "Vrati",
@@ -621,8 +665,10 @@
"LabelUploaderDragAndDrop": "Pritisni i prevuci datoteke ili mape", "LabelUploaderDragAndDrop": "Pritisni i prevuci datoteke ili mape",
"LabelUploaderDropFiles": "Ispusti datoteke", "LabelUploaderDropFiles": "Ispusti datoteke",
"LabelUploaderItemFetchMetadataHelp": "Automatski dohvati naslov, autora i serijal", "LabelUploaderItemFetchMetadataHelp": "Automatski dohvati naslov, autora i serijal",
"LabelUseAdvancedOptions": "Koristi se naprednim opcijama",
"LabelUseChapterTrack": "Koristi zvučni zapis poglavlja", "LabelUseChapterTrack": "Koristi zvučni zapis poglavlja",
"LabelUseFullTrack": "Koristi cijeli zvučni zapis", "LabelUseFullTrack": "Koristi cijeli zvučni zapis",
"LabelUseZeroForUnlimited": "0 za neograničeno",
"LabelUser": "Korisnik", "LabelUser": "Korisnik",
"LabelUsername": "Korisničko ime", "LabelUsername": "Korisničko ime",
"LabelValue": "Vrijednost", "LabelValue": "Vrijednost",
@@ -643,7 +689,7 @@
"LabelYourProgress": "Vaš napredak", "LabelYourProgress": "Vaš napredak",
"MessageAddToPlayerQueue": "Dodaj u redoslijed izvođenja", "MessageAddToPlayerQueue": "Dodaj u redoslijed izvođenja",
"MessageAppriseDescription": "Da biste se koristili ovom značajkom, treba vam instanca <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API-ja</a> ili API koji može rukovati istom vrstom zahtjeva.<br />The Adresa Apprise API-ja treba biti puna URL putanja za slanje obavijesti, npr. ako vam se API instanca poslužuje na adresi <code>http://192.168.1.1:8337</code> trebate upisati <code>http://192.168.1.1:8337/notify</code>.", "MessageAppriseDescription": "Da biste se koristili ovom značajkom, treba vam instanca <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API-ja</a> ili API koji može rukovati istom vrstom zahtjeva.<br />The Adresa Apprise API-ja treba biti puna URL putanja za slanje obavijesti, npr. ako vam se API instanca poslužuje na adresi <code>http://192.168.1.1:8337</code> trebate upisati <code>http://192.168.1.1:8337/notify</code>.",
"MessageBackupsDescription": "Backups uključuju korisnike, korisnikov napredak, detalje stavki iz biblioteke, postavke server i slike iz <code>/metadata/items</code> & <code>/metadata/authors</code>. Backups ne uključuju nijedne datoteke koje su u folderima biblioteke.", "MessageBackupsDescription": "Sigurnosne kopije sadrže korisnike, korisnikov napredak medija, pojedinosti knjižničke građe, postavke poslužitelja i slike koje se spremaju u <code>/metadata/items</code> & <code>/metadata/authors</code>. Sigurnosne kopije ne sadrže niti jednu datoteku iz mapa knjižnice.",
"MessageBackupsLocationEditNote": "Napomena: Uređivanje lokacije za sigurnosne kopije ne premješta ili mijenja postojeće sigurnosne kopije", "MessageBackupsLocationEditNote": "Napomena: Uređivanje lokacije za sigurnosne kopije ne premješta ili mijenja postojeće sigurnosne kopije",
"MessageBackupsLocationNoEditNote": "Napomena: Lokacija za sigurnosne kopije zadana je kroz varijablu okoline i ovdje se ne može izmijeniti.", "MessageBackupsLocationNoEditNote": "Napomena: Lokacija za sigurnosne kopije zadana je kroz varijablu okoline i ovdje se ne može izmijeniti.",
"MessageBackupsLocationPathEmpty": "Putanja do lokacije za sigurnosne kopije ne može ostati prazna", "MessageBackupsLocationPathEmpty": "Putanja do lokacije za sigurnosne kopije ne može ostati prazna",
@@ -669,6 +715,7 @@
"MessageConfirmDeleteMetadataProvider": "Sigurno želite izbrisati prilagođenog pružatelja meta-podataka \"{0}\"?", "MessageConfirmDeleteMetadataProvider": "Sigurno želite izbrisati prilagođenog pružatelja meta-podataka \"{0}\"?",
"MessageConfirmDeleteNotification": "Sigurno želite izbrisati ovu obavijest?", "MessageConfirmDeleteNotification": "Sigurno želite izbrisati ovu obavijest?",
"MessageConfirmDeleteSession": "Sigurno želite obrisati ovu sesiju?", "MessageConfirmDeleteSession": "Sigurno želite obrisati ovu sesiju?",
"MessageConfirmEmbedMetadataInAudioFiles": "Sigurno želite ugraditi meta-podatke u {0} zvučnih datoteka?",
"MessageConfirmForceReScan": "Sigurno želite ponovno pokrenuti skeniranje?", "MessageConfirmForceReScan": "Sigurno želite ponovno pokrenuti skeniranje?",
"MessageConfirmMarkAllEpisodesFinished": "Sigurno želite označiti sve nastavke dovršenima?", "MessageConfirmMarkAllEpisodesFinished": "Sigurno želite označiti sve nastavke dovršenima?",
"MessageConfirmMarkAllEpisodesNotFinished": "Sigurno želite označiti sve nastavke nedovršenima?", "MessageConfirmMarkAllEpisodesNotFinished": "Sigurno želite označiti sve nastavke nedovršenima?",
@@ -680,6 +727,7 @@
"MessageConfirmPurgeCache": "Brisanje predmemorije izbrisat će cijelu mapu <code>/metadata/cache</code>. <br /><br />Sigurno želite izbrisati mapu predmemorije?", "MessageConfirmPurgeCache": "Brisanje predmemorije izbrisat će cijelu mapu <code>/metadata/cache</code>. <br /><br />Sigurno želite izbrisati mapu predmemorije?",
"MessageConfirmPurgeItemsCache": "Brisanje predmemorije stavki izbrisat će cijelu mapu <code>/metadata/cache/items</code>.<br />Jeste li sigurni?", "MessageConfirmPurgeItemsCache": "Brisanje predmemorije stavki izbrisat će cijelu mapu <code>/metadata/cache/items</code>.<br />Jeste li sigurni?",
"MessageConfirmQuickEmbed": "Pažnja! Funkcija brzog ugrađivanja ne stvara sigurnosne kopije vaših zvučnih datoteka. Provjerite imate li sigurnosnu kopiju. <br><br>Želite li nastaviti?", "MessageConfirmQuickEmbed": "Pažnja! Funkcija brzog ugrađivanja ne stvara sigurnosne kopije vaših zvučnih datoteka. Provjerite imate li sigurnosnu kopiju. <br><br>Želite li nastaviti?",
"MessageConfirmQuickMatchEpisodes": "Brzo prepoznavanje nastavaka prepisat će pojedinosti ukoliko se pronađe podudaranje. Neprepoznati nastavci će se ažurirati. Jeste li sigurni?",
"MessageConfirmReScanLibraryItems": "Sigurno želite ponovno skenirati {0} stavki?", "MessageConfirmReScanLibraryItems": "Sigurno želite ponovno skenirati {0} stavki?",
"MessageConfirmRemoveAllChapters": "Sigurno želite ukloniti sva poglavlja?", "MessageConfirmRemoveAllChapters": "Sigurno želite ukloniti sva poglavlja?",
"MessageConfirmRemoveAuthor": "Sigurno želite ukloniti autora \"{0}\"?", "MessageConfirmRemoveAuthor": "Sigurno želite ukloniti autora \"{0}\"?",
@@ -687,6 +735,7 @@
"MessageConfirmRemoveEpisode": "Sigurno želite ukloniti nastavak \"{0}\"?", "MessageConfirmRemoveEpisode": "Sigurno želite ukloniti nastavak \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Sigurno želite ukloniti {0} nastavaka?", "MessageConfirmRemoveEpisodes": "Sigurno želite ukloniti {0} nastavaka?",
"MessageConfirmRemoveListeningSessions": "Sigurno želite ukloniti {0} sesija slušanja?", "MessageConfirmRemoveListeningSessions": "Sigurno želite ukloniti {0} sesija slušanja?",
"MessageConfirmRemoveMetadataFiles": "Sigurno želite ukloniti sve datoteke metadata.{0} u mapama vaših knjižničkih stavki?",
"MessageConfirmRemoveNarrator": "Sigurno želite ukloniti pripovjedača \"{0}\"?", "MessageConfirmRemoveNarrator": "Sigurno želite ukloniti pripovjedača \"{0}\"?",
"MessageConfirmRemovePlaylist": "Sigurno želite ukloniti vaš popis za izvođenje \"{0}\"?", "MessageConfirmRemovePlaylist": "Sigurno želite ukloniti vaš popis za izvođenje \"{0}\"?",
"MessageConfirmRenameGenre": "Sigurno želite preimenovati žanr \"{0}\" u \"{1}\" za sve stavke?", "MessageConfirmRenameGenre": "Sigurno želite preimenovati žanr \"{0}\" u \"{1}\" za sve stavke?",
@@ -699,9 +748,10 @@
"MessageConfirmSendEbookToDevice": "Sigurno želite poslati {0} e-knjiga/u \"{1}\" na uređaj \"{2}\"?", "MessageConfirmSendEbookToDevice": "Sigurno želite poslati {0} e-knjiga/u \"{1}\" na uređaj \"{2}\"?",
"MessageConfirmUnlinkOpenId": "Sigurno želite odspojiti ovog korisnika s OpenID-ja?", "MessageConfirmUnlinkOpenId": "Sigurno želite odspojiti ovog korisnika s OpenID-ja?",
"MessageDownloadingEpisode": "Preuzimam nastavak", "MessageDownloadingEpisode": "Preuzimam nastavak",
"MessageDragFilesIntoTrackOrder": "Ispravi redoslijed zapisa prevlačenje datoteka", "MessageDragFilesIntoTrackOrder": "Prevlačenjem datoteka složite pravilan redoslijed",
"MessageEmbedFailed": "Ugrađivanje nije uspjelo!", "MessageEmbedFailed": "Ugrađivanje nije uspjelo!",
"MessageEmbedFinished": "Ugrađivanje je dovršeno!", "MessageEmbedFinished": "Ugrađivanje je dovršeno!",
"MessageEmbedQueue": "Ugrađivanje meta-podataka dodano u red obrade ({0} u redu)",
"MessageEpisodesQueuedForDownload": "{0} nastavak(a) u redu za preuzimanje", "MessageEpisodesQueuedForDownload": "{0} nastavak(a) u redu za preuzimanje",
"MessageEreaderDevices": "Da biste osigurali isporuku e-knjiga, možda ćete morati gornju adresu e-pošte dodati kao dopuštenog pošiljatelja za svaki od donjih uređaja.", "MessageEreaderDevices": "Da biste osigurali isporuku e-knjiga, možda ćete morati gornju adresu e-pošte dodati kao dopuštenog pošiljatelja za svaki od donjih uređaja.",
"MessageFeedURLWillBe": "URL izvora bit će {0}", "MessageFeedURLWillBe": "URL izvora bit će {0}",
@@ -746,6 +796,7 @@
"MessageNoLogs": "Nema zapisnika", "MessageNoLogs": "Nema zapisnika",
"MessageNoMediaProgress": "Nema podataka o započetim medijima", "MessageNoMediaProgress": "Nema podataka o započetim medijima",
"MessageNoNotifications": "Nema obavijesti", "MessageNoNotifications": "Nema obavijesti",
"MessageNoPodcastFeed": "Neispravan podcast: Nema izvora",
"MessageNoPodcastsFound": "Nije pronađen niti jedan podcast", "MessageNoPodcastsFound": "Nije pronađen niti jedan podcast",
"MessageNoResults": "Nema rezultata", "MessageNoResults": "Nema rezultata",
"MessageNoSearchResultsFor": "Nema rezultata pretrage za \"{0}\"", "MessageNoSearchResultsFor": "Nema rezultata pretrage za \"{0}\"",
@@ -762,6 +813,10 @@
"MessagePlaylistCreateFromCollection": "Stvori popis za izvođenje od zbirke", "MessagePlaylistCreateFromCollection": "Stvori popis za izvođenje od zbirke",
"MessagePleaseWait": "Molimo pričekajte...", "MessagePleaseWait": "Molimo pričekajte...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nema adresu RSS izvora za prepoznavanje", "MessagePodcastHasNoRSSFeedForMatching": "Podcast nema adresu RSS izvora za prepoznavanje",
"MessagePodcastSearchField": "Unesite upit za pretragu ili URL RSS izvora",
"MessageQuickEmbedInProgress": "Brzo ugrađivanje u tijeku",
"MessageQuickEmbedQueue": "Dodano u red za brzo ugrađivanje ({0} u redu izvođenja)",
"MessageQuickMatchAllEpisodes": "Brzo prepoznavanje svih nastavaka",
"MessageQuickMatchDescription": "Popuni pojedinosti i naslovnice koji nedostaju prvim pronađenim rezultatom za '{0}'. Ne prepisuje podatke osim ako ne uključite mogućnost 'Daj prednost meta-podatcima prepoznatih stavki'.", "MessageQuickMatchDescription": "Popuni pojedinosti i naslovnice koji nedostaju prvim pronađenim rezultatom za '{0}'. Ne prepisuje podatke osim ako ne uključite mogućnost 'Daj prednost meta-podatcima prepoznatih stavki'.",
"MessageRemoveChapter": "Ukloni poglavlje", "MessageRemoveChapter": "Ukloni poglavlje",
"MessageRemoveEpisodes": "Ukloni {0} nastavaka", "MessageRemoveEpisodes": "Ukloni {0} nastavaka",
@@ -804,6 +859,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Podcast već postoji u putanji", "MessageTaskOpmlImportFeedPodcastExists": "Podcast već postoji u putanji",
"MessageTaskOpmlImportFeedPodcastFailed": "Stvaranje podcasta nije uspjelo", "MessageTaskOpmlImportFeedPodcastFailed": "Stvaranje podcasta nije uspjelo",
"MessageTaskOpmlImportFinished": "Dodano {0} podcasta", "MessageTaskOpmlImportFinished": "Dodano {0} podcasta",
"MessageTaskOpmlParseFailed": "Raščlanjivanje OPML datoteke nije uspjelo",
"MessageTaskOpmlParseFastFail": "Neispravna OPML datoteka, oznaka <opml> nije pronađena ILI oznaka <outline> nije pronađena",
"MessageTaskOpmlParseNoneFound": "U OPML datoteci nisu pronađeni izvori",
"MessageTaskScanItemsAdded": "{0} dodan(o)", "MessageTaskScanItemsAdded": "{0} dodan(o)",
"MessageTaskScanItemsMissing": "{0} nedostaje", "MessageTaskScanItemsMissing": "{0} nedostaje",
"MessageTaskScanItemsUpdated": "{0} ažurirano", "MessageTaskScanItemsUpdated": "{0} ažurirano",
@@ -828,6 +886,10 @@
"NoteUploaderFoldersWithMediaFiles": "Mape s medijskim datotekama smatrat će se zasebnim stavkama knjižnice.", "NoteUploaderFoldersWithMediaFiles": "Mape s medijskim datotekama smatrat će se zasebnim stavkama knjižnice.",
"NoteUploaderOnlyAudioFiles": "Ako učitavate samo zvučne datoteke svaka će se zvučna datoteka uvesti kao zasebna zvučna knjiga.", "NoteUploaderOnlyAudioFiles": "Ako učitavate samo zvučne datoteke svaka će se zvučna datoteka uvesti kao zasebna zvučna knjiga.",
"NoteUploaderUnsupportedFiles": "Nepodržane vrste datoteka zanemaruju se. Kada odabirete datoteke ili ispuštate mapu, sve datoteke koje nisu u mapi stavke zanemarit će se.", "NoteUploaderUnsupportedFiles": "Nepodržane vrste datoteka zanemaruju se. Kada odabirete datoteke ili ispuštate mapu, sve datoteke koje nisu u mapi stavke zanemarit će se.",
"NotificationOnBackupCompletedDescription": "Pokreće se po završetku sigurnosnog kopiranja",
"NotificationOnBackupFailedDescription": "Pokreće se kada sigurnosno kopiranje ne uspije",
"NotificationOnEpisodeDownloadedDescription": "Pokreće se kada se nastavak podcasta automatski preuzme",
"NotificationOnTestDescription": "Događaj za testiranje sustava obavijesti",
"PlaceholderNewCollection": "Ime nove zbirke", "PlaceholderNewCollection": "Ime nove zbirke",
"PlaceholderNewFolderPath": "Nova putanja mape", "PlaceholderNewFolderPath": "Nova putanja mape",
"PlaceholderNewPlaylist": "Naziv novog popisa za izvođenje", "PlaceholderNewPlaylist": "Naziv novog popisa za izvođenje",
@@ -853,6 +915,7 @@
"StatsYearInReview": "PREGLED GODINE", "StatsYearInReview": "PREGLED GODINE",
"ToastAccountUpdateSuccess": "Račun ažuriran", "ToastAccountUpdateSuccess": "Račun ažuriran",
"ToastAppriseUrlRequired": "Obavezno upisati Apprise URL", "ToastAppriseUrlRequired": "Obavezno upisati Apprise URL",
"ToastAsinRequired": "ASIN je obvezan",
"ToastAuthorImageRemoveSuccess": "Slika autora uklonjena", "ToastAuthorImageRemoveSuccess": "Slika autora uklonjena",
"ToastAuthorNotFound": "Autor \"{0}\" nije pronađen", "ToastAuthorNotFound": "Autor \"{0}\" nije pronađen",
"ToastAuthorRemoveSuccess": "Autor uklonjen", "ToastAuthorRemoveSuccess": "Autor uklonjen",
@@ -872,6 +935,8 @@
"ToastBackupUploadSuccess": "Sigurnosna kopija učitana", "ToastBackupUploadSuccess": "Sigurnosna kopija učitana",
"ToastBatchDeleteFailed": "Grupno brisanje nije uspjelo", "ToastBatchDeleteFailed": "Grupno brisanje nije uspjelo",
"ToastBatchDeleteSuccess": "Grupno brisanje je uspješno dovršeno", "ToastBatchDeleteSuccess": "Grupno brisanje je uspješno dovršeno",
"ToastBatchQuickMatchFailed": "Grupno brzo prepoznavanje nije uspjelo!",
"ToastBatchQuickMatchStarted": "Započelo je brzo prepoznavanje {0} knjiga!",
"ToastBatchUpdateFailed": "Skupno ažuriranje nije uspjelo", "ToastBatchUpdateFailed": "Skupno ažuriranje nije uspjelo",
"ToastBatchUpdateSuccess": "Skupno ažuriranje uspješno dovršeno", "ToastBatchUpdateSuccess": "Skupno ažuriranje uspješno dovršeno",
"ToastBookmarkCreateFailed": "Izrada knjižne oznake nije uspjela", "ToastBookmarkCreateFailed": "Izrada knjižne oznake nije uspjela",
@@ -883,6 +948,7 @@
"ToastChaptersHaveErrors": "Poglavlja imaju pogreške", "ToastChaptersHaveErrors": "Poglavlja imaju pogreške",
"ToastChaptersMustHaveTitles": "Poglavlja moraju imati naslove", "ToastChaptersMustHaveTitles": "Poglavlja moraju imati naslove",
"ToastChaptersRemoved": "Poglavlja uklonjena", "ToastChaptersRemoved": "Poglavlja uklonjena",
"ToastChaptersUpdated": "Poglavlja su ažurirana",
"ToastCollectionItemsAddFailed": "Neuspješno dodavanje stavki u zbirku", "ToastCollectionItemsAddFailed": "Neuspješno dodavanje stavki u zbirku",
"ToastCollectionItemsAddSuccess": "Uspješno dodavanje stavki u zbirku", "ToastCollectionItemsAddSuccess": "Uspješno dodavanje stavki u zbirku",
"ToastCollectionItemsRemoveSuccess": "Stavke izbrisane iz zbirke", "ToastCollectionItemsRemoveSuccess": "Stavke izbrisane iz zbirke",
@@ -900,11 +966,14 @@
"ToastEncodeCancelSucces": "Kodiranje otkazano", "ToastEncodeCancelSucces": "Kodiranje otkazano",
"ToastEpisodeDownloadQueueClearFailed": "Redoslijed izvođenja nije uspješno očišćen", "ToastEpisodeDownloadQueueClearFailed": "Redoslijed izvođenja nije uspješno očišćen",
"ToastEpisodeDownloadQueueClearSuccess": "Redoslijed preuzimanja nastavaka očišćen", "ToastEpisodeDownloadQueueClearSuccess": "Redoslijed preuzimanja nastavaka očišćen",
"ToastEpisodeUpdateSuccess": "{0} nastavak/a ažurirano",
"ToastErrorCannotShare": "Dijeljenje na ovaj uređaj nije moguće", "ToastErrorCannotShare": "Dijeljenje na ovaj uređaj nije moguće",
"ToastFailedToLoadData": "Učitavanje podataka nije uspjelo", "ToastFailedToLoadData": "Učitavanje podataka nije uspjelo",
"ToastFailedToMatch": "Nije prepoznato",
"ToastFailedToShare": "Dijeljenje nije uspjelo", "ToastFailedToShare": "Dijeljenje nije uspjelo",
"ToastFailedToUpdate": "Ažuriranje nije uspjelo", "ToastFailedToUpdate": "Ažuriranje nije uspjelo",
"ToastInvalidImageUrl": "Neispravan URL slike", "ToastInvalidImageUrl": "Neispravan URL slike",
"ToastInvalidMaxEpisodesToDownload": "Neispravan unos maksimalnog broja nastavaka",
"ToastInvalidUrl": "Neispravan URL", "ToastInvalidUrl": "Neispravan URL",
"ToastItemCoverUpdateSuccess": "Naslovnica stavke ažurirana", "ToastItemCoverUpdateSuccess": "Naslovnica stavke ažurirana",
"ToastItemDeletedFailed": "Brisanje stavke nije uspjelo", "ToastItemDeletedFailed": "Brisanje stavke nije uspjelo",
@@ -923,14 +992,21 @@
"ToastLibraryScanStarted": "Skeniranje knjižnice započelo", "ToastLibraryScanStarted": "Skeniranje knjižnice započelo",
"ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" ažurirana", "ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" ažurirana",
"ToastMatchAllAuthorsFailed": "Nisu prepoznati svi autori", "ToastMatchAllAuthorsFailed": "Nisu prepoznati svi autori",
"ToastMetadataFilesRemovedError": "Pogreška kod uklanjanja datoteka metadata.{0}",
"ToastMetadataFilesRemovedNoneFound": "U knjižnici nisu pronađene datoteke metadata.{0}",
"ToastMetadataFilesRemovedNoneRemoved": "Datoteke metadata.{0} nisu uklonjenje",
"ToastMetadataFilesRemovedSuccess": "uklonjeno {0} datoteka metadata.{1}",
"ToastMustHaveAtLeastOnePath": "Mora postojati barem jedna putanja",
"ToastNameEmailRequired": "Ime i adresa e-pošte su obavezni", "ToastNameEmailRequired": "Ime i adresa e-pošte su obavezni",
"ToastNameRequired": "Ime je obavezno", "ToastNameRequired": "Ime je obavezno",
"ToastNewEpisodesFound": "pronađeno {0} novih nastavaka",
"ToastNewUserCreatedFailed": "Račun \"{0}\" nije uspješno izrađen", "ToastNewUserCreatedFailed": "Račun \"{0}\" nije uspješno izrađen",
"ToastNewUserCreatedSuccess": "Novi račun izrađen", "ToastNewUserCreatedSuccess": "Novi račun izrađen",
"ToastNewUserLibraryError": "Treba odabrati barem jednu knjižnicu", "ToastNewUserLibraryError": "Treba odabrati barem jednu knjižnicu",
"ToastNewUserPasswordError": "Mora imati zaporku, samo korisnik root može imati praznu zaporku", "ToastNewUserPasswordError": "Mora imati zaporku, samo korisnik root može imati praznu zaporku",
"ToastNewUserTagError": "Potrebno je odabrati najmanje jednu oznaku", "ToastNewUserTagError": "Potrebno je odabrati najmanje jednu oznaku",
"ToastNewUserUsernameError": "Upišite korisničko ime", "ToastNewUserUsernameError": "Upišite korisničko ime",
"ToastNoNewEpisodesFound": "Nisu pronađeni novi nastavci",
"ToastNoUpdatesNecessary": "Ažuriranja nisu potrebna", "ToastNoUpdatesNecessary": "Ažuriranja nisu potrebna",
"ToastNotificationCreateFailed": "Stvaranje obavijesti nije uspjelo", "ToastNotificationCreateFailed": "Stvaranje obavijesti nije uspjelo",
"ToastNotificationDeleteFailed": "Brisanje obavijesti nije uspjelo", "ToastNotificationDeleteFailed": "Brisanje obavijesti nije uspjelo",
@@ -949,6 +1025,7 @@
"ToastPodcastGetFeedFailed": "Dohvat izvora podcasta nije uspio", "ToastPodcastGetFeedFailed": "Dohvat izvora podcasta nije uspio",
"ToastPodcastNoEpisodesInFeed": "U RSS izvoru nisu pronađeni nastavci", "ToastPodcastNoEpisodesInFeed": "U RSS izvoru nisu pronađeni nastavci",
"ToastPodcastNoRssFeed": "Podcast nema RSS izvor", "ToastPodcastNoRssFeed": "Podcast nema RSS izvor",
"ToastProgressIsNotBeingSynced": "Napredak se ne sinkronizira, ponovno pokrenite reprodukciju",
"ToastProviderCreatedFailed": "Dodavanje pružatelja nije uspjelo", "ToastProviderCreatedFailed": "Dodavanje pružatelja nije uspjelo",
"ToastProviderCreatedSuccess": "Novi pružatelj dodan", "ToastProviderCreatedSuccess": "Novi pružatelj dodan",
"ToastProviderNameAndUrlRequired": "Ime i URL su obavezni", "ToastProviderNameAndUrlRequired": "Ime i URL su obavezni",
@@ -975,6 +1052,7 @@
"ToastSessionCloseFailed": "Zatvaranje sesije nije uspjelo", "ToastSessionCloseFailed": "Zatvaranje sesije nije uspjelo",
"ToastSessionDeleteFailed": "Neuspješno brisanje serije", "ToastSessionDeleteFailed": "Neuspješno brisanje serije",
"ToastSessionDeleteSuccess": "Sesija obrisana", "ToastSessionDeleteSuccess": "Sesija obrisana",
"ToastSleepTimerDone": "Timer za spavanje istječe... zZzzZz",
"ToastSlugMustChange": "Slug sadrži nedozvoljene znakove", "ToastSlugMustChange": "Slug sadrži nedozvoljene znakove",
"ToastSlugRequired": "Slug je obavezan", "ToastSlugRequired": "Slug je obavezan",
"ToastSocketConnected": "Socket priključen", "ToastSocketConnected": "Socket priključen",
+2 -1
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése", "ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése",
"ButtonQueueAddItem": "Hozzáadás a sorhoz", "ButtonQueueAddItem": "Hozzáadás a sorhoz",
"ButtonQueueRemoveItem": "Eltávolítás a sorból", "ButtonQueueRemoveItem": "Eltávolítás a sorból",
"ButtonQuickEmbed": "Gyors beágyazás",
"ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása", "ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása",
"ButtonQuickMatch": "Gyors egyeztetés", "ButtonQuickMatch": "Gyors egyeztetés",
"ButtonReScan": "Újraszkennelés", "ButtonReScan": "Újraszkennelés",
@@ -343,7 +344,7 @@
"LabelHasSupplementaryEbook": "Van kiegészítő e-könyve", "LabelHasSupplementaryEbook": "Van kiegészítő e-könyve",
"LabelHideSubtitles": "Alcím elrejtése", "LabelHideSubtitles": "Alcím elrejtése",
"LabelHighestPriority": "Legmagasabb prioritás", "LabelHighestPriority": "Legmagasabb prioritás",
"LabelHost": "Házigazda", "LabelHost": "Kiszolgáló",
"LabelHour": "Óra", "LabelHour": "Óra",
"LabelHours": "Órák", "LabelHours": "Órák",
"LabelIcon": "Ikon", "LabelIcon": "Ikon",
+31 -1
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Elimina la Cache selezionata", "ButtonPurgeItemsCache": "Elimina la Cache selezionata",
"ButtonQueueAddItem": "Aggiungi alla Coda", "ButtonQueueAddItem": "Aggiungi alla Coda",
"ButtonQueueRemoveItem": "Rimuovi dalla Coda", "ButtonQueueRemoveItem": "Rimuovi dalla Coda",
"ButtonQuickEmbed": "Quick Embed",
"ButtonQuickEmbedMetadata": "Incorporamento rapido Metadati", "ButtonQuickEmbedMetadata": "Incorporamento rapido Metadati",
"ButtonQuickMatch": "Controlla Metadata Auto", "ButtonQuickMatch": "Controlla Metadata Auto",
"ButtonReScan": "Ri-scansiona", "ButtonReScan": "Ri-scansiona",
@@ -225,6 +226,9 @@
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti", "LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
"LabelAlreadyInYourLibrary": "Già esistente nella libreria", "LabelAlreadyInYourLibrary": "Già esistente nella libreria",
"LabelAppend": "Appese", "LabelAppend": "Appese",
"LabelAudioBitrate": "Audio Bitrate (es. 128k)",
"LabelAudioChannels": "Canali Audio (1 o 2)",
"LabelAudioCodec": "Codec Audio",
"LabelAuthor": "Autore", "LabelAuthor": "Autore",
"LabelAuthorFirstLast": "Autore (Per Nome)", "LabelAuthorFirstLast": "Autore (Per Nome)",
"LabelAuthorLastFirst": "Autori (Per Cognome)", "LabelAuthorLastFirst": "Autori (Per Cognome)",
@@ -237,6 +241,7 @@
"LabelAutoRegister": "Auto Registrazione", "LabelAutoRegister": "Auto Registrazione",
"LabelAutoRegisterDescription": "Crea automaticamente nuovi utenti dopo aver effettuato l'accesso", "LabelAutoRegisterDescription": "Crea automaticamente nuovi utenti dopo aver effettuato l'accesso",
"LabelBackToUser": "Torna a Utenti", "LabelBackToUser": "Torna a Utenti",
"LabelBackupAudioFiles": "Backup file Audio",
"LabelBackupLocation": "Percorso del Backup", "LabelBackupLocation": "Percorso del Backup",
"LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico", "LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico",
"LabelBackupsEnableAutomaticBackupsHelp": "I Backup saranno salvati in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "I Backup saranno salvati in /metadata/backups",
@@ -303,6 +308,15 @@
"LabelEmailSettingsTestAddress": "Indirizzo di test", "LabelEmailSettingsTestAddress": "Indirizzo di test",
"LabelEmbeddedCover": "Cover Integrata", "LabelEmbeddedCover": "Cover Integrata",
"LabelEnable": "Abilita", "LabelEnable": "Abilita",
"LabelEncodingBackupLocation": "il backup dei file audio verrà archiviato in:",
"LabelEncodingChaptersNotEmbedded": "Negli audiolibri multitraccia i capitoli non sono incorporati.",
"LabelEncodingClearItemCache": "Assicurati di svuotare periodicamente la cache degli oggetti.",
"LabelEncodingFinishedM4B": "L'M4B completato verrà inserito nella cartella:",
"LabelEncodingInfoEmbedded": "I metadati verranno incorporati nelle tracce audio all'interno della cartella dell'audiolibro.",
"LabelEncodingStartedNavigation": "Una volta avviata l'attività, è possibile uscire da questa pagina.",
"LabelEncodingTimeWarning": "La codifica può richiedere fino a 30 minuti.",
"LabelEncodingWarningAdvancedSettings": "Attenzione: non aggiornare queste impostazioni se non hai familiarità con le opzioni di codifica ffmpeg.",
"LabelEncodingWatcherDisabled": "Se hai disabilitato l'opzione Watcher, dovrai eseguire nuovamente la scansione dell'audiolibro in seguito.",
"LabelEnd": "Fine", "LabelEnd": "Fine",
"LabelEndOfChapter": "Fine Capitolo", "LabelEndOfChapter": "Fine Capitolo",
"LabelEpisode": "Episodio", "LabelEpisode": "Episodio",
@@ -501,6 +515,7 @@
"LabelSeries": "Serie", "LabelSeries": "Serie",
"LabelSeriesName": "Nome Serie", "LabelSeriesName": "Nome Serie",
"LabelSeriesProgress": "Cominciato", "LabelSeriesProgress": "Cominciato",
"LabelServerLogLevel": "Server Log Level",
"LabelServerYearReview": "Anno del server in sintesi({0})", "LabelServerYearReview": "Anno del server in sintesi({0})",
"LabelSetEbookAsPrimary": "Imposta come primario", "LabelSetEbookAsPrimary": "Imposta come primario",
"LabelSetEbookAsSupplementary": "Imposta come suplementare", "LabelSetEbookAsSupplementary": "Imposta come suplementare",
@@ -596,6 +611,7 @@
"LabelTitle": "Titolo", "LabelTitle": "Titolo",
"LabelToolsEmbedMetadata": "Incorpora Metadata", "LabelToolsEmbedMetadata": "Incorpora Metadata",
"LabelToolsEmbedMetadataDescription": "Incorpora i metadati nei file audio, inclusi l'immagine di copertina e i capitoli.", "LabelToolsEmbedMetadataDescription": "Incorpora i metadati nei file audio, inclusi l'immagine di copertina e i capitoli.",
"LabelToolsM4bEncoder": "M4B Encoder",
"LabelToolsMakeM4b": "Crea un file M4B", "LabelToolsMakeM4b": "Crea un file M4B",
"LabelToolsMakeM4bDescription": "Genera un file audiolibro M4B con metadati incorporati, immagine di copertina e capitoli.", "LabelToolsMakeM4bDescription": "Genera un file audiolibro M4B con metadati incorporati, immagine di copertina e capitoli.",
"LabelToolsSplitM4b": "Converti M4B in MP3", "LabelToolsSplitM4b": "Converti M4B in MP3",
@@ -621,6 +637,7 @@
"LabelUploaderDragAndDrop": "Drag & drop file o Cartelle", "LabelUploaderDragAndDrop": "Drag & drop file o Cartelle",
"LabelUploaderDropFiles": "Elimina file", "LabelUploaderDropFiles": "Elimina file",
"LabelUploaderItemFetchMetadataHelp": "Recupera automaticamente titolo, autore e serie", "LabelUploaderItemFetchMetadataHelp": "Recupera automaticamente titolo, autore e serie",
"LabelUseAdvancedOptions": "Usa le opzioni avanzate",
"LabelUseChapterTrack": "Usa il Capitolo della Traccia", "LabelUseChapterTrack": "Usa il Capitolo della Traccia",
"LabelUseFullTrack": "Usa la traccia totale", "LabelUseFullTrack": "Usa la traccia totale",
"LabelUser": "Utente", "LabelUser": "Utente",
@@ -669,6 +686,7 @@
"MessageConfirmDeleteMetadataProvider": "Sei sicuro/sicura di voler eliminare il fornitore di metadati personalizzato {0}?", "MessageConfirmDeleteMetadataProvider": "Sei sicuro/sicura di voler eliminare il fornitore di metadati personalizzato {0}?",
"MessageConfirmDeleteNotification": "Sei sicuro/sicura di voler eliminare questa notifica?", "MessageConfirmDeleteNotification": "Sei sicuro/sicura di voler eliminare questa notifica?",
"MessageConfirmDeleteSession": "Sei sicuro di voler eliminare questa sessione?", "MessageConfirmDeleteSession": "Sei sicuro di voler eliminare questa sessione?",
"MessageConfirmEmbedMetadataInAudioFiles": "Sei sicuro di voler incorporare i metadati nei file audio {0}?",
"MessageConfirmForceReScan": "Sei sicuro di voler forzare una nuova scansione?", "MessageConfirmForceReScan": "Sei sicuro di voler forzare una nuova scansione?",
"MessageConfirmMarkAllEpisodesFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come finiti?", "MessageConfirmMarkAllEpisodesFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come finiti?",
"MessageConfirmMarkAllEpisodesNotFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come non completati?", "MessageConfirmMarkAllEpisodesNotFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come non completati?",
@@ -702,6 +720,7 @@
"MessageDragFilesIntoTrackOrder": "Trascina i file nell'ordine di traccia corretto", "MessageDragFilesIntoTrackOrder": "Trascina i file nell'ordine di traccia corretto",
"MessageEmbedFailed": "Incorporamento non riuscito!", "MessageEmbedFailed": "Incorporamento non riuscito!",
"MessageEmbedFinished": "Incorporamento finito!", "MessageEmbedFinished": "Incorporamento finito!",
"MessageEmbedQueue": "In coda per l'incorporamento dei metadati ({0} in coda)",
"MessageEpisodesQueuedForDownload": "{0} episodio(i) in coda per lo scaricamento", "MessageEpisodesQueuedForDownload": "{0} episodio(i) in coda per lo scaricamento",
"MessageEreaderDevices": "Per garantire la consegna dei libri digitali, potrebbe essere necessario aggiungere l'indirizzo e-mail sopra indicato come mittente valido per ciascun dispositivo elencato di seguito.", "MessageEreaderDevices": "Per garantire la consegna dei libri digitali, potrebbe essere necessario aggiungere l'indirizzo e-mail sopra indicato come mittente valido per ciascun dispositivo elencato di seguito.",
"MessageFeedURLWillBe": "lURL del flusso sarà {0}", "MessageFeedURLWillBe": "lURL del flusso sarà {0}",
@@ -746,6 +765,7 @@
"MessageNoLogs": "Nessun Logs", "MessageNoLogs": "Nessun Logs",
"MessageNoMediaProgress": "Nessun progresso multimediale", "MessageNoMediaProgress": "Nessun progresso multimediale",
"MessageNoNotifications": "Nessuna notifica", "MessageNoNotifications": "Nessuna notifica",
"MessageNoPodcastFeed": "Podcast non valido: nessun feed",
"MessageNoPodcastsFound": "Nessun podcast trovato", "MessageNoPodcastsFound": "Nessun podcast trovato",
"MessageNoResults": "Nessun Risultato", "MessageNoResults": "Nessun Risultato",
"MessageNoSearchResultsFor": "Nessun risultato per \"{0}\"", "MessageNoSearchResultsFor": "Nessun risultato per \"{0}\"",
@@ -762,6 +782,9 @@
"MessagePlaylistCreateFromCollection": "Crea playlist da una Raccolta", "MessagePlaylistCreateFromCollection": "Crea playlist da una Raccolta",
"MessagePleaseWait": "Attendi...", "MessagePleaseWait": "Attendi...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast non ha l'URL del feed RSS da utilizzare per il match", "MessagePodcastHasNoRSSFeedForMatching": "Podcast non ha l'URL del feed RSS da utilizzare per il match",
"MessagePodcastSearchField": "Inserisci il termine di ricerca o l'URL del feed RSS",
"MessageQuickEmbedInProgress": "Incorporamento rapido in corso",
"MessageQuickEmbedQueue": "In coda per incorporamento rapido ({0} in coda)",
"MessageQuickMatchDescription": "Compila i dettagli dell'articolo vuoto e copri con il risultato della prima corrispondenza di '{0}'. Non sovrascrive i dettagli a meno che non sia abilitata l'impostazione del server \"Preferisci metadati corrispondenti\".", "MessageQuickMatchDescription": "Compila i dettagli dell'articolo vuoto e copri con il risultato della prima corrispondenza di '{0}'. Non sovrascrive i dettagli a meno che non sia abilitata l'impostazione del server \"Preferisci metadati corrispondenti\".",
"MessageRemoveChapter": "Rimuovi Capitolo", "MessageRemoveChapter": "Rimuovi Capitolo",
"MessageRemoveEpisodes": "rimuovi {0} episodio(i)", "MessageRemoveEpisodes": "rimuovi {0} episodio(i)",
@@ -804,6 +827,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Il podcast esiste già nel percorso", "MessageTaskOpmlImportFeedPodcastExists": "Il podcast esiste già nel percorso",
"MessageTaskOpmlImportFeedPodcastFailed": "Errore durante la creazione del podcast", "MessageTaskOpmlImportFeedPodcastFailed": "Errore durante la creazione del podcast",
"MessageTaskOpmlImportFinished": "{0} podcast aggiunti", "MessageTaskOpmlImportFinished": "{0} podcast aggiunti",
"MessageTaskOpmlParseFailed": "Impossibile analizzare il file OPML",
"MessageTaskOpmlParseFastFail": "File OPML non valido. Tag <opml> non trovato OPPURE non è stato trovato un tag <outline>",
"MessageTaskOpmlParseNoneFound": "Nessun feed trovato nel file OPML",
"MessageTaskScanItemsAdded": "{0} aggiunti", "MessageTaskScanItemsAdded": "{0} aggiunti",
"MessageTaskScanItemsMissing": "{0} mancanti", "MessageTaskScanItemsMissing": "{0} mancanti",
"MessageTaskScanItemsUpdated": "{0} aggiornati", "MessageTaskScanItemsUpdated": "{0} aggiornati",
@@ -828,6 +854,10 @@
"NoteUploaderFoldersWithMediaFiles": "Le cartelle con file multimediali verranno gestite come elementi della libreria separati.", "NoteUploaderFoldersWithMediaFiles": "Le cartelle con file multimediali verranno gestite come elementi della libreria separati.",
"NoteUploaderOnlyAudioFiles": "Se carichi solo file audio, ogni file audio verrà gestito come un audiolibro separato.", "NoteUploaderOnlyAudioFiles": "Se carichi solo file audio, ogni file audio verrà gestito come un audiolibro separato.",
"NoteUploaderUnsupportedFiles": "I file non supportati vengono ignorati. Quando si sceglie o si elimina una cartella, gli altri file che non si trovano in una cartella di elementi vengono ignorati.", "NoteUploaderUnsupportedFiles": "I file non supportati vengono ignorati. Quando si sceglie o si elimina una cartella, gli altri file che non si trovano in una cartella di elementi vengono ignorati.",
"NotificationOnBackupCompletedDescription": "Attivato al completamento di un backup",
"NotificationOnBackupFailedDescription": "Attivato quando un backup fallisce",
"NotificationOnEpisodeDownloadedDescription": "Attivato quando un episodio di podcast viene scaricato automaticamente",
"NotificationOnTestDescription": "test il sistema di notifica",
"PlaceholderNewCollection": "Nome Nuova Raccolta", "PlaceholderNewCollection": "Nome Nuova Raccolta",
"PlaceholderNewFolderPath": "Nuovo Percorso Cartella", "PlaceholderNewFolderPath": "Nuovo Percorso Cartella",
"PlaceholderNewPlaylist": "Nome nuova playlist", "PlaceholderNewPlaylist": "Nome nuova playlist",
@@ -922,7 +952,7 @@
"ToastLibraryScanFailedToStart": "Errore inizio scansione", "ToastLibraryScanFailedToStart": "Errore inizio scansione",
"ToastLibraryScanStarted": "Scansione Libreria iniziata", "ToastLibraryScanStarted": "Scansione Libreria iniziata",
"ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata", "ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata",
"ToastMatchAllAuthorsFailed": "Tutti gli autori non hanno potuto essere classificati", "ToastMatchAllAuthorsFailed": "Tutti gli autori non sono potuti essere classificati",
"ToastNameEmailRequired": "Nome ed email sono obbligatori", "ToastNameEmailRequired": "Nome ed email sono obbligatori",
"ToastNameRequired": "Il nome è obbligatorio", "ToastNameRequired": "Il nome è obbligatorio",
"ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"", "ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"",
+403 -12
View File
@@ -19,6 +19,7 @@
"ButtonChooseFiles": "Bestanden kiezen", "ButtonChooseFiles": "Bestanden kiezen",
"ButtonClearFilter": "Filter verwijderen", "ButtonClearFilter": "Filter verwijderen",
"ButtonCloseFeed": "Feed sluiten", "ButtonCloseFeed": "Feed sluiten",
"ButtonCloseSession": "Sluit Sessie",
"ButtonCollections": "Collecties", "ButtonCollections": "Collecties",
"ButtonConfigureScanner": "Configureer scanner", "ButtonConfigureScanner": "Configureer scanner",
"ButtonCreate": "Creëer", "ButtonCreate": "Creëer",
@@ -28,6 +29,9 @@
"ButtonEdit": "Wijzig", "ButtonEdit": "Wijzig",
"ButtonEditChapters": "Hoofdstukken wijzigen", "ButtonEditChapters": "Hoofdstukken wijzigen",
"ButtonEditPodcast": "Podcast wijzigen", "ButtonEditPodcast": "Podcast wijzigen",
"ButtonEnable": "Aanzetten",
"ButtonFireAndFail": "Fire and Fail",
"ButtonFireOnTest": "Fire onTest event",
"ButtonForceReScan": "Forceer nieuwe scan", "ButtonForceReScan": "Forceer nieuwe scan",
"ButtonFullPath": "Volledig pad", "ButtonFullPath": "Volledig pad",
"ButtonHide": "Verberg", "ButtonHide": "Verberg",
@@ -46,18 +50,24 @@
"ButtonNevermind": "Laat maar", "ButtonNevermind": "Laat maar",
"ButtonNext": "Volgende", "ButtonNext": "Volgende",
"ButtonNextChapter": "Volgend hoofdstuk", "ButtonNextChapter": "Volgend hoofdstuk",
"ButtonNextItemInQueue": "Volgend Item in Wachtrij",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Feed openen", "ButtonOpenFeed": "Feed openen",
"ButtonOpenManager": "Manager openen", "ButtonOpenManager": "Manager openen",
"ButtonPause": "Pauze", "ButtonPause": "Pauze",
"ButtonPlay": "Afspelen", "ButtonPlay": "Afspelen",
"ButtonPlayAll": "Alles Afspelen",
"ButtonPlaying": "Speelt", "ButtonPlaying": "Speelt",
"ButtonPlaylists": "Afspeellijsten", "ButtonPlaylists": "Afspeellijsten",
"ButtonPrevious": "Vorige", "ButtonPrevious": "Vorige",
"ButtonPreviousChapter": "Vorig hoofdstuk", "ButtonPreviousChapter": "Vorig hoofdstuk",
"ButtonProbeAudioFile": "Onderzoek Audio Bestand",
"ButtonPurgeAllCache": "Volledige cache legen", "ButtonPurgeAllCache": "Volledige cache legen",
"ButtonPurgeItemsCache": "Onderdelen-cache legen", "ButtonPurgeItemsCache": "Onderdelen-cache legen",
"ButtonQueueAddItem": "In wachtrij zetten", "ButtonQueueAddItem": "In wachtrij zetten",
"ButtonQueueRemoveItem": "Uit wachtrij verwijderen", "ButtonQueueRemoveItem": "Uit wachtrij verwijderen",
"ButtonQuickEmbed": "Snel Embedden",
"ButtonQuickEmbedMetadata": "Snel Metadata Insluiten",
"ButtonQuickMatch": "Snelle match", "ButtonQuickMatch": "Snelle match",
"ButtonReScan": "Nieuwe scan", "ButtonReScan": "Nieuwe scan",
"ButtonRead": "Lees", "ButtonRead": "Lees",
@@ -70,10 +80,13 @@
"ButtonRemoveFromContinueListening": "Vewijder uit Verder luisteren", "ButtonRemoveFromContinueListening": "Vewijder uit Verder luisteren",
"ButtonRemoveFromContinueReading": "Verwijder van Verder luisteren", "ButtonRemoveFromContinueReading": "Verwijder van Verder luisteren",
"ButtonRemoveSeriesFromContinueSeries": "Verwijder serie uit Serie vervolgen", "ButtonRemoveSeriesFromContinueSeries": "Verwijder serie uit Serie vervolgen",
"ButtonReset": "Opnieuw Instellen",
"ButtonResetToDefault": "Standaardwaarden Terugzetten",
"ButtonRestore": "Herstel", "ButtonRestore": "Herstel",
"ButtonSave": "Opslaan", "ButtonSave": "Opslaan",
"ButtonSaveAndClose": "Opslaan & sluiten", "ButtonSaveAndClose": "Opslaan & sluiten",
"ButtonSaveTracklist": "Afspeellijst opslaan", "ButtonSaveTracklist": "Afspeellijst opslaan",
"ButtonScan": "Scannen",
"ButtonScanLibrary": "Scan bibliotheek", "ButtonScanLibrary": "Scan bibliotheek",
"ButtonSearch": "Zoeken", "ButtonSearch": "Zoeken",
"ButtonSelectFolderPath": "Maplocatie selecteren", "ButtonSelectFolderPath": "Maplocatie selecteren",
@@ -84,7 +97,11 @@
"ButtonShow": "Toon", "ButtonShow": "Toon",
"ButtonStartM4BEncode": "Start M4B-encoding", "ButtonStartM4BEncode": "Start M4B-encoding",
"ButtonStartMetadataEmbed": "Start insluiten metadata", "ButtonStartMetadataEmbed": "Start insluiten metadata",
"ButtonStats": "Statistieken",
"ButtonSubmit": "Indienen", "ButtonSubmit": "Indienen",
"ButtonTest": "Testen",
"ButtonUnlinkOpenId": "OpenID Ontkoppelen",
"ButtonUpload": "Upload",
"ButtonUploadBackup": "Upload back-up", "ButtonUploadBackup": "Upload back-up",
"ButtonUploadCover": "Upload cover", "ButtonUploadCover": "Upload cover",
"ButtonUploadOPMLFile": "Upload OPML-bestand", "ButtonUploadOPMLFile": "Upload OPML-bestand",
@@ -96,10 +113,12 @@
"ErrorUploadFetchMetadataNoResults": "Kan metadata niet ophalen - probeer de titel en/of auteur te updaten", "ErrorUploadFetchMetadataNoResults": "Kan metadata niet ophalen - probeer de titel en/of auteur te updaten",
"ErrorUploadLacksTitle": "Moet een titel hebben", "ErrorUploadLacksTitle": "Moet een titel hebben",
"HeaderAccount": "Account", "HeaderAccount": "Account",
"HeaderAddCustomMetadataProvider": "Aangepaste Metadataprovider Toevoegen",
"HeaderAdvanced": "Geavanceerd", "HeaderAdvanced": "Geavanceerd",
"HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen", "HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen",
"HeaderAudioTracks": "Audiotracks", "HeaderAudioTracks": "Audiotracks",
"HeaderAudiobookTools": "Audioboekbestandbeheer tools", "HeaderAudiobookTools": "Audioboekbestandbeheer tools",
"HeaderAuthentication": "Authenticatie",
"HeaderBackups": "Back-ups", "HeaderBackups": "Back-ups",
"HeaderChangePassword": "Wachtwoord wijzigen", "HeaderChangePassword": "Wachtwoord wijzigen",
"HeaderChapters": "Hoofdstukken", "HeaderChapters": "Hoofdstukken",
@@ -108,6 +127,8 @@
"HeaderCollectionItems": "Collectie-objecten", "HeaderCollectionItems": "Collectie-objecten",
"HeaderCover": "Omslag", "HeaderCover": "Omslag",
"HeaderCurrentDownloads": "Huidige downloads", "HeaderCurrentDownloads": "Huidige downloads",
"HeaderCustomMessageOnLogin": "Aangepast Bericht bij Aanmelden",
"HeaderCustomMetadataProviders": "Aangepaste Metadata Providers",
"HeaderDetails": "Details", "HeaderDetails": "Details",
"HeaderDownloadQueue": "Download-wachtrij", "HeaderDownloadQueue": "Download-wachtrij",
"HeaderEbookFiles": "Ebook bestanden", "HeaderEbookFiles": "Ebook bestanden",
@@ -128,16 +149,27 @@
"HeaderLibraryStats": "Bibliotheekstatistieken", "HeaderLibraryStats": "Bibliotheekstatistieken",
"HeaderListeningSessions": "Luistersessies", "HeaderListeningSessions": "Luistersessies",
"HeaderListeningStats": "Luisterstatistieken", "HeaderListeningStats": "Luisterstatistieken",
"HeaderLogin": "Aanmelden",
"HeaderLogs": "Logboek",
"HeaderManageGenres": "Genres beheren", "HeaderManageGenres": "Genres beheren",
"HeaderManageTags": "Tags beheren", "HeaderManageTags": "Tags beheren",
"HeaderMapDetails": "Map details",
"HeaderMatch": "Vergelijken",
"HeaderMetadataOrderOfPrecedence": "Metadata volgorde",
"HeaderMetadataToEmbed": "In te sluiten metadata", "HeaderMetadataToEmbed": "In te sluiten metadata",
"HeaderNewAccount": "Nieuwe account", "HeaderNewAccount": "Nieuwe account",
"HeaderNewLibrary": "Nieuwe bibliotheek", "HeaderNewLibrary": "Nieuwe bibliotheek",
"HeaderNotificationCreate": "Notificatie Aanmaken",
"HeaderNotificationUpdate": "Update Notificatie",
"HeaderNotifications": "Notificaties", "HeaderNotifications": "Notificaties",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authenticatie",
"HeaderOpenListeningSessions": "Open Luistersessies",
"HeaderOpenRSSFeed": "Open RSS-feed", "HeaderOpenRSSFeed": "Open RSS-feed",
"HeaderOtherFiles": "Andere bestanden", "HeaderOtherFiles": "Andere bestanden",
"HeaderPasswordAuthentication": "Wachtwoord Authenticatie",
"HeaderPermissions": "Toestemmingen", "HeaderPermissions": "Toestemmingen",
"HeaderPlayerQueue": "Afspeelwachtrij", "HeaderPlayerQueue": "Afspeelwachtrij",
"HeaderPlayerSettings": "Speler Instellingen",
"HeaderPlaylist": "Afspeellijst", "HeaderPlaylist": "Afspeellijst",
"HeaderPlaylistItems": "Onderdelen in afspeellijst", "HeaderPlaylistItems": "Onderdelen in afspeellijst",
"HeaderPodcastsToAdd": "Toe te voegen podcasts", "HeaderPodcastsToAdd": "Toe te voegen podcasts",
@@ -149,6 +181,7 @@
"HeaderRemoveEpisodes": "Verwijder {0} afleveringen", "HeaderRemoveEpisodes": "Verwijder {0} afleveringen",
"HeaderSavedMediaProgress": "Opgeslagen mediavoortgang", "HeaderSavedMediaProgress": "Opgeslagen mediavoortgang",
"HeaderSchedule": "Schema", "HeaderSchedule": "Schema",
"HeaderScheduleEpisodeDownloads": "Automatische afleveringsdownloads plannen",
"HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans", "HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans",
"HeaderSession": "Sessie", "HeaderSession": "Sessie",
"HeaderSetBackupSchedule": "Kies schema voor back-up", "HeaderSetBackupSchedule": "Kies schema voor back-up",
@@ -156,6 +189,7 @@
"HeaderSettingsDisplay": "Toon", "HeaderSettingsDisplay": "Toon",
"HeaderSettingsExperimental": "Experimentele functies", "HeaderSettingsExperimental": "Experimentele functies",
"HeaderSettingsGeneral": "Algemeen", "HeaderSettingsGeneral": "Algemeen",
"HeaderSettingsScanner": "Scanner",
"HeaderSleepTimer": "Slaaptimer", "HeaderSleepTimer": "Slaaptimer",
"HeaderStatsLargestItems": "Grootste items", "HeaderStatsLargestItems": "Grootste items",
"HeaderStatsLongestItems": "Langste items (uren)", "HeaderStatsLongestItems": "Langste items (uren)",
@@ -164,13 +198,18 @@
"HeaderStatsTop10Authors": "Top 10 auteurs", "HeaderStatsTop10Authors": "Top 10 auteurs",
"HeaderStatsTop5Genres": "Top 5 genres", "HeaderStatsTop5Genres": "Top 5 genres",
"HeaderTableOfContents": "Inhoudsopgave", "HeaderTableOfContents": "Inhoudsopgave",
"HeaderTools": "Gereedschap",
"HeaderUpdateAccount": "Account bijwerken", "HeaderUpdateAccount": "Account bijwerken",
"HeaderUpdateAuthor": "Auteur bijwerken", "HeaderUpdateAuthor": "Auteur bijwerken",
"HeaderUpdateDetails": "Details bijwerken", "HeaderUpdateDetails": "Details bijwerken",
"HeaderUpdateLibrary": "Bibliotheek bijwerken", "HeaderUpdateLibrary": "Bibliotheek bijwerken",
"HeaderUsers": "Gebruikers", "HeaderUsers": "Gebruikers",
"HeaderYearReview": "Jaar {0} in Review",
"HeaderYourStats": "Je statistieken", "HeaderYourStats": "Je statistieken",
"LabelAbridged": "Verkort", "LabelAbridged": "Verkort",
"LabelAbridgedChecked": "Verkort (gechecked)",
"LabelAbridgedUnchecked": "Onverkort (niet gechecked)",
"LabelAccessibleBy": "Toegankelijk door",
"LabelAccountType": "Accounttype", "LabelAccountType": "Accounttype",
"LabelAccountTypeAdmin": "Beheerder", "LabelAccountTypeAdmin": "Beheerder",
"LabelAccountTypeGuest": "Gast", "LabelAccountTypeGuest": "Gast",
@@ -181,39 +220,63 @@
"LabelAddToPlaylist": "Toevoegen aan afspeellijst", "LabelAddToPlaylist": "Toevoegen aan afspeellijst",
"LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst", "LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst",
"LabelAddedAt": "Toegevoegd op", "LabelAddedAt": "Toegevoegd op",
"LabelAddedDate": "Toegevoegd {0}",
"LabelAdminUsersOnly": "Enkel Admin gebruikers",
"LabelAll": "Alle", "LabelAll": "Alle",
"LabelAllUsers": "Alle gebruikers", "LabelAllUsers": "Alle gebruikers",
"LabelAllUsersExcludingGuests": "Alle gebruikers exclusief gasten",
"LabelAllUsersIncludingGuests": "Alle gebruikers inclusief gasten",
"LabelAlreadyInYourLibrary": "Reeds in je bibliotheek", "LabelAlreadyInYourLibrary": "Reeds in je bibliotheek",
"LabelApiToken": "API Token",
"LabelAppend": "Achteraan toevoegen", "LabelAppend": "Achteraan toevoegen",
"LabelAudioBitrate": "Audio Bitrate (b.v. 128k)",
"LabelAudioChannels": "Audio Kanalen (1 of 2)",
"LabelAudioCodec": "Audio Codec",
"LabelAuthor": "Auteur", "LabelAuthor": "Auteur",
"LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)", "LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)",
"LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)", "LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)",
"LabelAuthors": "Auteurs", "LabelAuthors": "Auteurs",
"LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden", "LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden",
"LabelAutoFetchMetadata": "Automatisch Metadata Ophalen",
"LabelAutoFetchMetadataHelp": "Haalt metadata op voor titel, auteur en serie om het uploaden te stroomlijnen. Aanvullende metadata moet mogelijk worden gematcht na het uploaden.",
"LabelAutoLaunch": "Automatisch Openen",
"LabelAutoLaunchDescription": "Automatisch doorverwijzen naar de auth-provider bij het navigeren naar de inlogpagina (handmatig pad <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Automatisch Registreren",
"LabelAutoRegisterDescription": "Automatisch nieuwe gebruikers aanmaken na inloggen",
"LabelBackToUser": "Terug naar gebruiker", "LabelBackToUser": "Terug naar gebruiker",
"LabelBackupAudioFiles": "Back-up audiobestanden",
"LabelBackupLocation": "Back-up locatie", "LabelBackupLocation": "Back-up locatie",
"LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen", "LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen",
"LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB)", "LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB) (0 voor ongelimiteerd)",
"LabelBackupsMaxBackupSizeHelp": "Als een beveiliging tegen verkeerde instelling, zullen back-up mislukken als ze de ingestelde grootte overschrijden.", "LabelBackupsMaxBackupSizeHelp": "Als een beveiliging tegen verkeerde instelling, zullen back-up mislukken als ze de ingestelde grootte overschrijden.",
"LabelBackupsNumberToKeep": "Aantal te bewaren back-ups", "LabelBackupsNumberToKeep": "Aantal te bewaren back-ups",
"LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.", "LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.",
"LabelBitrate": "Bitrate",
"LabelBonus": "Bonus",
"LabelBooks": "Boeken", "LabelBooks": "Boeken",
"LabelButtonText": "Knop Tekst",
"LabelByAuthor": "Door {0}",
"LabelChangePassword": "Wachtwoord wijzigen", "LabelChangePassword": "Wachtwoord wijzigen",
"LabelChannels": "Kanalen", "LabelChannels": "Kanalen",
"LabelChapterCount": "{0} Hoofdstukken",
"LabelChapterTitle": "Hoofdstuktitel", "LabelChapterTitle": "Hoofdstuktitel",
"LabelChapters": "Hoofdstukken", "LabelChapters": "Hoofdstukken",
"LabelChaptersFound": "Hoofdstukken gevonden", "LabelChaptersFound": "Hoofdstukken gevonden",
"LabelClickForMoreInfo": "Klik voor meer informatie", "LabelClickForMoreInfo": "Klik voor meer informatie",
"LabelClickToUseCurrentValue": "Klik om huidige waarde te gebruiken",
"LabelClosePlayer": "Sluit speler", "LabelClosePlayer": "Sluit speler",
"LabelCodec": "Codec",
"LabelCollapseSeries": "Series inklappen", "LabelCollapseSeries": "Series inklappen",
"LabelCollapseSubSeries": "Subserie samenvouwen",
"LabelCollection": "Collectie", "LabelCollection": "Collectie",
"LabelCollections": "Collecties", "LabelCollections": "Collecties",
"LabelComplete": "Compleet", "LabelComplete": "Compleet",
"LabelConfirmPassword": "Bevestig wachtwoord", "LabelConfirmPassword": "Bevestig wachtwoord",
"LabelContinueListening": "Verder Luisteren", "LabelContinueListening": "Verder Luisteren",
"LabelContinueReading": "Verder lezen", "LabelContinueReading": "Verder lezen",
"LabelContinueSeries": "Ga verder met serie", "LabelContinueSeries": "Doorgaan met Serie",
"LabelCover": "Omslag",
"LabelCoverImageURL": "Coverafbeelding URL", "LabelCoverImageURL": "Coverafbeelding URL",
"LabelCreatedAt": "Gecreëerd op", "LabelCreatedAt": "Gecreëerd op",
"LabelCronExpression": "Cron-uitdrukking", "LabelCronExpression": "Cron-uitdrukking",
@@ -222,33 +285,68 @@
"LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:", "LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:",
"LabelDatetime": "Datum-tijd", "LabelDatetime": "Datum-tijd",
"LabelDays": "Dagen", "LabelDays": "Dagen",
"LabelDeleteFromFileSystemCheckbox": "Verwijderen uit bestandssysteem (uncheck om alleen uit database te verwijderen)",
"LabelDescription": "Beschrijving", "LabelDescription": "Beschrijving",
"LabelDeselectAll": "Deselecteer alle", "LabelDeselectAll": "Deselecteer alle",
"LabelDevice": "Apparaat", "LabelDevice": "Apparaat",
"LabelDeviceInfo": "Apparaat info", "LabelDeviceInfo": "Apparaat info",
"LabelDeviceIsAvailableTo": "Apparaat is beschikbaar voor...",
"LabelDirectory": "Map", "LabelDirectory": "Map",
"LabelDiscFromFilename": "Schijf uit bestandsnaam", "LabelDiscFromFilename": "Schijf uit bestandsnaam",
"LabelDiscFromMetadata": "Schijf uit metadata", "LabelDiscFromMetadata": "Schijf uit metadata",
"LabelDiscover": "Ontdek", "LabelDiscover": "Ontdekken",
"LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} afleveringen",
"LabelDuration": "Duur", "LabelDuration": "Duur",
"LabelDurationComparisonExactMatch": "(exacte overeenkomst)",
"LabelDurationComparisonLonger": "({0} langer)",
"LabelDurationComparisonShorter": "({0} korter)",
"LabelDurationFound": "Gevonden duur:", "LabelDurationFound": "Gevonden duur:",
"LabelEbook": "Ebook",
"LabelEbooks": "Eboeken",
"LabelEdit": "Wijzig", "LabelEdit": "Wijzig",
"LabelEmail": "Email",
"LabelEmailSettingsFromAddress": "Van-adres", "LabelEmailSettingsFromAddress": "Van-adres",
"LabelEmailSettingsRejectUnauthorized": "Ongeautoriseerde certificaten afwijzen",
"LabelEmailSettingsRejectUnauthorizedHelp": "Het uitschakelen van SSL-certificaatvalidatie kan uw verbinding blootstellen aan beveiligingsrisico's, zoals man-in-the-middle-aanvallen. Schakel deze optie alleen uit als u de implicaties begrijpt en de mailserver waarmee u verbinding maakt vertrouwt.",
"LabelEmailSettingsSecure": "Veilig", "LabelEmailSettingsSecure": "Veilig",
"LabelEmailSettingsSecureHelp": "Als 'waar', dan gebruikt de verbinding TLS om met de server te verbinden. Als 'onwaar', dan wordt TLS gebruikt als de server de STARTTLS-extensie ondersteunt. In de meeste gevallen kies je voor 'waar' verbindt met poort 465. Voo poort 587 of 25, laat op 'onwaar'. (van nodemailer.com/smtp/#authentication)", "LabelEmailSettingsSecureHelp": "Als 'waar', dan gebruikt de verbinding TLS om met de server te verbinden. Als 'onwaar', dan wordt TLS gebruikt als de server de STARTTLS-extensie ondersteunt. In de meeste gevallen kies je voor 'waar' verbindt met poort 465. Voo poort 587 of 25, laat op 'onwaar'. (van nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Test-adres", "LabelEmailSettingsTestAddress": "Test-adres",
"LabelEmbeddedCover": "Ingesloten cover", "LabelEmbeddedCover": "Ingesloten cover",
"LabelEnable": "Inschakelen", "LabelEnable": "Inschakelen",
"LabelEncodingBackupLocation": "Er wordt een back-up van uw originele audiobestanden opgeslagen in:",
"LabelEncodingChaptersNotEmbedded": "Hoofdstukken zijn niet ingesloten in audioboeken met meerdere sporen.",
"LabelEncodingClearItemCache": "Zorg ervoor dat u de cache van items regelmatig wist.",
"LabelEncodingFinishedM4B": "Een voltooide M4B wordt in uw audioboekfolder geplaatst in:",
"LabelEncodingInfoEmbedded": "Metagegevens worden ingesloten in de audiotracks in uw audioboekmap.",
"LabelEncodingStartedNavigation": "Eenmaal de taak is gestart kan u weg navigeren van deze pagina.",
"LabelEncodingTimeWarning": "Encoding kan tot 30 minuten duren.",
"LabelEncodingWarningAdvancedSettings": "Waarschuwing: update deze instellingen niet tenzij u bekend bent met de coderingsopties van ffmpeg.",
"LabelEncodingWatcherDisabled": "Als u de watcher hebt uitgeschakeld, moet u het audioboek daarna opnieuw scannen.",
"LabelEnd": "Einde", "LabelEnd": "Einde",
"LabelEndOfChapter": "Einde van het Hoofdstuk",
"LabelEpisode": "Aflevering", "LabelEpisode": "Aflevering",
"LabelEpisodeNotLinkedToRssFeed": "Aflevering niet gelinkt aan RSS feed",
"LabelEpisodeNumber": "Aflevering #{0}",
"LabelEpisodeTitle": "Afleveringtitel", "LabelEpisodeTitle": "Afleveringtitel",
"LabelEpisodeType": "Afleveringtype", "LabelEpisodeType": "Afleveringtype",
"LabelEpisodeUrlFromRssFeed": "Aflevering URL van RSS feed",
"LabelEpisodes": "Afleveringen",
"LabelEpisodic": "Episodisch",
"LabelExample": "Voorbeeld", "LabelExample": "Voorbeeld",
"LabelExpandSeries": "Serie Uitvouwen",
"LabelExpandSubSeries": "Subserie Uitvouwen",
"LabelExplicit": "Expliciet", "LabelExplicit": "Expliciet",
"LabelExplicitChecked": "Expliciet (gechecked)",
"LabelExplicitUnchecked": "Niet Expliciet (niet gechecked)",
"LabelExportOPML": "OPML exporteren",
"LabelFeedURL": "Feed URL",
"LabelFetchingMetadata": "Metadata ophalen", "LabelFetchingMetadata": "Metadata ophalen",
"LabelFile": "Bestand", "LabelFile": "Bestand",
"LabelFileBirthtime": "Aanmaaktijd bestand", "LabelFileBirthtime": "Aanmaaktijd bestand",
"LabelFileBornDate": "Geboren {0}",
"LabelFileModified": "Bestand gewijzigd", "LabelFileModified": "Bestand gewijzigd",
"LabelFileModifiedDate": "Gewijzigd {0}",
"LabelFilename": "Bestandsnaam", "LabelFilename": "Bestandsnaam",
"LabelFilterByUser": "Filter op gebruiker", "LabelFilterByUser": "Filter op gebruiker",
"LabelFindEpisodes": "Zoek afleveringen", "LabelFindEpisodes": "Zoek afleveringen",
@@ -256,18 +354,29 @@
"LabelFolder": "Map", "LabelFolder": "Map",
"LabelFolders": "Mappen", "LabelFolders": "Mappen",
"LabelFontBold": "Vetgedrukt", "LabelFontBold": "Vetgedrukt",
"LabelFontBoldness": "Font Boldness",
"LabelFontFamily": "Lettertypefamilie", "LabelFontFamily": "Lettertypefamilie",
"LabelFontItalic": "Cursief",
"LabelFontScale": "Lettertype schaal", "LabelFontScale": "Lettertype schaal",
"LabelFontStrikethrough": "Doorgestreept",
"LabelFormat": "Formaat", "LabelFormat": "Formaat",
"LabelFull": "Vol",
"LabelGenre": "Genre",
"LabelGenres": "Genres",
"LabelHardDeleteFile": "Hard-delete bestand", "LabelHardDeleteFile": "Hard-delete bestand",
"LabelHasEbook": "Heeft ebook", "LabelHasEbook": "Heeft Ebook",
"LabelHasSupplementaryEbook": "Heeft supplementair ebook", "LabelHasSupplementaryEbook": "Heeft aanvullend Ebook",
"LabelHideSubtitles": "Ondertitels Verstoppen",
"LabelHighestPriority": "Hoogste Prioriteit",
"LabelHost": "Host",
"LabelHour": "Uur", "LabelHour": "Uur",
"LabelHours": "Uren", "LabelHours": "Uren",
"LabelIcon": "Icoon", "LabelIcon": "Icoon",
"LabelImageURLFromTheWeb": "Afbeelding URL van web",
"LabelInProgress": "Bezig", "LabelInProgress": "Bezig",
"LabelIncludeInTracklist": "Includeer in tracklijst", "LabelIncludeInTracklist": "Includeer in tracklijst",
"LabelIncomplete": "Incompleet", "LabelIncomplete": "Incompleet",
"LabelInterval": "Interval",
"LabelIntervalCustomDailyWeekly": "Aangepast dagelijks/wekelijks", "LabelIntervalCustomDailyWeekly": "Aangepast dagelijks/wekelijks",
"LabelIntervalEvery12Hours": "Iedere 12 uur", "LabelIntervalEvery12Hours": "Iedere 12 uur",
"LabelIntervalEvery15Minutes": "Iedere 15 minuten", "LabelIntervalEvery15Minutes": "Iedere 15 minuten",
@@ -278,32 +387,52 @@
"LabelIntervalEveryHour": "Ieder uur", "LabelIntervalEveryHour": "Ieder uur",
"LabelInvert": "Omdraaien", "LabelInvert": "Omdraaien",
"LabelItem": "Onderdeel", "LabelItem": "Onderdeel",
"LabelJumpBackwardAmount": "Terugspoelen hoeveelheid",
"LabelJumpForwardAmount": "Vooruitspoelen hoeveelheid",
"LabelLanguage": "Taal", "LabelLanguage": "Taal",
"LabelLanguageDefaultServer": "Standaard servertaal", "LabelLanguageDefaultServer": "Standaard servertaal",
"LabelLanguages": "Talen",
"LabelLastBookAdded": "Laatst toegevoegde boek", "LabelLastBookAdded": "Laatst toegevoegde boek",
"LabelLastBookUpdated": "Laatst bijgewerkte boek", "LabelLastBookUpdated": "Laatst bijgewerkte boek",
"LabelLastSeen": "Laatst gezien", "LabelLastSeen": "Laatst gezien",
"LabelLastTime": "Laatste keer", "LabelLastTime": "Laatste keer",
"LabelLastUpdate": "Laatste update", "LabelLastUpdate": "Laatste update",
"LabelLayout": "Layout",
"LabelLayoutSinglePage": "Enkele pagina", "LabelLayoutSinglePage": "Enkele pagina",
"LabelLayoutSplitPage": "Gesplitste pagina", "LabelLayoutSplitPage": "Gesplitste pagina",
"LabelLess": "Minder", "LabelLess": "Minder",
"LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken", "LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken",
"LabelLibrary": "Bibliotheek", "LabelLibrary": "Bibliotheek",
"LabelLibraryFilterSublistEmpty": "Nee {0}",
"LabelLibraryItem": "Bibliotheekonderdeel", "LabelLibraryItem": "Bibliotheekonderdeel",
"LabelLibraryName": "Bibliotheeknaam", "LabelLibraryName": "Bibliotheeknaam",
"LabelLimit": "Limiet", "LabelLimit": "Limiet",
"LabelLineSpacing": "Regelruimte", "LabelLineSpacing": "Regelruimte",
"LabelListenAgain": "Luister opnieuw", "LabelListenAgain": "Opnieuw Beluisteren",
"LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Informatie",
"LabelLogLevelWarn": "Waarschuwing", "LabelLogLevelWarn": "Waarschuwing",
"LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum", "LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum",
"LabelLowestPriority": "Laagste Prioriteit",
"LabelMatchExistingUsersBy": "Bestaande gebruikers matchen op",
"LabelMatchExistingUsersByDescription": "Wordt gebruikt om bestaande gebruikers te verbinden. Zodra ze verbonden zijn, worden gebruikers gekoppeld aan een unieke id van uw SSO-provider.",
"LabelMaxEpisodesToDownload": "Maximale # afleveringen om te downloaden. Gebruik 0 voor ongelimiteerd.",
"LabelMaxEpisodesToDownloadPerCheck": "Maximale # nieuwe afleveringen om te downloaden per check",
"LabelMaxEpisodesToKeep": "Maximale # afleveringen om te houden",
"LabelMaxEpisodesToKeepHelp": "Waarde van 0 stelt geen maximumlimiet in. Nadat een nieuwe aflevering automatisch is gedownload, wordt de oudste aflevering verwijderd als u meer dan X afleveringen hebt. Hiermee wordt slechts 1 aflevering per nieuwe download verwijderd.",
"LabelMediaPlayer": "Mediaspeler", "LabelMediaPlayer": "Mediaspeler",
"LabelMediaType": "Mediatype", "LabelMediaType": "Mediatype",
"LabelMetaTag": "Meta-tag", "LabelMetaTag": "Meta-tag",
"LabelMetaTags": "Meta-tags", "LabelMetaTags": "Meta-tags",
"LabelMetadataOrderOfPrecedenceDescription": "Metadatabronnen met een hogere prioriteit zullen metadatabronnen met een lagere prioriteit overschrijven",
"LabelMetadataProvider": "Metadatabron", "LabelMetadataProvider": "Metadatabron",
"LabelMinute": "Minuut", "LabelMinute": "Minuut",
"LabelMinutes": "Minuten",
"LabelMissing": "Ontbrekend", "LabelMissing": "Ontbrekend",
"LabelMissingEbook": "Heeft geen ebook",
"LabelMissingSupplementaryEbook": "Heeft geen supplementair ebook",
"LabelMobileRedirectURIs": "Toegestane mobiele omleidings-URL's",
"LabelMobileRedirectURIsDescription": "Dit is een whitelist met geldige redirect-URI's voor mobiele apps. De standaard is <code>audiobookshelf://oauth</code>, die u kunt verwijderen of aanvullen met extra URI's voor integratie met apps van derden. Als u een asterisk (<code>*</code>) als enige invoer gebruikt, is elke URI toegestaan.",
"LabelMore": "Meer", "LabelMore": "Meer",
"LabelMoreInfo": "Meer info", "LabelMoreInfo": "Meer info",
"LabelName": "Naam", "LabelName": "Naam",
@@ -311,14 +440,16 @@
"LabelNarrators": "Vertellers", "LabelNarrators": "Vertellers",
"LabelNew": "Nieuw", "LabelNew": "Nieuw",
"LabelNewPassword": "Nieuw wachtwoord", "LabelNewPassword": "Nieuw wachtwoord",
"LabelNewestAuthors": "Nieuwste auteurs", "LabelNewestAuthors": "Nieuwste Auteurs",
"LabelNewestEpisodes": "Nieuwste afleveringen", "LabelNewestEpisodes": "Nieuwste Afleveringen",
"LabelNextBackupDate": "Volgende back-up datum", "LabelNextBackupDate": "Volgende back-up datum",
"LabelNextScheduledRun": "Volgende geplande run", "LabelNextScheduledRun": "Volgende geplande run",
"LabelNoCustomMetadataProviders": "Geen custom metadata bronnen",
"LabelNoEpisodesSelected": "Geen afleveringen geselecteerd", "LabelNoEpisodesSelected": "Geen afleveringen geselecteerd",
"LabelNotFinished": "Niet Voltooid", "LabelNotFinished": "Niet Voltooid",
"LabelNotStarted": "Niet Gestart", "LabelNotStarted": "Niet Gestart",
"LabelNotes": "Notities", "LabelNotes": "Notities",
"LabelNotificationAppriseURL": "URL(s) van kennisgeving",
"LabelNotificationAvailableVariables": "Beschikbare variabelen", "LabelNotificationAvailableVariables": "Beschikbare variabelen",
"LabelNotificationBodyTemplate": "Body-template", "LabelNotificationBodyTemplate": "Body-template",
"LabelNotificationEvent": "Notificatie gebeurtenis", "LabelNotificationEvent": "Notificatie gebeurtenis",
@@ -329,10 +460,15 @@
"LabelNotificationsMaxQueueSizeHelp": "Gebeurtenissen zijn beperkt tot 1 aftrap per seconde. Gebeurtenissen zullen genegeerd worden als de rij aan de maximale grootte zit. Dit voorkomt notificatie-spamming.", "LabelNotificationsMaxQueueSizeHelp": "Gebeurtenissen zijn beperkt tot 1 aftrap per seconde. Gebeurtenissen zullen genegeerd worden als de rij aan de maximale grootte zit. Dit voorkomt notificatie-spamming.",
"LabelNumberOfBooks": "Aantal Boeken", "LabelNumberOfBooks": "Aantal Boeken",
"LabelNumberOfEpisodes": "# afleveringen", "LabelNumberOfEpisodes": "# afleveringen",
"LabelOpenIDAdvancedPermsClaimDescription": "Naam van de OpenID-claim die geavanceerde machtigingen bevat voor gebruikersacties binnen de applicatie die van toepassing zijn op niet-beheerdersrollen (<b>indien geconfigureerd</b>). Als de claim ontbreekt in het antwoord, wordt toegang tot ABS geweigerd. Als er één optie ontbreekt, wordt deze behandeld als <code>false</code>. Zorg ervoor dat de claim van de identiteitsprovider overeenkomt met de verwachte structuur:",
"LabelOpenIDClaims": "Laat de volgende opties leeg om geavanceerde groeps- en machtigingstoewijzing uit te schakelen en de groep 'Gebruiker' automatisch toe te wijzen.",
"LabelOpenIDGroupClaimDescription": "Naam van de OpenID-claim die een lijst met de groepen van de gebruiker bevat. Vaak aangeduid als <code>groepen</code>. <b>Indien geconfigureerd</b>, zal de applicatie automatisch rollen toewijzen op basis van de groepslidmaatschappen van de gebruiker, op voorwaarde dat deze groepen hoofdlettergevoelig 'admin', 'gebruiker' of 'gast' worden genoemd in de claim. De claim moet een lijst bevatten en als een gebruiker tot meerdere groepen behoort, zal de applicatie de rol toewijzen die overeenkomt met het hoogste toegangsniveau. Als er geen groep overeenkomt, wordt de toegang geweigerd.",
"LabelOpenRSSFeed": "Open RSS-feed", "LabelOpenRSSFeed": "Open RSS-feed",
"LabelOverwrite": "Overschrijf", "LabelOverwrite": "Overschrijf",
"LabelPaginationPageXOfY": "Pagina {0} van {1}",
"LabelPassword": "Wachtwoord", "LabelPassword": "Wachtwoord",
"LabelPath": "Pad", "LabelPath": "Pad",
"LabelPermanent": "Permanent",
"LabelPermissionsAccessAllLibraries": "Heeft toegang tot all bibliotheken", "LabelPermissionsAccessAllLibraries": "Heeft toegang tot all bibliotheken",
"LabelPermissionsAccessAllTags": "Heeft toegang tot alle tags", "LabelPermissionsAccessAllTags": "Heeft toegang tot alle tags",
"LabelPermissionsAccessExplicitContent": "Heeft toegang tot expliciete inhoud", "LabelPermissionsAccessExplicitContent": "Heeft toegang tot expliciete inhoud",
@@ -340,51 +476,75 @@
"LabelPermissionsDownload": "Kan downloaden", "LabelPermissionsDownload": "Kan downloaden",
"LabelPermissionsUpdate": "Kan bijwerken", "LabelPermissionsUpdate": "Kan bijwerken",
"LabelPermissionsUpload": "Kan uploaden", "LabelPermissionsUpload": "Kan uploaden",
"LabelPersonalYearReview": "Jouw jaar in review ({0})",
"LabelPhotoPathURL": "Foto pad/URL", "LabelPhotoPathURL": "Foto pad/URL",
"LabelPlayMethod": "Afspeelwijze", "LabelPlayMethod": "Afspeelwijze",
"LabelPlayerChapterNumberMarker": "{0} van {1}",
"LabelPlaylists": "Afspeellijsten", "LabelPlaylists": "Afspeellijsten",
"LabelPodcast": "Podcast",
"LabelPodcastSearchRegion": "Podcast zoekregio", "LabelPodcastSearchRegion": "Podcast zoekregio",
"LabelPodcastType": "Podcasttype", "LabelPodcastType": "Podcasttype",
"LabelPodcasts": "Podcasts",
"LabelPort": "Poort", "LabelPort": "Poort",
"LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)", "LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)",
"LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen", "LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen",
"LabelPrimaryEbook": "Primair ebook", "LabelPrimaryEbook": "Primair ebook",
"LabelProgress": "Voortgang", "LabelProgress": "Voortgang",
"LabelProvider": "Bron", "LabelProvider": "Bron",
"LabelProviderAuthorizationValue": "Autorisatie Header Waarde",
"LabelPubDate": "Publicatiedatum", "LabelPubDate": "Publicatiedatum",
"LabelPublishYear": "Jaar van uitgave", "LabelPublishYear": "Jaar van uitgave",
"LabelPublishedDate": "Gepubliceerd {0}",
"LabelPublishedDecade": "Gepubliceerd Decennium",
"LabelPublishedDecades": "Gepubliceerd Decennia",
"LabelPublisher": "Uitgever", "LabelPublisher": "Uitgever",
"LabelPublishers": "Uitgevers",
"LabelRSSFeedCustomOwnerEmail": "Aangepast e-mailadres eigenaar", "LabelRSSFeedCustomOwnerEmail": "Aangepast e-mailadres eigenaar",
"LabelRSSFeedCustomOwnerName": "Aangepaste naam eigenaar", "LabelRSSFeedCustomOwnerName": "Aangepaste naam eigenaar",
"LabelRSSFeedOpen": "RSS-feed open", "LabelRSSFeedOpen": "RSS-feed open",
"LabelRSSFeedPreventIndexing": "Voorkom indexering", "LabelRSSFeedPreventIndexing": "Voorkom indexering",
"LabelRSSFeedSlug": "RSS-feed slug", "LabelRSSFeedSlug": "RSS-feed slug",
"LabelRSSFeedURL": "RSS-feed URL", "LabelRSSFeedURL": "RSS-feed URL",
"LabelRandomly": "Willekeurig",
"LabelReAddSeriesToContinueListening": "Serie opnieuw toevoegen aan verder luisteren",
"LabelRead": "Lees", "LabelRead": "Lees",
"LabelReadAgain": "Lees opnieuw", "LabelReadAgain": "Opnieuw Lezen",
"LabelReadEbookWithoutProgress": "Lees ebook zonder voortgang bij te houden", "LabelReadEbookWithoutProgress": "Lees ebook zonder voortgang bij te houden",
"LabelRecentSeries": "Recente series", "LabelRecentSeries": "Recente Serie",
"LabelRecentlyAdded": "Recent toegevoegd", "LabelRecentlyAdded": "Recent Toegevoegd",
"LabelRecommended": "Aangeraden", "LabelRecommended": "Aangeraden",
"LabelRedo": "Opnieuw",
"LabelRegion": "Regio", "LabelRegion": "Regio",
"LabelReleaseDate": "Verschijningsdatum", "LabelReleaseDate": "Verschijningsdatum",
"LabelRemoveAllMetadataAbs": "Verwijder alle metadata.abs bestanden",
"LabelRemoveAllMetadataJson": "Verwijder alle metadata.json bestanden",
"LabelRemoveCover": "Verwijder cover", "LabelRemoveCover": "Verwijder cover",
"LabelRemoveMetadataFile": "Verwijder metadata bestanden in bibliotheek item folders",
"LabelRemoveMetadataFileHelp": "Verwijder alle metadata.json en metadata.abs bestanden in uw {0} folders.",
"LabelRowsPerPage": "Rijen per pagina",
"LabelSearchTerm": "Zoekterm", "LabelSearchTerm": "Zoekterm",
"LabelSearchTitle": "Zoek titel", "LabelSearchTitle": "Zoek titel",
"LabelSearchTitleOrASIN": "Zoek titel of ASIN", "LabelSearchTitleOrASIN": "Zoek titel of ASIN",
"LabelSeason": "Seizoen", "LabelSeason": "Seizoen",
"LabelSeasonNumber": "Seizoen #{0}",
"LabelSelectAll": "Alles selecteren",
"LabelSelectAllEpisodes": "Selecteer alle afleveringen", "LabelSelectAllEpisodes": "Selecteer alle afleveringen",
"LabelSelectEpisodesShowing": "Selecteer {0} afleveringen laten zien", "LabelSelectEpisodesShowing": "Selecteer {0} afleveringen laten zien",
"LabelSelectUsers": "Selecteer gebruikers",
"LabelSendEbookToDevice": "Stuur ebook naar...", "LabelSendEbookToDevice": "Stuur ebook naar...",
"LabelSequence": "Sequentie", "LabelSequence": "Sequentie",
"LabelSerial": "Serie",
"LabelSeries": "Serie", "LabelSeries": "Serie",
"LabelSeriesName": "Naam serie", "LabelSeriesName": "Naam serie",
"LabelSeriesProgress": "Voortgang serie", "LabelSeriesProgress": "Voortgang serie",
"LabelServerLogLevel": "Server Log Niveau",
"LabelServerYearReview": "Server Jaar in Review ({0})",
"LabelSetEbookAsPrimary": "Stel in als primair", "LabelSetEbookAsPrimary": "Stel in als primair",
"LabelSetEbookAsSupplementary": "Stel in als supplementair", "LabelSetEbookAsSupplementary": "Stel in als supplementair",
"LabelSettingsAudiobooksOnly": "Alleen audiobooks", "LabelSettingsAudiobooksOnly": "Alleen audiobooks",
"LabelSettingsAudiobooksOnlyHelp": "Deze instelling inschakelen zorgt ervoor dat ebook-bestanden genegeerd worden tenzij ze in een audiobook-map staan, in welk geval ze worden ingesteld als supplementaire ebooks", "LabelSettingsAudiobooksOnlyHelp": "Deze instelling inschakelen zorgt ervoor dat ebook-bestanden genegeerd worden tenzij ze in een audiobook-map staan, in welk geval ze worden ingesteld als supplementaire ebooks",
"LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken", "LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken",
"LabelSettingsChromecastSupport": "Chromecast ondersteuning",
"LabelSettingsDateFormat": "Datum format", "LabelSettingsDateFormat": "Datum format",
"LabelSettingsDisableWatcher": "Watcher uitschakelen", "LabelSettingsDisableWatcher": "Watcher uitschakelen",
"LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen", "LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen",
@@ -392,6 +552,8 @@
"LabelSettingsEnableWatcher": "Watcher inschakelen", "LabelSettingsEnableWatcher": "Watcher inschakelen",
"LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen", "LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen",
"LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server", "LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server",
"LabelSettingsEpubsAllowScriptedContent": "Sta scripted content toe in epubs",
"LabelSettingsEpubsAllowScriptedContentHelp": "Sta toe dat epub-bestanden scripts uitvoeren. Het wordt aanbevolen om deze instelling uitgeschakeld te houden, tenzij u de bron van de epub-bestanden vertrouwt.",
"LabelSettingsExperimentalFeatures": "Experimentele functies", "LabelSettingsExperimentalFeatures": "Experimentele functies",
"LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.", "LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.",
"LabelSettingsFindCovers": "Zoek covers", "LabelSettingsFindCovers": "Zoek covers",
@@ -400,6 +562,8 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series die slechts een enkel boek bevatten worden verborgen op de seriespagina en de homepagina-planken.", "LabelSettingsHideSingleBookSeriesHelp": "Series die slechts een enkel boek bevatten worden verborgen op de seriespagina en de homepagina-planken.",
"LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina", "LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina",
"LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek", "LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Sla eedere boeken in Serie Verderzetten over",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "De Continue Series home page shelf toont het eerste boek dat nog niet is begonnen in series waarvan er minstens één is voltooid en er geen boeken in uitvoering zijn. Als u deze instelling inschakelt, wordt de serie voortgezet vanaf het boek dat het verst is voltooid in plaats van het eerste boek dat nog niet is begonnen.",
"LabelSettingsParseSubtitles": "Parseer subtitel", "LabelSettingsParseSubtitles": "Parseer subtitel",
"LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"", "LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"",
"LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata", "LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata",
@@ -415,9 +579,16 @@
"LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel", "LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel",
"LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden", "LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden",
"LabelSettingsTimeFormat": "Tijdformat", "LabelSettingsTimeFormat": "Tijdformat",
"LabelShare": "Delen",
"LabelShareOpen": "Delen Open",
"LabelShareURL": "URL Delen",
"LabelShowAll": "Toon alle", "LabelShowAll": "Toon alle",
"LabelShowSeconds": "Laat seconden zien",
"LabelShowSubtitles": "Laat Ondertitels zien",
"LabelSize": "Grootte", "LabelSize": "Grootte",
"LabelSleepTimer": "Slaaptimer", "LabelSleepTimer": "Slaaptimer",
"LabelSlug": "Slak",
"LabelStart": "Start",
"LabelStartTime": "Starttijd", "LabelStartTime": "Starttijd",
"LabelStarted": "Gestart", "LabelStarted": "Gestart",
"LabelStartedAt": "Gestart op", "LabelStartedAt": "Gestart op",
@@ -438,13 +609,24 @@
"LabelStatsWeekListening": "Week luisterend", "LabelStatsWeekListening": "Week luisterend",
"LabelSubtitle": "Subtitel", "LabelSubtitle": "Subtitel",
"LabelSupportedFileTypes": "Ondersteunde bestandstypes", "LabelSupportedFileTypes": "Ondersteunde bestandstypes",
"LabelTag": "Tag",
"LabelTags": "Tags",
"LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker", "LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker",
"LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker", "LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker",
"LabelTasks": "Lopende taken", "LabelTasks": "Lopende taken",
"LabelTextEditorBulletedList": "Opgesomde lijst",
"LabelTextEditorLink": "Link",
"LabelTextEditorNumberedList": "Genummerde lijst",
"LabelTextEditorUnlink": "Unlink",
"LabelTheme": "Thema", "LabelTheme": "Thema",
"LabelThemeDark": "Donker", "LabelThemeDark": "Donker",
"LabelThemeLight": "Licht", "LabelThemeLight": "Licht",
"LabelTimeBase": "Tijdsbasis", "LabelTimeBase": "Tijdsbasis",
"LabelTimeDurationXHours": "{0} Uren",
"LabelTimeDurationXMinutes": "{0} minuten",
"LabelTimeDurationXSeconds": "{0} seconden",
"LabelTimeInMinutes": "Tijd in minuten",
"LabelTimeLeft": "{0} over",
"LabelTimeListened": "Tijd geluisterd", "LabelTimeListened": "Tijd geluisterd",
"LabelTimeListenedToday": "Tijd geluisterd vandaag", "LabelTimeListenedToday": "Tijd geluisterd vandaag",
"LabelTimeRemaining": "{0} te gaan", "LabelTimeRemaining": "{0} te gaan",
@@ -452,6 +634,7 @@
"LabelTitle": "Titel", "LabelTitle": "Titel",
"LabelToolsEmbedMetadata": "Metadata insluiten", "LabelToolsEmbedMetadata": "Metadata insluiten",
"LabelToolsEmbedMetadataDescription": "Metadata insluiten in audiobestanden, inclusief coverafbeelding en hoofdstukken.", "LabelToolsEmbedMetadataDescription": "Metadata insluiten in audiobestanden, inclusief coverafbeelding en hoofdstukken.",
"LabelToolsM4bEncoder": "M4B Encoder",
"LabelToolsMakeM4b": "Maak M4B-audioboekbestand", "LabelToolsMakeM4b": "Maak M4B-audioboekbestand",
"LabelToolsMakeM4bDescription": "Genereer een .M4B-audioboekbestand met ingesloten metadata, coverafbeelding en hoofdstukken.", "LabelToolsMakeM4bDescription": "Genereer een .M4B-audioboekbestand met ingesloten metadata, coverafbeelding en hoofdstukken.",
"LabelToolsSplitM4b": "Splitst M4B in MP3's", "LabelToolsSplitM4b": "Splitst M4B in MP3's",
@@ -460,11 +643,16 @@
"LabelTotalTimeListened": "Totale tijd geluisterd", "LabelTotalTimeListened": "Totale tijd geluisterd",
"LabelTrackFromFilename": "Track vanuit bestandsnaam", "LabelTrackFromFilename": "Track vanuit bestandsnaam",
"LabelTrackFromMetadata": "Track vanuit metadata", "LabelTrackFromMetadata": "Track vanuit metadata",
"LabelTracks": "Audiosporen",
"LabelTracksMultiTrack": "Multi-spoor",
"LabelTracksNone": "Geen tracks", "LabelTracksNone": "Geen tracks",
"LabelTracksSingleTrack": "Enkele track", "LabelTracksSingleTrack": "Enkele track",
"LabelTrailer": "Trailer",
"LabelType": "Type",
"LabelUnabridged": "Onverkort", "LabelUnabridged": "Onverkort",
"LabelUndo": "Ongedaan maken", "LabelUndo": "Ongedaan maken",
"LabelUnknown": "Onbekend", "LabelUnknown": "Onbekend",
"LabelUnknownPublishDate": "Onbekende uitgeefdatum",
"LabelUpdateCover": "Cover bijwerken", "LabelUpdateCover": "Cover bijwerken",
"LabelUpdateCoverHelp": "Sta overschrijven van bestaande covers toe voor de geselecteerde boeken wanneer een match is gevonden", "LabelUpdateCoverHelp": "Sta overschrijven van bestaande covers toe voor de geselecteerde boeken wanneer een match is gevonden",
"LabelUpdateDetails": "Details bijwerken", "LabelUpdateDetails": "Details bijwerken",
@@ -472,16 +660,25 @@
"LabelUpdatedAt": "Bijgewerkt op", "LabelUpdatedAt": "Bijgewerkt op",
"LabelUploaderDragAndDrop": "Slepen & neerzeten van bestanden of mappen", "LabelUploaderDragAndDrop": "Slepen & neerzeten van bestanden of mappen",
"LabelUploaderDropFiles": "Bestanden neerzetten", "LabelUploaderDropFiles": "Bestanden neerzetten",
"LabelUploaderItemFetchMetadataHelp": "Automatisch titel, auteur en serie ophalen",
"LabelUseAdvancedOptions": "Gebruik Geavanceerde Instellingen",
"LabelUseChapterTrack": "Gebruik hoofdstuktrack", "LabelUseChapterTrack": "Gebruik hoofdstuktrack",
"LabelUseFullTrack": "Gebruik volledige track", "LabelUseFullTrack": "Gebruik volledige track",
"LabelUseZeroForUnlimited": "Gebruik 0 voor ongelimiteerd",
"LabelUser": "Gebruiker", "LabelUser": "Gebruiker",
"LabelUsername": "Gebruikersnaam", "LabelUsername": "Gebruikersnaam",
"LabelValue": "Waarde", "LabelValue": "Waarde",
"LabelVersion": "Versie", "LabelVersion": "Versie",
"LabelViewBookmarks": "Bekijk boekwijzers", "LabelViewBookmarks": "Bekijk boekwijzers",
"LabelViewChapters": "Bekijk hoofdstukken", "LabelViewChapters": "Bekijk hoofdstukken",
"LabelViewPlayerSettings": "Laat spelerinstellingen zien",
"LabelViewQueue": "Bekijk afspeelwachtrij", "LabelViewQueue": "Bekijk afspeelwachtrij",
"LabelVolume": "Volume",
"LabelWeekdaysToRun": "Weekdagen om te draaien", "LabelWeekdaysToRun": "Weekdagen om te draaien",
"LabelXBooks": "{0} boeken",
"LabelXItems": "{0} items",
"LabelYearReviewHide": "Verberg Jaar in Review",
"LabelYearReviewShow": "Laat Jaar in Review zien",
"LabelYourAudiobookDuration": "Je audioboekduur", "LabelYourAudiobookDuration": "Je audioboekduur",
"LabelYourBookmarks": "Je boekwijzers", "LabelYourBookmarks": "Je boekwijzers",
"LabelYourPlaylists": "Je afspeellijsten", "LabelYourPlaylists": "Je afspeellijsten",
@@ -489,10 +686,14 @@
"MessageAddToPlayerQueue": "Toevoegen aan wachtrij", "MessageAddToPlayerQueue": "Toevoegen aan wachtrij",
"MessageAppriseDescription": "Om deze functie te gebruiken heb je een draaiende instantie van <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nodig of een api die dezelfde requests afhandelt. <br />De Apprise API Url moet het volledige URL-pad zijn om de notificatie te verzenden, b.v., als je API-instantie draait op <code>http://192.168.1.1:8337</code> dan zou je <code>http://192.168.1.1:8337/notify</code> gebruiken.", "MessageAppriseDescription": "Om deze functie te gebruiken heb je een draaiende instantie van <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nodig of een api die dezelfde requests afhandelt. <br />De Apprise API Url moet het volledige URL-pad zijn om de notificatie te verzenden, b.v., als je API-instantie draait op <code>http://192.168.1.1:8337</code> dan zou je <code>http://192.168.1.1:8337/notify</code> gebruiken.",
"MessageBackupsDescription": "Back-ups omvatten gebruikers, gebruikers' voortgang, bibliotheekonderdeeldetails, serverinstellingen en afbeeldingen bewaard in <code>/metadata/items</code> & <code>/metadata/authors</code>. Back-ups <strong>bevatten niet</strong> de bestanden bewaard in je bibliotheekmappen.", "MessageBackupsDescription": "Back-ups omvatten gebruikers, gebruikers' voortgang, bibliotheekonderdeeldetails, serverinstellingen en afbeeldingen bewaard in <code>/metadata/items</code> & <code>/metadata/authors</code>. Back-ups <strong>bevatten niet</strong> de bestanden bewaard in je bibliotheekmappen.",
"MessageBackupsLocationEditNote": "Let op: het bijwerken van de back-uplocatie zal bestaande back-ups niet verplaatsen of wijzigen",
"MessageBackupsLocationNoEditNote": "Let op: De back-uplocatie wordt ingesteld via een omgevingsvariabele en kan hier niet worden gewijzigd.",
"MessageBackupsLocationPathEmpty": "Backup locatie pad kan niet leeg zijn",
"MessageBatchQuickMatchDescription": "Quick Match zal proberen ontbrekende covers en metadata voor de geselecteerde onderdelen te matchten. Schakel de opties hieronder in om Quick Match toe te staan bestaande covers en/of metadata te overschrijven.", "MessageBatchQuickMatchDescription": "Quick Match zal proberen ontbrekende covers en metadata voor de geselecteerde onderdelen te matchten. Schakel de opties hieronder in om Quick Match toe te staan bestaande covers en/of metadata te overschrijven.",
"MessageBookshelfNoCollections": "Je hebt nog geen collecties gemaakt", "MessageBookshelfNoCollections": "Je hebt nog geen collecties gemaakt",
"MessageBookshelfNoRSSFeeds": "Geen RSS-feeds geopend", "MessageBookshelfNoRSSFeeds": "Geen RSS-feeds geopend",
"MessageBookshelfNoResultsForFilter": "Geen resultaten voor filter \"{0}: {1}\"", "MessageBookshelfNoResultsForFilter": "Geen resultaten voor filter \"{0}: {1}\"",
"MessageBookshelfNoResultsForQuery": "Geen resultaten voor query",
"MessageBookshelfNoSeries": "Je hebt geen series", "MessageBookshelfNoSeries": "Je hebt geen series",
"MessageChapterEndIsAfter": "Hoofdstukeinde is na het einde van je audioboek", "MessageChapterEndIsAfter": "Hoofdstukeinde is na het einde van je audioboek",
"MessageChapterErrorFirstNotZero": "Eerste hoofdstuk moet starten op 0", "MessageChapterErrorFirstNotZero": "Eerste hoofdstuk moet starten op 0",
@@ -500,21 +701,37 @@
"MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk", "MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk",
"MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek", "MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek",
"MessageCheckingCron": "Cron aan het checken...", "MessageCheckingCron": "Cron aan het checken...",
"MessageConfirmCloseFeed": "Ben je zeker dat je deze feed wil sluiten?",
"MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?", "MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?",
"MessageConfirmDeleteDevice": "Ben je zeker dat je e-reader apparaat \"{0}\" wil verwijderen?",
"MessageConfirmDeleteFile": "Dit verwijdert het bestand uit het bestandssysteem. Weet je het zeker?", "MessageConfirmDeleteFile": "Dit verwijdert het bestand uit het bestandssysteem. Weet je het zeker?",
"MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?", "MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?",
"MessageConfirmDeleteLibraryItem": "Hiermee wordt het bibliotheekitem uit de database en uw bestandssysteem verwijderd. Bent u zeker?",
"MessageConfirmDeleteLibraryItems": "Hiermee worden {0} bibliotheekitems uit de database en uw bestandssysteem verwijderd. Bent u zeker?",
"MessageConfirmDeleteMetadataProvider": "Weet u zeker dat u de aangepaste metadataprovider \"{0}\" wilt verwijderen?",
"MessageConfirmDeleteNotification": "Weet u zeker dat u deze melding wil verwijderen?",
"MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?", "MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?",
"MessageConfirmEmbedMetadataInAudioFiles": "Weet u zeker dat u metagegevens wilt insluiten in {0} audiobestanden?",
"MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?", "MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?",
"MessageConfirmMarkAllEpisodesFinished": "Weet je zeker dat je alle afleveringen als voltooid wil markeren?", "MessageConfirmMarkAllEpisodesFinished": "Weet je zeker dat je alle afleveringen als voltooid wil markeren?",
"MessageConfirmMarkAllEpisodesNotFinished": "Weet je zeker dat je alle afleveringen als niet-voltooid wil markeren?", "MessageConfirmMarkAllEpisodesNotFinished": "Weet je zeker dat je alle afleveringen als niet-voltooid wil markeren?",
"MessageConfirmMarkItemFinished": "Weet u zeker dat u \"{0}\" als voltooid wilt markeren?",
"MessageConfirmMarkItemNotFinished": "Weet u zeker dat u \"{0}\" als niet voltooid wilt markeren?",
"MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?", "MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?",
"MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?", "MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?",
"MessageConfirmNotificationTestTrigger": "Trigger deze melding met test data?",
"MessageConfirmPurgeCache": "Met Purge cache wordt de gehele directory op <code>/metadata/cache</code> verwijderd. <br /><br />Weet u zeker dat u de cachedirectory wilt verwijderen?",
"MessageConfirmPurgeItemsCache": "Met Purge items cache wordt de gehele directory op <code>/metadata/cache/items</code> verwijderd.<br />Weet u het zeker?",
"MessageConfirmQuickEmbed": "Waarschuwing! Quick embed maakt geen back-up van uw audiobestanden. Zorg ervoor dat u een back-up van uw audiobestanden hebt. <br><br>Wilt u doorgaan?",
"MessageConfirmQuickMatchEpisodes": "Snel matchende afleveringen overschrijven details als er een match is gevonden. Alleen niet-matchende afleveringen worden bijgewerkt. Weet u het zeker?",
"MessageConfirmReScanLibraryItems": "Bent u zeker dat u {0} items opnieuw wil scannen?",
"MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?", "MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?",
"MessageConfirmRemoveAuthor": "Weet je zeker dat je auteur \"{0}\" wil verwijderen?", "MessageConfirmRemoveAuthor": "Weet je zeker dat je auteur \"{0}\" wil verwijderen?",
"MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?", "MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?",
"MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?", "MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?",
"MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?", "MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?",
"MessageConfirmRemoveListeningSessions": "Weet je zeker dat je {0} luistersessies wilt verwijderen?", "MessageConfirmRemoveListeningSessions": "Weet je zeker dat je {0} luistersessies wilt verwijderen?",
"MessageConfirmRemoveMetadataFiles": "Bent u zeker dat u alle metadata wil verwijderen. {0} bestanden in uw bibliotheel item folders?",
"MessageConfirmRemoveNarrator": "Weet je zeker dat je verteller \"{0}\" wil verwijderen?", "MessageConfirmRemoveNarrator": "Weet je zeker dat je verteller \"{0}\" wil verwijderen?",
"MessageConfirmRemovePlaylist": "Weet je zeker dat je je afspeellijst \"{0}\" wil verwijderen?", "MessageConfirmRemovePlaylist": "Weet je zeker dat je je afspeellijst \"{0}\" wil verwijderen?",
"MessageConfirmRenameGenre": "Weet je zeker dat je genre \"{0}\" wil hernoemen naar \"{1}\" voor alle onderdelen?", "MessageConfirmRenameGenre": "Weet je zeker dat je genre \"{0}\" wil hernoemen naar \"{1}\" voor alle onderdelen?",
@@ -523,11 +740,16 @@
"MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?", "MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?",
"MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.", "MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.",
"MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".", "MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".",
"MessageConfirmResetProgress": "Bet u zeker dat u uw voortgang wil resetten?",
"MessageConfirmSendEbookToDevice": "Weet je zeker dat je {0} ebook \"{1}\" naar apparaat \"{2}\" wil sturen?", "MessageConfirmSendEbookToDevice": "Weet je zeker dat je {0} ebook \"{1}\" naar apparaat \"{2}\" wil sturen?",
"MessageConfirmUnlinkOpenId": "Bent u zeker dat u deze gebruiker wil ontkoppelen van OpenID?",
"MessageDownloadingEpisode": "Aflevering aan het dowloaden", "MessageDownloadingEpisode": "Aflevering aan het dowloaden",
"MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde", "MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde",
"MessageEmbedFailed": "Insluiten Mislukt!",
"MessageEmbedFinished": "Insluiting voltooid!", "MessageEmbedFinished": "Insluiting voltooid!",
"MessageEmbedQueue": "In de wachtrij voor metadata-embed ({0} in wachtrij)",
"MessageEpisodesQueuedForDownload": "{0} aflevering(en) in de rij om te downloaden", "MessageEpisodesQueuedForDownload": "{0} aflevering(en) in de rij om te downloaden",
"MessageEreaderDevices": "Om de levering van e-books te garanderen, moet u mogelijk bovenstaand e-mailadres opgeven als geldige afzender voor elk hieronder vermeld apparaat.",
"MessageFeedURLWillBe": "Feed URL zal {0} zijn", "MessageFeedURLWillBe": "Feed URL zal {0} zijn",
"MessageFetching": "Aan het ophalen...", "MessageFetching": "Aan het ophalen...",
"MessageForceReScanDescription": "zal alle bestanden opnieuw scannen als een verse scan. Audiobestanden ID3-tags, OPF-bestanden en textbestanden zullen als nieuw worden gescand.", "MessageForceReScanDescription": "zal alle bestanden opnieuw scannen als een verse scan. Audiobestanden ID3-tags, OPF-bestanden en textbestanden zullen als nieuw worden gescand.",
@@ -539,6 +761,7 @@
"MessageListeningSessionsInTheLastYear": "{0} luistersessies in het laatste jaar", "MessageListeningSessionsInTheLastYear": "{0} luistersessies in het laatste jaar",
"MessageLoading": "Aan het laden...", "MessageLoading": "Aan het laden...",
"MessageLoadingFolders": "Mappen aan het laden...", "MessageLoadingFolders": "Mappen aan het laden...",
"MessageLogsDescription": "Logs worden opgeslagen in <code>/metadata/logs</code> als JSON-bestanden. Crashlogs worden opgeslagen in <code>/metadata/logs/crash_logs.txt</code>.",
"MessageM4BFailed": "M4B mislukt!", "MessageM4BFailed": "M4B mislukt!",
"MessageM4BFinished": "M4B voltooid!", "MessageM4BFinished": "M4B voltooid!",
"MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden", "MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden",
@@ -555,6 +778,7 @@
"MessageNoCollections": "Geen collecties", "MessageNoCollections": "Geen collecties",
"MessageNoCoversFound": "Geen covers gevonden", "MessageNoCoversFound": "Geen covers gevonden",
"MessageNoDescription": "Geen beschrijving", "MessageNoDescription": "Geen beschrijving",
"MessageNoDevices": "Geen Apparaten",
"MessageNoDownloadsInProgress": "Geen downloads bezig op dit moment", "MessageNoDownloadsInProgress": "Geen downloads bezig op dit moment",
"MessageNoDownloadsQueued": "Geen downloads in de wachtrij", "MessageNoDownloadsQueued": "Geen downloads in de wachtrij",
"MessageNoEpisodeMatchesFound": "Geen afleveringsmatches gevonden", "MessageNoEpisodeMatchesFound": "Geen afleveringsmatches gevonden",
@@ -568,6 +792,7 @@
"MessageNoLogs": "Geen logs", "MessageNoLogs": "Geen logs",
"MessageNoMediaProgress": "Geen mediavoortgang", "MessageNoMediaProgress": "Geen mediavoortgang",
"MessageNoNotifications": "Geen notificaties", "MessageNoNotifications": "Geen notificaties",
"MessageNoPodcastFeed": "Ongeldige podcast: Geen Feed",
"MessageNoPodcastsFound": "Geen podcasts gevonden", "MessageNoPodcastsFound": "Geen podcasts gevonden",
"MessageNoResults": "Geen resultaten", "MessageNoResults": "Geen resultaten",
"MessageNoSearchResultsFor": "Geen zoekresultaten voor \"{0}\"", "MessageNoSearchResultsFor": "Geen zoekresultaten voor \"{0}\"",
@@ -577,11 +802,17 @@
"MessageNoUpdatesWereNecessary": "Geen bijwerkingen waren noodzakelijk", "MessageNoUpdatesWereNecessary": "Geen bijwerkingen waren noodzakelijk",
"MessageNoUserPlaylists": "Je hebt geen afspeellijsten", "MessageNoUserPlaylists": "Je hebt geen afspeellijsten",
"MessageNotYetImplemented": "Nog niet geimplementeerd", "MessageNotYetImplemented": "Nog niet geimplementeerd",
"MessageOpmlPreviewNote": "Let op: Dit is een preview van het geparseerde OPML-bestand. De werkelijke podcasttitel wordt overgenomen uit de RSS-feed.",
"MessageOr": "of", "MessageOr": "of",
"MessagePauseChapter": "Pauzeer afspelen hoofdstuk", "MessagePauseChapter": "Pauzeer afspelen hoofdstuk",
"MessagePlayChapter": "Luister naar begin van hoofdstuk", "MessagePlayChapter": "Luister naar begin van hoofdstuk",
"MessagePlaylistCreateFromCollection": "Afspeellijst aanmaken vanuit collectie", "MessagePlaylistCreateFromCollection": "Afspeellijst aanmaken vanuit collectie",
"MessagePleaseWait": "Even geduld...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast heeft geen RSS-feed URL om te gebruiken voor matching", "MessagePodcastHasNoRSSFeedForMatching": "Podcast heeft geen RSS-feed URL om te gebruiken voor matching",
"MessagePodcastSearchField": "Voer zoekterm of RSS-feed-URL in",
"MessageQuickEmbedInProgress": "Snelle inbedding in uitvoering",
"MessageQuickEmbedQueue": "In de wachtrij voor snelle insluiting ({0} in wachtrij)",
"MessageQuickMatchAllEpisodes": "Alle Afleveringen Snel Matchen",
"MessageQuickMatchDescription": "Vul lege onderdeeldetails & cover met eerste matchresultaat van '{0}'. Overschrijft geen details tenzij 'Prefereer gematchte metadata' serverinstelling is ingeschakeld.", "MessageQuickMatchDescription": "Vul lege onderdeeldetails & cover met eerste matchresultaat van '{0}'. Overschrijft geen details tenzij 'Prefereer gematchte metadata' serverinstelling is ingeschakeld.",
"MessageRemoveChapter": "Verwijder hoofdstuk", "MessageRemoveChapter": "Verwijder hoofdstuk",
"MessageRemoveEpisodes": "Verwijder {0} aflevering(en)", "MessageRemoveEpisodes": "Verwijder {0} aflevering(en)",
@@ -592,10 +823,48 @@
"MessageRestoreBackupConfirm": "Weet je zeker dat je wil herstellen met behulp van de back-up gemaakt op", "MessageRestoreBackupConfirm": "Weet je zeker dat je wil herstellen met behulp van de back-up gemaakt op",
"MessageRestoreBackupWarning": "Herstellen met een back-up zal de volledige database in /config en de covers in /metadata/items & /metadata/authors overschrijven.<br /><br />Back-ups wijzigen geen bestanden in je bibliotheekmappen. Als je de serverinstelling gebruikt om covers en metadata in je bibliotheekmappen te bewaren dan worden deze niet geback-upt of overschreven.<br /><br />Alle clients die van je server gebruik maken zullen automatisch worden ververst.", "MessageRestoreBackupWarning": "Herstellen met een back-up zal de volledige database in /config en de covers in /metadata/items & /metadata/authors overschrijven.<br /><br />Back-ups wijzigen geen bestanden in je bibliotheekmappen. Als je de serverinstelling gebruikt om covers en metadata in je bibliotheekmappen te bewaren dan worden deze niet geback-upt of overschreven.<br /><br />Alle clients die van je server gebruik maken zullen automatisch worden ververst.",
"MessageSearchResultsFor": "Zoekresultaten voor", "MessageSearchResultsFor": "Zoekresultaten voor",
"MessageSelected": "{0} geselecteerd",
"MessageServerCouldNotBeReached": "Server niet bereikbaar", "MessageServerCouldNotBeReached": "Server niet bereikbaar",
"MessageSetChaptersFromTracksDescription": "Stel hoofdstukken in met ieder audiobestand als een hoofdstuk en de audiobestandsnaam als hoofdstuktitel", "MessageSetChaptersFromTracksDescription": "Stel hoofdstukken in met ieder audiobestand als een hoofdstuk en de audiobestandsnaam als hoofdstuktitel",
"MessageShareExpirationWillBe": "Vervaldatum is <strong>{0}</strong>",
"MessageShareExpiresIn": "Vervalt in {0}", "MessageShareExpiresIn": "Vervalt in {0}",
"MessageShareURLWillBe": "De gedeelde URL wordt <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Afspelen van \"{0}\" beginnen op {1}?", "MessageStartPlaybackAtTime": "Afspelen van \"{0}\" beginnen op {1}?",
"MessageTaskAudioFileNotWritable": "Audiobestand \"{0}\" is niet beschrijfbaar",
"MessageTaskCanceledByUser": "Taak geannuleerd door gebruiker",
"MessageTaskDownloadingEpisodeDescription": "Aflevering \"{0}\" downloaden",
"MessageTaskEmbeddingMetadata": "Metadata insluiten",
"MessageTaskEmbeddingMetadataDescription": "Metadata insluiten in audioboek \"{0}\"",
"MessageTaskEncodingM4b": "M4B Encoden",
"MessageTaskEncodingM4bDescription": "Audioboek \"{0}\" coderen in één m4b-bestand",
"MessageTaskFailed": "Mislukt",
"MessageTaskFailedToBackupAudioFile": "Het is niet gelukt om een back-up te maken van audiobestand \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "Het is niet gelukt om een cachemap te maken",
"MessageTaskFailedToEmbedMetadataInFile": "Het is niet gelukt om metagegevens in bestand \"{0}\" in te sluiten",
"MessageTaskFailedToMergeAudioFiles": "Audiobestanden samenvoegen mislukt",
"MessageTaskFailedToMoveM4bFile": "m4b bestand verplaatsen mislukt",
"MessageTaskFailedToWriteMetadataFile": "Metadata bestand schrijven mislukt",
"MessageTaskMatchingBooksInLibrary": "Overeenkomende boeken in bibliotheek \"{0}\"",
"MessageTaskNoFilesToScan": "Geen bestanden om te scannen",
"MessageTaskOpmlImport": "OPML importeren",
"MessageTaskOpmlImportDescription": "Podcasts maken van {0} RSS feeds",
"MessageTaskOpmlImportFeed": "OPML feed importeren",
"MessageTaskOpmlImportFeedDescription": "RSS feed \"{0}\" importeren",
"MessageTaskOpmlImportFeedFailed": "Podcastfeed kon niet worden opgehaald",
"MessageTaskOpmlImportFeedPodcastDescription": "Podcast \"{0}\" maken",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast bestaat al in pad",
"MessageTaskOpmlImportFeedPodcastFailed": "Mislukt om podcast aan te maken",
"MessageTaskOpmlImportFinished": "{0} podcasts toegevoegd",
"MessageTaskOpmlParseFailed": "Het is niet gelukt om het OPML-bestand te parseren",
"MessageTaskOpmlParseFastFail": "Ongeldig OPML-bestand <opml> tag niet gevonden OF een <outline> tag is niet gevonden",
"MessageTaskOpmlParseNoneFound": "Geen feeds gevonden in OPML bestand",
"MessageTaskScanItemsAdded": "{0} toegevoegd",
"MessageTaskScanItemsMissing": "{0} missend",
"MessageTaskScanItemsUpdated": "{0} bijgewerkt",
"MessageTaskScanNoChangesNeeded": "Geen aanpassingen nodig",
"MessageTaskScanningFileChanges": "Scannen van bestandswijzigingen in \"{0}\"",
"MessageTaskScanningLibrary": "Scannen van bibliotheek \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "Doelmap is niet beschrijfbaar",
"MessageThinking": "Aan het denken...", "MessageThinking": "Aan het denken...",
"MessageUploaderItemFailed": "Uploaden mislukt", "MessageUploaderItemFailed": "Uploaden mislukt",
"MessageUploaderItemSuccess": "Uploaden gelukt!", "MessageUploaderItemSuccess": "Uploaden gelukt!",
@@ -613,40 +882,104 @@
"NoteUploaderFoldersWithMediaFiles": "Mappen met mediabestanden zullen worden behandeld als aparte bibliotheekonderdelen.", "NoteUploaderFoldersWithMediaFiles": "Mappen met mediabestanden zullen worden behandeld als aparte bibliotheekonderdelen.",
"NoteUploaderOnlyAudioFiles": "Bij uploaden van uitsluitend audiobestanden wordt ieder audiobestand als apart audiobook worden behandeld.", "NoteUploaderOnlyAudioFiles": "Bij uploaden van uitsluitend audiobestanden wordt ieder audiobestand als apart audiobook worden behandeld.",
"NoteUploaderUnsupportedFiles": "Niet-ondersteunde bestanden worden genegeerd. Bij het kiezen of neerzetten van een map worden andere bestanden die niet in de map staan genegeerd.", "NoteUploaderUnsupportedFiles": "Niet-ondersteunde bestanden worden genegeerd. Bij het kiezen of neerzetten van een map worden andere bestanden die niet in de map staan genegeerd.",
"NotificationOnBackupCompletedDescription": "Wordt geactiveerd wanneer een back-up is voltooid",
"NotificationOnBackupFailedDescription": "Wordt geactiveerd wanneer een back-up mislukt",
"NotificationOnEpisodeDownloadedDescription": "Wordt geactiveerd wanneer een podcastaflevering automatisch wordt gedownload",
"NotificationOnTestDescription": "Event voor het testen van het notificatiesysteem",
"PlaceholderNewCollection": "Nieuwe naam collectie", "PlaceholderNewCollection": "Nieuwe naam collectie",
"PlaceholderNewFolderPath": "Nieuwe locatie map", "PlaceholderNewFolderPath": "Nieuwe locatie map",
"PlaceholderNewPlaylist": "Nieuwe naam afspeellijst", "PlaceholderNewPlaylist": "Nieuwe naam afspeellijst",
"PlaceholderSearch": "Zoeken..", "PlaceholderSearch": "Zoeken..",
"PlaceholderSearchEpisode": "Aflevering zoeken..", "PlaceholderSearchEpisode": "Aflevering zoeken..",
"StatsAuthorsAdded": "auteurs toegevoegd",
"StatsBooksAdded": "boeken toegevoegd",
"StatsBooksAdditional": "Enkele toevoegingen zijn…",
"StatsBooksFinished": "boeken voltooid",
"StatsBooksFinishedThisYear": "Enkele boeken voltooid dit jaar…",
"StatsBooksListenedTo": "geluisterde boeken",
"StatsCollectionGrewTo": "Je boeken collectie groeide tot…",
"StatsSessions": "sessies",
"StatsSpentListening": "tijd geluisterd",
"StatsTopAuthor": "TOP AUTEUR",
"StatsTopAuthors": "TOP AUTEURS",
"StatsTopGenre": "TOP GENRE",
"StatsTopGenres": "TOP GENRES",
"StatsTopMonth": "TOP MAAND",
"StatsTopNarrator": "TOP VERTELLER",
"StatsTopNarrators": "TOP VERTELLERS",
"StatsTotalDuration": "Met een totale tijd van…",
"StatsYearInReview": "JAAR IN REVIEW",
"ToastAccountUpdateSuccess": "Account bijgewerkt", "ToastAccountUpdateSuccess": "Account bijgewerkt",
"ToastAppriseUrlRequired": "Moet een Apprise URL invoeren",
"ToastAsinRequired": "ASIN is vereist",
"ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd", "ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd",
"ToastAuthorNotFound": "Auteur \"{0}\" niet gevonden",
"ToastAuthorRemoveSuccess": "Auteur verwijderd",
"ToastAuthorSearchNotFound": "Auteur niet gevonden",
"ToastAuthorUpdateMerged": "Auteur samengevoegd", "ToastAuthorUpdateMerged": "Auteur samengevoegd",
"ToastAuthorUpdateSuccess": "Auteur bijgewerkt", "ToastAuthorUpdateSuccess": "Auteur bijgewerkt",
"ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)", "ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)",
"ToastBackupAppliedSuccess": "Backup toegepast",
"ToastBackupCreateFailed": "Back-up maken mislukt", "ToastBackupCreateFailed": "Back-up maken mislukt",
"ToastBackupCreateSuccess": "Back-up gemaakt", "ToastBackupCreateSuccess": "Back-up gemaakt",
"ToastBackupDeleteFailed": "Verwijderen back-up mislukt", "ToastBackupDeleteFailed": "Verwijderen back-up mislukt",
"ToastBackupDeleteSuccess": "Back-up verwijderd", "ToastBackupDeleteSuccess": "Back-up verwijderd",
"ToastBackupInvalidMaxKeep": "Ongeldig aantal backups om bij te houden",
"ToastBackupInvalidMaxSize": "Ongeldige maximum backupgrootte",
"ToastBackupRestoreFailed": "Herstellen back-up mislukt", "ToastBackupRestoreFailed": "Herstellen back-up mislukt",
"ToastBackupUploadFailed": "Uploaden back-up mislukt", "ToastBackupUploadFailed": "Uploaden back-up mislukt",
"ToastBackupUploadSuccess": "Back-up geüpload", "ToastBackupUploadSuccess": "Back-up geüpload",
"ToastBatchDeleteFailed": "Batch verwijderen mislukt",
"ToastBatchDeleteSuccess": "Batch verwijderen gelukt",
"ToastBatchQuickMatchFailed": "Batch Snel Vergelijken mislukt!",
"ToastBatchQuickMatchStarted": "Bulk Snel Vergelijken van {0} boeken gestart!",
"ToastBatchUpdateFailed": "Bulk-bijwerking mislukt", "ToastBatchUpdateFailed": "Bulk-bijwerking mislukt",
"ToastBatchUpdateSuccess": "Bulk-bijwerking gelukt", "ToastBatchUpdateSuccess": "Bulk-bijwerking gelukt",
"ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt", "ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt",
"ToastBookmarkCreateSuccess": "boekwijzer toegevoegd", "ToastBookmarkCreateSuccess": "boekwijzer toegevoegd",
"ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd", "ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd",
"ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt", "ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt",
"ToastCachePurgeFailed": "Cache wissen is mislukt",
"ToastCachePurgeSuccess": "Cache succesvol verwijderd",
"ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten", "ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten",
"ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben", "ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben",
"ToastChaptersRemoved": "Hoofdstukken verwijderd",
"ToastChaptersUpdated": "Hoofdstukken bijgewerkt",
"ToastCollectionItemsAddFailed": "Item(s) toegevoegd aan collectie mislukt",
"ToastCollectionItemsAddSuccess": "Item(s) toegevoegd aan collectie gelukt",
"ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie", "ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie",
"ToastCollectionRemoveSuccess": "Collectie verwijderd", "ToastCollectionRemoveSuccess": "Collectie verwijderd",
"ToastCollectionUpdateSuccess": "Collectie bijgewerkt", "ToastCollectionUpdateSuccess": "Collectie bijgewerkt",
"ToastCoverUpdateFailed": "Cover update mislukt",
"ToastDeleteFileFailed": "Bestand verwijderen mislukt",
"ToastDeleteFileSuccess": "Bestand verwijderd",
"ToastDeviceAddFailed": "Apparaat toevoegen mislukt",
"ToastDeviceNameAlreadyExists": "Er bestaat al een e-reader met die naam",
"ToastDeviceTestEmailFailed": "Het is niet gelukt om een test-e-mail te verzenden",
"ToastDeviceTestEmailSuccess": "Test e-mail verzonden",
"ToastEmailSettingsUpdateSuccess": "Emaill intellingen bijgewerkt",
"ToastEncodeCancelFailed": "Het is niet gelukt om het coderen te annuleren",
"ToastEncodeCancelSucces": "Encode geannuleerd",
"ToastEpisodeDownloadQueueClearFailed": "Wachtrij legen mislukt",
"ToastEpisodeDownloadQueueClearSuccess": "Aflevering download-wachtrij geleegt",
"ToastEpisodeUpdateSuccess": "{0} afleveringen bijgewerkt",
"ToastErrorCannotShare": "Kan niet native delen op dit apparaat",
"ToastFailedToLoadData": "Data laden mislukt",
"ToastFailedToMatch": "Match mislukt",
"ToastFailedToShare": "Delen mislukt",
"ToastFailedToUpdate": "Update mislukt",
"ToastInvalidImageUrl": "Ongeldige afbeeldings-URL",
"ToastInvalidMaxEpisodesToDownload": "Ongeldig maximum aantal afleveringen om te downloaden",
"ToastInvalidUrl": "Ongeldige URL",
"ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt", "ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt",
"ToastItemDeletedFailed": "Item verwijderen mislukt",
"ToastItemDeletedSuccess": "Verwijderd item",
"ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt", "ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt",
"ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt", "ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt",
"ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid", "ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid",
"ToastItemMarkedAsNotFinishedFailed": "Markeren als Niet Voltooid mislukt", "ToastItemMarkedAsNotFinishedFailed": "Markeren als Niet Voltooid mislukt",
"ToastItemMarkedAsNotFinishedSuccess": "Onderdeel gemarkeerd als Niet Voltooid", "ToastItemMarkedAsNotFinishedSuccess": "Onderdeel gemarkeerd als Niet Voltooid",
"ToastItemUpdateSuccess": "Item bijgewerkt",
"ToastLibraryCreateFailed": "Bibliotheek aanmaken mislukt", "ToastLibraryCreateFailed": "Bibliotheek aanmaken mislukt",
"ToastLibraryCreateSuccess": "Bibliotheek \"{0}\" aangemaakt", "ToastLibraryCreateSuccess": "Bibliotheek \"{0}\" aangemaakt",
"ToastLibraryDeleteFailed": "Bibliotheek verwijderen mislukt", "ToastLibraryDeleteFailed": "Bibliotheek verwijderen mislukt",
@@ -654,25 +987,83 @@
"ToastLibraryScanFailedToStart": "Starten scan mislukt", "ToastLibraryScanFailedToStart": "Starten scan mislukt",
"ToastLibraryScanStarted": "Scannen bibliotheek gestart", "ToastLibraryScanStarted": "Scannen bibliotheek gestart",
"ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt", "ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt",
"ToastMatchAllAuthorsFailed": "Alle auteurs matchen mislukt",
"ToastMetadataFilesRemovedError": "Fout bij verwijderen van metadata. {0} bestanden",
"ToastMetadataFilesRemovedNoneFound": "Geen metadata. {0} bestanden gevonden in bibliotheek",
"ToastMetadataFilesRemovedNoneRemoved": "Geen metadata. {0} bestanden verwijderd",
"ToastMetadataFilesRemovedSuccess": "{0} metadata. {1} bestanden verwijderd",
"ToastMustHaveAtLeastOnePath": "Moet ten minste een pad hebben",
"ToastNameEmailRequired": "Naam en email zijn vereist",
"ToastNameRequired": "Naam is vereist",
"ToastNewEpisodesFound": "{0} nieuwe afleveringen gevonden",
"ToastNewUserCreatedFailed": "Account: \"{0}\" aanmaken mislukt",
"ToastNewUserCreatedSuccess": "Nieuw account aangemaakt",
"ToastNewUserLibraryError": "Moet ten minste een bibliotheek selecteren",
"ToastNewUserPasswordError": "Moet een wachtwoord hebben, enkel root gebruiker kan een leeg wachtwoord gebruiken",
"ToastNewUserTagError": "Moet ten minste een tag selecteren",
"ToastNewUserUsernameError": "Voer een gebruikersnaam in",
"ToastNoNewEpisodesFound": "Geen nieuwe afleveringen gevonden",
"ToastNoUpdatesNecessary": "Geen updates nodig",
"ToastNotificationCreateFailed": "Nieuwe melding aanmaken mislukt",
"ToastNotificationDeleteFailed": "Melding verwijderen mislukt",
"ToastNotificationFailedMaximum": "Maximum aantal pogingen moet >=0",
"ToastNotificationQueueMaximum": "Maximale meldingen wachtrij moet >=0",
"ToastNotificationSettingsUpdateSuccess": "Meldingsinstellingen bijgewerkt",
"ToastNotificationTestTriggerFailed": "Het is niet gelukt om een testmelding te activeren",
"ToastNotificationTestTriggerSuccess": "Geactiveerde testmelding",
"ToastNotificationUpdateSuccess": "Melding bijgewerkt",
"ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt", "ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt",
"ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt", "ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt",
"ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd", "ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd",
"ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt", "ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt",
"ToastPodcastCreateFailed": "Podcast aanmaken mislukt", "ToastPodcastCreateFailed": "Podcast aanmaken mislukt",
"ToastPodcastCreateSuccess": "Podcast aangemaakt", "ToastPodcastCreateSuccess": "Podcast aangemaakt",
"ToastPodcastGetFeedFailed": "Podcast feed ophalen mislukt",
"ToastPodcastNoEpisodesInFeed": "Geen afleveringen gevonden in RSS feed",
"ToastPodcastNoRssFeed": "Podcast heeft geen RSS feed",
"ToastProgressIsNotBeingSynced": "De voortgang wordt niet gesynchroniseerd, start het afspelen opnieuw",
"ToastProviderCreatedFailed": "Provider toevoegen mislukt",
"ToastProviderCreatedSuccess": "Nieuwe provider toegevoegd",
"ToastProviderNameAndUrlRequired": "Naam en URL vereist",
"ToastProviderRemoveSuccess": "Provider verwijderd",
"ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt", "ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt",
"ToastRSSFeedCloseSuccess": "RSS-feed gesloten", "ToastRSSFeedCloseSuccess": "RSS-feed gesloten",
"ToastRemoveFailed": "Verwijderen mislukt",
"ToastRemoveItemFromCollectionFailed": "Onderdeel verwijderen uit collectie mislukt", "ToastRemoveItemFromCollectionFailed": "Onderdeel verwijderen uit collectie mislukt",
"ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie", "ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie",
"ToastRemoveItemsWithIssuesFailed": "Verwijderen van bibliotheekitems met problemen mislukt",
"ToastRemoveItemsWithIssuesSuccess": "Bibliotheekitems met problemen verwijderd",
"ToastRenameFailed": "Hernoemen mislukt",
"ToastRescanFailed": "Opnieuw scannen mislukt voor {0}",
"ToastRescanRemoved": "Opnieuw scannen voltooid, item is verwijderd",
"ToastRescanUpToDate": "Rescan voltooid, item is up to date",
"ToastRescanUpdated": "Rescan voltooid, item is geupdated",
"ToastScanFailed": "Bibliotheek item scannen mislukt",
"ToastSelectAtLeastOneUser": "Selecteer ten minste een gebruiker",
"ToastSendEbookToDeviceFailed": "Ebook naar apparaat sturen mislukt", "ToastSendEbookToDeviceFailed": "Ebook naar apparaat sturen mislukt",
"ToastSendEbookToDeviceSuccess": "Ebook verstuurd naar apparaat \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook verstuurd naar apparaat \"{0}\"",
"ToastSeriesUpdateFailed": "Bijwerken serie mislukt", "ToastSeriesUpdateFailed": "Bijwerken serie mislukt",
"ToastSeriesUpdateSuccess": "Bijwerken serie gelukt", "ToastSeriesUpdateSuccess": "Bijwerken serie gelukt",
"ToastServerSettingsUpdateSuccess": "Server instellingen bijgewerkt",
"ToastSessionCloseFailed": "Sessie sluiten mislukt",
"ToastSessionDeleteFailed": "Verwijderen sessie mislukt", "ToastSessionDeleteFailed": "Verwijderen sessie mislukt",
"ToastSessionDeleteSuccess": "Sessie verwijderd", "ToastSessionDeleteSuccess": "Sessie verwijderd",
"ToastSleepTimerDone": "Slaap timer voltooid... zZzzZz",
"ToastSlugMustChange": "Slug bevat ongeldige symbolen",
"ToastSlugRequired": "Slug is vereist",
"ToastSocketConnected": "Socket verbonden", "ToastSocketConnected": "Socket verbonden",
"ToastSocketDisconnected": "Socket niet verbonden", "ToastSocketDisconnected": "Socket niet verbonden",
"ToastSocketFailedToConnect": "Verbinding Socket mislukt", "ToastSocketFailedToConnect": "Verbinding Socket mislukt",
"ToastSortingPrefixesEmptyError": "Moet ten minste 1 sorteer-prefix bevatten",
"ToastSortingPrefixesUpdateSuccess": "Sorteer prefixes geupdated ({0} items)",
"ToastTitleRequired": "Titel is vereist",
"ToastUnknownError": "Onbekende fout",
"ToastUnlinkOpenIdFailed": "Gebruiker ontkoppelen van OpenID mislukt",
"ToastUnlinkOpenIdSuccess": "Gebruiker ontkoppeld van OpenID",
"ToastUserDeleteFailed": "Verwijderen gebruiker mislukt", "ToastUserDeleteFailed": "Verwijderen gebruiker mislukt",
"ToastUserDeleteSuccess": "Gebruiker verwijderd" "ToastUserDeleteSuccess": "Gebruiker verwijderd",
"ToastUserPasswordChangeSuccess": "Wachtwoord succesvol gewijzigd",
"ToastUserPasswordMismatch": "Wachtwoorden komen niet overeen",
"ToastUserPasswordMustChange": "Het nieuwe wachtwoord kan niet overeenkomen met het oude wachtwoord",
"ToastUserRootRequireName": "U moet een root-gebruikersnaam invoeren"
} }
+14 -2
View File
@@ -64,6 +64,7 @@
"ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji", "ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji",
"ButtonQueueAddItem": "Dodaj do kolejki", "ButtonQueueAddItem": "Dodaj do kolejki",
"ButtonQueueRemoveItem": "Usuń z kolejki", "ButtonQueueRemoveItem": "Usuń z kolejki",
"ButtonQuickEmbed": "Szybkie wstawienie",
"ButtonQuickEmbedMetadata": "Szybkie wstawianie metadanych", "ButtonQuickEmbedMetadata": "Szybkie wstawianie metadanych",
"ButtonQuickMatch": "Szybkie dopasowanie", "ButtonQuickMatch": "Szybkie dopasowanie",
"ButtonReScan": "Ponowne skanowanie", "ButtonReScan": "Ponowne skanowanie",
@@ -95,7 +96,7 @@
"ButtonStartM4BEncode": "Eksportuj jako plik M4B", "ButtonStartM4BEncode": "Eksportuj jako plik M4B",
"ButtonStartMetadataEmbed": "Osadź metadane", "ButtonStartMetadataEmbed": "Osadź metadane",
"ButtonStats": "Statystyki", "ButtonStats": "Statystyki",
"ButtonSubmit": "Zaloguj", "ButtonSubmit": "Zapisz",
"ButtonTest": "Test", "ButtonTest": "Test",
"ButtonUnlinkOpenId": "Odłącz OpenID", "ButtonUnlinkOpenId": "Odłącz OpenID",
"ButtonUpload": "Wgraj", "ButtonUpload": "Wgraj",
@@ -138,6 +139,7 @@
"HeaderFindChapters": "Wyszukaj rozdziały", "HeaderFindChapters": "Wyszukaj rozdziały",
"HeaderIgnoredFiles": "Zignoruj pliki", "HeaderIgnoredFiles": "Zignoruj pliki",
"HeaderItemFiles": "Pliki", "HeaderItemFiles": "Pliki",
"HeaderItemMetadataUtils": "Narzędzia dla metadanych",
"HeaderLastListeningSession": "Ostatnia sesja słuchania", "HeaderLastListeningSession": "Ostatnia sesja słuchania",
"HeaderLatestEpisodes": "Najnowsze odcinki", "HeaderLatestEpisodes": "Najnowsze odcinki",
"HeaderLibraries": "Biblioteki", "HeaderLibraries": "Biblioteki",
@@ -176,6 +178,7 @@
"HeaderRemoveEpisodes": "Usuń {0} odcinków", "HeaderRemoveEpisodes": "Usuń {0} odcinków",
"HeaderSavedMediaProgress": "Zapisany postęp", "HeaderSavedMediaProgress": "Zapisany postęp",
"HeaderSchedule": "Harmonogram", "HeaderSchedule": "Harmonogram",
"HeaderScheduleEpisodeDownloads": "Planowanie automatycznego ściągania odcinków",
"HeaderScheduleLibraryScans": "Zaplanuj automatyczne skanowanie biblioteki", "HeaderScheduleLibraryScans": "Zaplanuj automatyczne skanowanie biblioteki",
"HeaderSession": "Sesja", "HeaderSession": "Sesja",
"HeaderSetBackupSchedule": "Ustaw harmonogram tworzenia kopii zapasowej", "HeaderSetBackupSchedule": "Ustaw harmonogram tworzenia kopii zapasowej",
@@ -221,7 +224,11 @@
"LabelAllUsersExcludingGuests": "Wszyscy użytkownicy z wyłączeniem gości", "LabelAllUsersExcludingGuests": "Wszyscy użytkownicy z wyłączeniem gości",
"LabelAllUsersIncludingGuests": "Wszyscy użytkownicy, łącznie z gośćmi", "LabelAllUsersIncludingGuests": "Wszyscy użytkownicy, łącznie z gośćmi",
"LabelAlreadyInYourLibrary": "Już istnieje w twojej bibliotece", "LabelAlreadyInYourLibrary": "Już istnieje w twojej bibliotece",
"LabelApiToken": "API Token",
"LabelAppend": "Dołącz", "LabelAppend": "Dołącz",
"LabelAudioBitrate": "Audio Bitrate (np. 128k)",
"LabelAudioChannels": "Kanały dźwięku (1 lub 2)",
"LabelAudioCodec": "Kodek audio",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Rosnąco)", "LabelAuthorFirstLast": "Autor (Rosnąco)",
"LabelAuthorLastFirst": "Author (Malejąco)", "LabelAuthorLastFirst": "Author (Malejąco)",
@@ -233,6 +240,7 @@
"LabelAutoRegister": "Automatyczna rejestracja", "LabelAutoRegister": "Automatyczna rejestracja",
"LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu", "LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu",
"LabelBackToUser": "Powrót", "LabelBackToUser": "Powrót",
"LabelBackupAudioFiles": "Kopia zapasowa plików audio",
"LabelBackupLocation": "Lokalizacja kopii zapasowej", "LabelBackupLocation": "Lokalizacja kopii zapasowej",
"LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe", "LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe",
"LabelBackupsEnableAutomaticBackupsHelp": "Kopie zapasowe są zapisywane w folderze /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Kopie zapasowe są zapisywane w folderze /metadata/backups",
@@ -241,15 +249,18 @@
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania", "LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.", "LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBonus": "Bonus",
"LabelBooks": "Książki", "LabelBooks": "Książki",
"LabelButtonText": "Tekst przycisku", "LabelButtonText": "Tekst przycisku",
"LabelByAuthor": "autorstwa {0}", "LabelByAuthor": "autorstwa {0}",
"LabelChangePassword": "Zmień hasło", "LabelChangePassword": "Zmień hasło",
"LabelChannels": "Kanały", "LabelChannels": "Kanały",
"LabelChapterCount": "{0} rozdziałów",
"LabelChapterTitle": "Tytuł rozdziału", "LabelChapterTitle": "Tytuł rozdziału",
"LabelChapters": "Rozdziały", "LabelChapters": "Rozdziały",
"LabelChaptersFound": "Znalezione rozdziały", "LabelChaptersFound": "Znalezione rozdziały",
"LabelClickForMoreInfo": "Kliknij po więcej szczegółów", "LabelClickForMoreInfo": "Kliknij po więcej szczegółów",
"LabelClickToUseCurrentValue": "Kliknij by zastosować aktualną wartość",
"LabelClosePlayer": "Zamknij odtwarzacz", "LabelClosePlayer": "Zamknij odtwarzacz",
"LabelCodec": "Kodek", "LabelCodec": "Kodek",
"LabelCollapseSeries": "Podsumuj serię", "LabelCollapseSeries": "Podsumuj serię",
@@ -299,6 +310,7 @@
"LabelEmailSettingsTestAddress": "Adres testowy", "LabelEmailSettingsTestAddress": "Adres testowy",
"LabelEmbeddedCover": "Wbudowana okładka", "LabelEmbeddedCover": "Wbudowana okładka",
"LabelEnable": "Włącz", "LabelEnable": "Włącz",
"LabelEncodingBackupLocation": "Kopia zapasowa twoich oryginalnych plików audio będzie się znajdować w:",
"LabelEnd": "Zakończ", "LabelEnd": "Zakończ",
"LabelEndOfChapter": "Koniec rozdziału", "LabelEndOfChapter": "Koniec rozdziału",
"LabelEpisode": "Odcinek", "LabelEpisode": "Odcinek",
@@ -462,7 +474,7 @@
"LabelReadAgain": "Czytaj ponownie", "LabelReadAgain": "Czytaj ponownie",
"LabelReadEbookWithoutProgress": "Czytaj książkę bez zapamiętywania postępu", "LabelReadEbookWithoutProgress": "Czytaj książkę bez zapamiętywania postępu",
"LabelRecentSeries": "Ostatnie serie", "LabelRecentSeries": "Ostatnie serie",
"LabelRecentlyAdded": "Niedawno dodany", "LabelRecentlyAdded": "Niedawno dodane",
"LabelRecommended": "Polecane", "LabelRecommended": "Polecane",
"LabelRedo": "Wycofaj", "LabelRedo": "Wycofaj",
"LabelReleaseDate": "Data wydania", "LabelReleaseDate": "Data wydania",
+115 -1
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Очистить кэш элементов", "ButtonPurgeItemsCache": "Очистить кэш элементов",
"ButtonQueueAddItem": "Добавить в очередь", "ButtonQueueAddItem": "Добавить в очередь",
"ButtonQueueRemoveItem": "Удалить из очереди", "ButtonQueueRemoveItem": "Удалить из очереди",
"ButtonQuickEmbed": "Быстрое внедрение",
"ButtonQuickEmbedMetadata": "Быстрое встраивание метаданных", "ButtonQuickEmbedMetadata": "Быстрое встраивание метаданных",
"ButtonQuickMatch": "Быстрый поиск", "ButtonQuickMatch": "Быстрый поиск",
"ButtonReScan": "Пересканировать", "ButtonReScan": "Пересканировать",
@@ -162,6 +163,7 @@
"HeaderNotificationUpdate": "Уведомление об обновлении", "HeaderNotificationUpdate": "Уведомление об обновлении",
"HeaderNotifications": "Уведомления", "HeaderNotifications": "Уведомления",
"HeaderOpenIDConnectAuthentication": "Аутентификация OpenID Connect", "HeaderOpenIDConnectAuthentication": "Аутентификация OpenID Connect",
"HeaderOpenListeningSessions": "Открытые сеансы прослушивания",
"HeaderOpenRSSFeed": "Открыть RSS-канал", "HeaderOpenRSSFeed": "Открыть RSS-канал",
"HeaderOtherFiles": "Другие файлы", "HeaderOtherFiles": "Другие файлы",
"HeaderPasswordAuthentication": "Аутентификация по паролю", "HeaderPasswordAuthentication": "Аутентификация по паролю",
@@ -179,6 +181,7 @@
"HeaderRemoveEpisodes": "Удалить {0} эпизодов", "HeaderRemoveEpisodes": "Удалить {0} эпизодов",
"HeaderSavedMediaProgress": "Прогресс медиа сохранен", "HeaderSavedMediaProgress": "Прогресс медиа сохранен",
"HeaderSchedule": "Планировщик", "HeaderSchedule": "Планировщик",
"HeaderScheduleEpisodeDownloads": "Запланируйте автоматическую загрузку эпизодов",
"HeaderScheduleLibraryScans": "Планировщик автоматического сканирования библиотеки", "HeaderScheduleLibraryScans": "Планировщик автоматического сканирования библиотеки",
"HeaderSession": "Сеансы", "HeaderSession": "Сеансы",
"HeaderSetBackupSchedule": "Установить планировщик бэкапов", "HeaderSetBackupSchedule": "Установить планировщик бэкапов",
@@ -224,7 +227,11 @@
"LabelAllUsersExcludingGuests": "Все пользователи, кроме гостей", "LabelAllUsersExcludingGuests": "Все пользователи, кроме гостей",
"LabelAllUsersIncludingGuests": "Все пользователи, включая гостей", "LabelAllUsersIncludingGuests": "Все пользователи, включая гостей",
"LabelAlreadyInYourLibrary": "Уже в Вашей библиотеке", "LabelAlreadyInYourLibrary": "Уже в Вашей библиотеке",
"LabelApiToken": "Токен API",
"LabelAppend": "Добавить", "LabelAppend": "Добавить",
"LabelAudioBitrate": "Битрейт аудио (напр. 128k)",
"LabelAudioChannels": "Аудиоканалы (1 или 2)",
"LabelAudioCodec": "Аудиокодек",
"LabelAuthor": "Автор", "LabelAuthor": "Автор",
"LabelAuthorFirstLast": "Автор (Имя Фамилия)", "LabelAuthorFirstLast": "Автор (Имя Фамилия)",
"LabelAuthorLastFirst": "Автор (Фамилия, Имя)", "LabelAuthorLastFirst": "Автор (Фамилия, Имя)",
@@ -237,6 +244,7 @@
"LabelAutoRegister": "Автоматическая регистрация", "LabelAutoRegister": "Автоматическая регистрация",
"LabelAutoRegisterDescription": "Автоматическое создание новых пользователей после входа в систему", "LabelAutoRegisterDescription": "Автоматическое создание новых пользователей после входа в систему",
"LabelBackToUser": "Назад к пользователю", "LabelBackToUser": "Назад к пользователю",
"LabelBackupAudioFiles": "Резервное копирование аудиофайлов",
"LabelBackupLocation": "Путь для бэкапов", "LabelBackupLocation": "Путь для бэкапов",
"LabelBackupsEnableAutomaticBackups": "Включить автоматическое бэкапирование", "LabelBackupsEnableAutomaticBackups": "Включить автоматическое бэкапирование",
"LabelBackupsEnableAutomaticBackupsHelp": "Бэкапы сохраняются в /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Бэкапы сохраняются в /metadata/backups",
@@ -245,15 +253,18 @@
"LabelBackupsNumberToKeep": "Сохранять бэкапов", "LabelBackupsNumberToKeep": "Сохранять бэкапов",
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.", "LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
"LabelBitrate": "Битрейт", "LabelBitrate": "Битрейт",
"LabelBonus": "Бонус",
"LabelBooks": "Книги", "LabelBooks": "Книги",
"LabelButtonText": "Текст кнопки", "LabelButtonText": "Текст кнопки",
"LabelByAuthor": "{0}", "LabelByAuthor": "{0}",
"LabelChangePassword": "Изменить пароль", "LabelChangePassword": "Изменить пароль",
"LabelChannels": "Каналы", "LabelChannels": "Каналы",
"LabelChapterCount": "{0} Главы",
"LabelChapterTitle": "Название главы", "LabelChapterTitle": "Название главы",
"LabelChapters": "Главы", "LabelChapters": "Главы",
"LabelChaptersFound": "глав найдено", "LabelChaptersFound": "глав найдено",
"LabelClickForMoreInfo": "Нажмите, чтобы узнать больше", "LabelClickForMoreInfo": "Нажмите, чтобы узнать больше",
"LabelClickToUseCurrentValue": "Нажмите, чтобы использовать текущее значение",
"LabelClosePlayer": "Закрыть проигрыватель", "LabelClosePlayer": "Закрыть проигрыватель",
"LabelCodec": "Кодек", "LabelCodec": "Кодек",
"LabelCollapseSeries": "Свернуть серии", "LabelCollapseSeries": "Свернуть серии",
@@ -303,12 +314,25 @@
"LabelEmailSettingsTestAddress": "Тестовый адрес", "LabelEmailSettingsTestAddress": "Тестовый адрес",
"LabelEmbeddedCover": "Встроенная обложка", "LabelEmbeddedCover": "Встроенная обложка",
"LabelEnable": "Включить", "LabelEnable": "Включить",
"LabelEncodingBackupLocation": "Резервная копия ваших оригинальных аудиофайлов будет сохранена в:",
"LabelEncodingChaptersNotEmbedded": "Главы не встраиваются в многодорожечные аудиокниги.",
"LabelEncodingClearItemCache": "Обязательно периодически очищайте кэш элементов.",
"LabelEncodingFinishedM4B": "Готовый M4B будет помещен в вашу папку с аудиокнигами по адресу:",
"LabelEncodingInfoEmbedded": "Метаданные будут встроены в звуковые дорожки внутри папки вашей аудиокниги.",
"LabelEncodingStartedNavigation": "Как только задача будет запущена, вы сможете перейти с этой страницы.",
"LabelEncodingTimeWarning": "Кодирование может занять до 30 минут.",
"LabelEncodingWarningAdvancedSettings": "Предупреждение: Не обновляйте эти настройки, если вы не знакомы с параметрами кодировки ffmpeg.",
"LabelEncodingWatcherDisabled": "Если у вас отключено наблюдение за папкой, вам нужно будет повторно пересканировать эту аудиокнигу.",
"LabelEnd": "Конец", "LabelEnd": "Конец",
"LabelEndOfChapter": "Конец главы", "LabelEndOfChapter": "Конец главы",
"LabelEpisode": "Эпизод", "LabelEpisode": "Эпизод",
"LabelEpisodeNotLinkedToRssFeed": "Эпизод, не связанный с RSS-каналом",
"LabelEpisodeNumber": "Эпизод #{0}",
"LabelEpisodeTitle": "Имя эпизода", "LabelEpisodeTitle": "Имя эпизода",
"LabelEpisodeType": "Тип эпизода", "LabelEpisodeType": "Тип эпизода",
"LabelEpisodeUrlFromRssFeed": "URL-адрес эпизода из RSS-ленты",
"LabelEpisodes": "Эпизодов", "LabelEpisodes": "Эпизодов",
"LabelEpisodic": "Эпизодический",
"LabelExample": "Пример", "LabelExample": "Пример",
"LabelExpandSeries": "Развернуть серию", "LabelExpandSeries": "Развернуть серию",
"LabelExpandSubSeries": "Развернуть подсерию", "LabelExpandSubSeries": "Развернуть подсерию",
@@ -336,6 +360,7 @@
"LabelFontScale": "Масштаб шрифта", "LabelFontScale": "Масштаб шрифта",
"LabelFontStrikethrough": "Зачеркнутый", "LabelFontStrikethrough": "Зачеркнутый",
"LabelFormat": "Формат", "LabelFormat": "Формат",
"LabelFull": "Полный",
"LabelGenre": "Жанр", "LabelGenre": "Жанр",
"LabelGenres": "Жанры", "LabelGenres": "Жанры",
"LabelHardDeleteFile": "Жесткое удаление файла", "LabelHardDeleteFile": "Жесткое удаление файла",
@@ -391,6 +416,10 @@
"LabelLowestPriority": "Самый низкий приоритет", "LabelLowestPriority": "Самый низкий приоритет",
"LabelMatchExistingUsersBy": "Сопоставление существующих пользователей по", "LabelMatchExistingUsersBy": "Сопоставление существующих пользователей по",
"LabelMatchExistingUsersByDescription": "Используется для подключения существующих пользователей. После подключения пользователям будет присвоен уникальный идентификатор от поставщика единого входа", "LabelMatchExistingUsersByDescription": "Используется для подключения существующих пользователей. После подключения пользователям будет присвоен уникальный идентификатор от поставщика единого входа",
"LabelMaxEpisodesToDownload": "Максимальное количество эпизодов для загрузки. Используйте 0 для неограниченного количества.",
"LabelMaxEpisodesToDownloadPerCheck": "Максимальное количество новых эпизодов для загрузки за одну проверку",
"LabelMaxEpisodesToKeep": "Максимальное количество сохраняемых эпизодов",
"LabelMaxEpisodesToKeepHelp": "Значение 0 не устанавливает максимального ограничения. После автоматической загрузки нового эпизода самый старый эпизод будет удален, если у вас более X эпизодов. При этом будет удален только 1 эпизод за каждую новую загрузку.",
"LabelMediaPlayer": "Медиа проигрыватель", "LabelMediaPlayer": "Медиа проигрыватель",
"LabelMediaType": "Тип медиа", "LabelMediaType": "Тип медиа",
"LabelMetaTag": "Мета тег", "LabelMetaTag": "Мета тег",
@@ -436,12 +465,14 @@
"LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.", "LabelOpenIDGroupClaimDescription": "Имя утверждения OpenID, содержащего список групп пользователя. Обычно их называют <code>groups</code>. <b>Если эта настройка</b> настроена, приложение будет автоматически назначать роли на основе членства пользователя в группах при условии, что эти группы названы в утверждении без учета регистра \"admin\", \"user\" или \"guest\". Утверждение должно содержать список, и если пользователь принадлежит к нескольким группам, то приложение назначит роль, соответствующую самому высокому уровню доступа. Если ни одна из групп не совпадает, доступ будет запрещен.",
"LabelOpenRSSFeed": "Открыть RSS-канал", "LabelOpenRSSFeed": "Открыть RSS-канал",
"LabelOverwrite": "Перезаписать", "LabelOverwrite": "Перезаписать",
"LabelPaginationPageXOfY": "Страница {0} из {1}",
"LabelPassword": "Пароль", "LabelPassword": "Пароль",
"LabelPath": "Путь", "LabelPath": "Путь",
"LabelPermanent": "Постоянный", "LabelPermanent": "Постоянный",
"LabelPermissionsAccessAllLibraries": "Есть доступ ко всем библиотекам", "LabelPermissionsAccessAllLibraries": "Есть доступ ко всем библиотекам",
"LabelPermissionsAccessAllTags": "Есть доступ ко всем тегам", "LabelPermissionsAccessAllTags": "Есть доступ ко всем тегам",
"LabelPermissionsAccessExplicitContent": "Есть доступ к явному содержимому", "LabelPermissionsAccessExplicitContent": "Есть доступ к явному содержимому",
"LabelPermissionsCreateEreader": "Можно создать читалку",
"LabelPermissionsDelete": "Может удалять", "LabelPermissionsDelete": "Может удалять",
"LabelPermissionsDownload": "Может скачивать", "LabelPermissionsDownload": "Может скачивать",
"LabelPermissionsUpdate": "Может обновлять", "LabelPermissionsUpdate": "Может обновлять",
@@ -465,6 +496,8 @@
"LabelPubDate": "Дата публикации", "LabelPubDate": "Дата публикации",
"LabelPublishYear": "Год публикации", "LabelPublishYear": "Год публикации",
"LabelPublishedDate": "Опубликовано {0}", "LabelPublishedDate": "Опубликовано {0}",
"LabelPublishedDecade": "Опубликованное десятилетие",
"LabelPublishedDecades": "Опубликованные десятилетия",
"LabelPublisher": "Издатель", "LabelPublisher": "Издатель",
"LabelPublishers": "Издатели", "LabelPublishers": "Издатели",
"LabelRSSFeedCustomOwnerEmail": "Пользовательский Email владельца", "LabelRSSFeedCustomOwnerEmail": "Пользовательский Email владельца",
@@ -484,21 +517,28 @@
"LabelRedo": "Повторить", "LabelRedo": "Повторить",
"LabelRegion": "Регион", "LabelRegion": "Регион",
"LabelReleaseDate": "Дата выхода", "LabelReleaseDate": "Дата выхода",
"LabelRemoveAllMetadataAbs": "Удалите все файлы metadata.abs",
"LabelRemoveAllMetadataJson": "Удалите все файлы metadata.json",
"LabelRemoveCover": "Удалить обложку", "LabelRemoveCover": "Удалить обложку",
"LabelRemoveMetadataFile": "Удаление файлов метаданных в папках элементов библиотеки",
"LabelRemoveMetadataFileHelp": "Удалите все файлы metadata.json и metadata.abs из ваших папок {0}.",
"LabelRowsPerPage": "Строк на странице", "LabelRowsPerPage": "Строк на странице",
"LabelSearchTerm": "Поисковый запрос", "LabelSearchTerm": "Поисковый запрос",
"LabelSearchTitle": "Поиск по названию", "LabelSearchTitle": "Поиск по названию",
"LabelSearchTitleOrASIN": "Поиск по названию или ASIN", "LabelSearchTitleOrASIN": "Поиск по названию или ASIN",
"LabelSeason": "Сезон", "LabelSeason": "Сезон",
"LabelSeasonNumber": "Сезон #{0}",
"LabelSelectAll": "Выбрать все", "LabelSelectAll": "Выбрать все",
"LabelSelectAllEpisodes": "Выбрать все эпизоды", "LabelSelectAllEpisodes": "Выбрать все эпизоды",
"LabelSelectEpisodesShowing": "Выберите {0} эпизодов для показа", "LabelSelectEpisodesShowing": "Выберите {0} эпизодов для показа",
"LabelSelectUsers": "Выбор пользователей", "LabelSelectUsers": "Выбор пользователей",
"LabelSendEbookToDevice": "Отправить e-книгу в...", "LabelSendEbookToDevice": "Отправить e-книгу в...",
"LabelSequence": "Последовательность", "LabelSequence": "Последовательность",
"LabelSerial": "Серийный",
"LabelSeries": "Серия", "LabelSeries": "Серия",
"LabelSeriesName": "Имя серии", "LabelSeriesName": "Имя серии",
"LabelSeriesProgress": "Прогресс серии", "LabelSeriesProgress": "Прогресс серии",
"LabelServerLogLevel": "Уровень журнала сервера",
"LabelServerYearReview": "Итоги года всего сервера ({0})", "LabelServerYearReview": "Итоги года всего сервера ({0})",
"LabelSetEbookAsPrimary": "Установить как основную", "LabelSetEbookAsPrimary": "Установить как основную",
"LabelSetEbookAsSupplementary": "Установить как дополнительную", "LabelSetEbookAsSupplementary": "Установить как дополнительную",
@@ -523,6 +563,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "Серии, в которых всего одна книга, будут скрыты со страницы серий и полок домашней страницы.", "LabelSettingsHideSingleBookSeriesHelp": "Серии, в которых всего одна книга, будут скрыты со страницы серий и полок домашней страницы.",
"LabelSettingsHomePageBookshelfView": "Вид книжной полки на Домашней странице", "LabelSettingsHomePageBookshelfView": "Вид книжной полки на Домашней странице",
"LabelSettingsLibraryBookshelfView": "Вид книжной полки в Библиотеке", "LabelSettingsLibraryBookshelfView": "Вид книжной полки в Библиотеке",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Процент выполнения больше, чем",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Оставшееся время составляет менее (секунд)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Отметьте мультимедийный элемент как законченный, когда",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропустить предыдущие книги в \"Продолжить серию\"", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропустить предыдущие книги в \"Продолжить серию\"",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "На домашней странице \"Продолжить серию\" отображается первая книга, не начатая в серии, в которой закончена хотя бы одна книга и нет начатых книг. При включении этого параметра серия будет продолжена с самой последней завершенной книги, а не с первой, которая не начата.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "На домашней странице \"Продолжить серию\" отображается первая книга, не начатая в серии, в которой закончена хотя бы одна книга и нет начатых книг. При включении этого параметра серия будет продолжена с самой последней завершенной книги, а не с первой, которая не начата.",
"LabelSettingsParseSubtitles": "Разбор подзаголовков", "LabelSettingsParseSubtitles": "Разбор подзаголовков",
@@ -587,13 +630,15 @@
"LabelTimeDurationXMinutes": "{0} минут", "LabelTimeDurationXMinutes": "{0} минут",
"LabelTimeDurationXSeconds": "{0} секунд", "LabelTimeDurationXSeconds": "{0} секунд",
"LabelTimeInMinutes": "Время в минутах", "LabelTimeInMinutes": "Время в минутах",
"LabelTimeLeft": "{0} осталось",
"LabelTimeListened": "Время прослушивания", "LabelTimeListened": "Время прослушивания",
"LabelTimeListenedToday": "Время прослушивания сегодня", "LabelTimeListenedToday": "Время прослушивания сегодня",
"LabelTimeRemaining": "{0} осталось", "LabelTimeRemaining": "{0} осталось",
"LabelTimeToShift": "Время смещения в сек.", "LabelTimeToShift": "Время смещения в секундах",
"LabelTitle": "Название", "LabelTitle": "Название",
"LabelToolsEmbedMetadata": "Встроить метаданные", "LabelToolsEmbedMetadata": "Встроить метаданные",
"LabelToolsEmbedMetadataDescription": "Встроить метаданные в аудио файлы, включая обложку и главы.", "LabelToolsEmbedMetadataDescription": "Встроить метаданные в аудио файлы, включая обложку и главы.",
"LabelToolsM4bEncoder": "Кодировщик M4B",
"LabelToolsMakeM4b": "Создать M4B файл аудиокниги", "LabelToolsMakeM4b": "Создать M4B файл аудиокниги",
"LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.", "LabelToolsMakeM4bDescription": "Создает .M4B файл аудиокниги с встроенными метаданными, обложкой и главами.",
"LabelToolsSplitM4b": "Разделить M4B на MP3 файлы", "LabelToolsSplitM4b": "Разделить M4B на MP3 файлы",
@@ -606,6 +651,7 @@
"LabelTracksMultiTrack": "Мультитрек", "LabelTracksMultiTrack": "Мультитрек",
"LabelTracksNone": "Нет треков", "LabelTracksNone": "Нет треков",
"LabelTracksSingleTrack": "Один трек", "LabelTracksSingleTrack": "Один трек",
"LabelTrailer": "Трейлер",
"LabelType": "Тип", "LabelType": "Тип",
"LabelUnabridged": "Полное издание", "LabelUnabridged": "Полное издание",
"LabelUndo": "Отменить", "LabelUndo": "Отменить",
@@ -619,8 +665,10 @@
"LabelUploaderDragAndDrop": "Перетащите файлы или каталоги", "LabelUploaderDragAndDrop": "Перетащите файлы или каталоги",
"LabelUploaderDropFiles": "Перетащите файлы", "LabelUploaderDropFiles": "Перетащите файлы",
"LabelUploaderItemFetchMetadataHelp": "Автоматическое извлечение названия, автора и серии", "LabelUploaderItemFetchMetadataHelp": "Автоматическое извлечение названия, автора и серии",
"LabelUseAdvancedOptions": "Используйте расширенные опции",
"LabelUseChapterTrack": "Показывать время главы", "LabelUseChapterTrack": "Показывать время главы",
"LabelUseFullTrack": "Показывать время книги", "LabelUseFullTrack": "Показывать время книги",
"LabelUseZeroForUnlimited": "Используйте 0 для неограниченного количества",
"LabelUser": "Пользователь", "LabelUser": "Пользователь",
"LabelUsername": "Имя пользователя", "LabelUsername": "Имя пользователя",
"LabelValue": "Значение", "LabelValue": "Значение",
@@ -667,6 +715,7 @@
"MessageConfirmDeleteMetadataProvider": "Вы уверены, что хотите удалить пользовательский поставщик метаданных \"{0}\"?", "MessageConfirmDeleteMetadataProvider": "Вы уверены, что хотите удалить пользовательский поставщик метаданных \"{0}\"?",
"MessageConfirmDeleteNotification": "Вы уверены, что хотите удалить это уведомление?", "MessageConfirmDeleteNotification": "Вы уверены, что хотите удалить это уведомление?",
"MessageConfirmDeleteSession": "Вы уверены, что хотите удалить этот сеанс?", "MessageConfirmDeleteSession": "Вы уверены, что хотите удалить этот сеанс?",
"MessageConfirmEmbedMetadataInAudioFiles": "Вы уверены, что хотите вставить метаданные в {0} аудиофайлов?",
"MessageConfirmForceReScan": "Вы уверены, что хотите принудительно выполнить повторное сканирование?", "MessageConfirmForceReScan": "Вы уверены, что хотите принудительно выполнить повторное сканирование?",
"MessageConfirmMarkAllEpisodesFinished": "Вы уверены, что хотите отметить все эпизоды как завершенные?", "MessageConfirmMarkAllEpisodesFinished": "Вы уверены, что хотите отметить все эпизоды как завершенные?",
"MessageConfirmMarkAllEpisodesNotFinished": "Вы уверены, что хотите отметить все эпизоды как не завершенные?", "MessageConfirmMarkAllEpisodesNotFinished": "Вы уверены, что хотите отметить все эпизоды как не завершенные?",
@@ -678,6 +727,7 @@
"MessageConfirmPurgeCache": "Очистка кэша удалит весь каталог в <code>/metadata/cache</code>. <br /><br />Вы уверены, что хотите удалить каталог кэша?", "MessageConfirmPurgeCache": "Очистка кэша удалит весь каталог в <code>/metadata/cache</code>. <br /><br />Вы уверены, что хотите удалить каталог кэша?",
"MessageConfirmPurgeItemsCache": "Очистка кэша элементов удалит весь каталог в <code>/metadata/cache/items</code>.<br />Вы уверены?", "MessageConfirmPurgeItemsCache": "Очистка кэша элементов удалит весь каталог в <code>/metadata/cache/items</code>.<br />Вы уверены?",
"MessageConfirmQuickEmbed": "Предупреждение! Быстрое встраивание не позволяет создавать резервные копии аудиофайлов. Убедитесь, что у вас есть резервная копия аудиофайлов. <br><br>Хотите продолжить?", "MessageConfirmQuickEmbed": "Предупреждение! Быстрое встраивание не позволяет создавать резервные копии аудиофайлов. Убедитесь, что у вас есть резервная копия аудиофайлов. <br><br>Хотите продолжить?",
"MessageConfirmQuickMatchEpisodes": "При обнаружении совпадений информация о эпизодах быстрого поиска будет перезаписана. Будут обновлены только несопоставимые эпизоды. Вы уверены?",
"MessageConfirmReScanLibraryItems": "Вы уверены, что хотите пересканировать {0} элементов?", "MessageConfirmReScanLibraryItems": "Вы уверены, что хотите пересканировать {0} элементов?",
"MessageConfirmRemoveAllChapters": "Вы уверены, что хотите удалить все главы?", "MessageConfirmRemoveAllChapters": "Вы уверены, что хотите удалить все главы?",
"MessageConfirmRemoveAuthor": "Вы уверены, что хотите удалить автора \"{0}\"?", "MessageConfirmRemoveAuthor": "Вы уверены, что хотите удалить автора \"{0}\"?",
@@ -685,6 +735,7 @@
"MessageConfirmRemoveEpisode": "Вы уверены, что хотите удалить эпизод \"{0}\"?", "MessageConfirmRemoveEpisode": "Вы уверены, что хотите удалить эпизод \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Вы уверены, что хотите удалить {0} эпизодов?", "MessageConfirmRemoveEpisodes": "Вы уверены, что хотите удалить {0} эпизодов?",
"MessageConfirmRemoveListeningSessions": "Вы уверены, что хотите удалить {0} сеансов прослушивания?", "MessageConfirmRemoveListeningSessions": "Вы уверены, что хотите удалить {0} сеансов прослушивания?",
"MessageConfirmRemoveMetadataFiles": "Вы уверены, что хотите удалить все файлы metadata. {0} файлов из папок элементов вашей библиотеки?",
"MessageConfirmRemoveNarrator": "Вы уверены, что хотите удалить чтеца \"{0}\"?", "MessageConfirmRemoveNarrator": "Вы уверены, что хотите удалить чтеца \"{0}\"?",
"MessageConfirmRemovePlaylist": "Вы уверены, что хотите удалить плейлист \"{0}\"?", "MessageConfirmRemovePlaylist": "Вы уверены, что хотите удалить плейлист \"{0}\"?",
"MessageConfirmRenameGenre": "Вы уверены, что хотите переименовать жанр \"{0}\" в \"{1}\" для всех элементов?", "MessageConfirmRenameGenre": "Вы уверены, что хотите переименовать жанр \"{0}\" в \"{1}\" для всех элементов?",
@@ -700,6 +751,7 @@
"MessageDragFilesIntoTrackOrder": "Перетащите файлы для исправления порядка треков", "MessageDragFilesIntoTrackOrder": "Перетащите файлы для исправления порядка треков",
"MessageEmbedFailed": "Вставка не удалась!", "MessageEmbedFailed": "Вставка не удалась!",
"MessageEmbedFinished": "Встраивание завершено!", "MessageEmbedFinished": "Встраивание завершено!",
"MessageEmbedQueue": "Поставлен в очередь для внедрения метаданных ({0} в очереди)",
"MessageEpisodesQueuedForDownload": "{0} Эпизод(ов) запланировано для закачки", "MessageEpisodesQueuedForDownload": "{0} Эпизод(ов) запланировано для закачки",
"MessageEreaderDevices": "Чтобы обеспечить доставку электронных книг, вам может потребоваться добавить указанный выше адрес электронной почты в качестве действительного отправителя для каждого устройства, перечисленного ниже.", "MessageEreaderDevices": "Чтобы обеспечить доставку электронных книг, вам может потребоваться добавить указанный выше адрес электронной почты в качестве действительного отправителя для каждого устройства, перечисленного ниже.",
"MessageFeedURLWillBe": "URL канала будет {0}", "MessageFeedURLWillBe": "URL канала будет {0}",
@@ -744,6 +796,7 @@
"MessageNoLogs": "Нет логов", "MessageNoLogs": "Нет логов",
"MessageNoMediaProgress": "Нет прогресса медиа", "MessageNoMediaProgress": "Нет прогресса медиа",
"MessageNoNotifications": "Нет уведомлений", "MessageNoNotifications": "Нет уведомлений",
"MessageNoPodcastFeed": "Недопустимый подкаст: Нет канала",
"MessageNoPodcastsFound": "Подкасты не найдены", "MessageNoPodcastsFound": "Подкасты не найдены",
"MessageNoResults": "Нет результатов", "MessageNoResults": "Нет результатов",
"MessageNoSearchResultsFor": "Нет результатов поиска для \"{0}\"", "MessageNoSearchResultsFor": "Нет результатов поиска для \"{0}\"",
@@ -760,6 +813,10 @@
"MessagePlaylistCreateFromCollection": "Создать плейлист из коллекции", "MessagePlaylistCreateFromCollection": "Создать плейлист из коллекции",
"MessagePleaseWait": "Пожалуйста подождите...", "MessagePleaseWait": "Пожалуйста подождите...",
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не имеет URL-адреса RSS-канала, который можно использовать для поиска", "MessagePodcastHasNoRSSFeedForMatching": "Подкаст не имеет URL-адреса RSS-канала, который можно использовать для поиска",
"MessagePodcastSearchField": "Введите поисковый запрос или URL-адрес RSS-канала",
"MessageQuickEmbedInProgress": "Быстрое внедрение в процессе выполнения",
"MessageQuickEmbedQueue": "Поставлен в очередь для быстрого внедрения ({0} в очереди)",
"MessageQuickMatchAllEpisodes": "Быстрое сопоставление всех эпизодов",
"MessageQuickMatchDescription": "Заполняет пустые детали элемента и обложку первым результатом поиска из «{0}». Не перезаписывает сведения, если не включен параметр сервера 'Предпочитать метаданные поиска'.", "MessageQuickMatchDescription": "Заполняет пустые детали элемента и обложку первым результатом поиска из «{0}». Не перезаписывает сведения, если не включен параметр сервера 'Предпочитать метаданные поиска'.",
"MessageRemoveChapter": "Удалить главу", "MessageRemoveChapter": "Удалить главу",
"MessageRemoveEpisodes": "Удалить {0} эпизод(ов)", "MessageRemoveEpisodes": "Удалить {0} эпизод(ов)",
@@ -777,6 +834,41 @@
"MessageShareExpiresIn": "Срок действия истекает через {0}", "MessageShareExpiresIn": "Срок действия истекает через {0}",
"MessageShareURLWillBe": "URL-адрес общего доступа будет <strong>{0}</strong>", "MessageShareURLWillBe": "URL-адрес общего доступа будет <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Начать воспроизведение для \"{0}\" с {1}?", "MessageStartPlaybackAtTime": "Начать воспроизведение для \"{0}\" с {1}?",
"MessageTaskAudioFileNotWritable": "Аудиофайл \"{0}\" недоступен для записи",
"MessageTaskCanceledByUser": "Задание отменено пользователем",
"MessageTaskDownloadingEpisodeDescription": "Загрузка эпизода \"{0}\"",
"MessageTaskEmbeddingMetadata": "Внедрение метаданных",
"MessageTaskEmbeddingMetadataDescription": "Встраивание метаданных в аудиокнигу \"{0}\"",
"MessageTaskEncodingM4b": "Кодировка M4B",
"MessageTaskEncodingM4bDescription": "Кодирование аудиокниги \"{0}\" в один файл формата m4b",
"MessageTaskFailed": "Неудачный",
"MessageTaskFailedToBackupAudioFile": "Не удалось создать резервную копию аудиофайла \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "Не удалось создать каталог кэша",
"MessageTaskFailedToEmbedMetadataInFile": "Не удалось вставить метаданные в файл \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Не удалось объединить аудиофайлы",
"MessageTaskFailedToMoveM4bFile": "Не удалось переместить файл m4b",
"MessageTaskFailedToWriteMetadataFile": "Не удалось записать файл метаданных",
"MessageTaskMatchingBooksInLibrary": "Сопоставление книг в библиотеке \"{0}\"",
"MessageTaskNoFilesToScan": "Нет файлов для сканирования",
"MessageTaskOpmlImport": "Импорт OPML",
"MessageTaskOpmlImportDescription": "Создание подкастов из {0} RSS-каналов",
"MessageTaskOpmlImportFeed": "Канал импорта OPML",
"MessageTaskOpmlImportFeedDescription": "Импорт RSS-канала \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Не удалось получить ленту подкаста",
"MessageTaskOpmlImportFeedPodcastDescription": "Создание подкаста \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Подкаст уже существует по адресу",
"MessageTaskOpmlImportFeedPodcastFailed": "Не удалось создать подкаст",
"MessageTaskOpmlImportFinished": "Добавлено {0} подкастов",
"MessageTaskOpmlParseFailed": "Не удалось разобрать OPML-файл",
"MessageTaskOpmlParseFastFail": "Недопустимый тег <opml> файла OPML не найден ИЛИ тег <outline> не найден",
"MessageTaskOpmlParseNoneFound": "В OPML-файле не найдено ни одного канала",
"MessageTaskScanItemsAdded": "{0} добавлено",
"MessageTaskScanItemsMissing": "{0} отсутствует",
"MessageTaskScanItemsUpdated": "{0} обновлено",
"MessageTaskScanNoChangesNeeded": "Никаких изменений не требуется",
"MessageTaskScanningFileChanges": "Проверка изменений файлов в \"{0}\"",
"MessageTaskScanningLibrary": "Сканирование библиотеки \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "Целевой каталог недоступен для записи",
"MessageThinking": "Думаю...", "MessageThinking": "Думаю...",
"MessageUploaderItemFailed": "Не удалось загрузить", "MessageUploaderItemFailed": "Не удалось загрузить",
"MessageUploaderItemSuccess": "Успешно загружено!", "MessageUploaderItemSuccess": "Успешно загружено!",
@@ -794,6 +886,10 @@
"NoteUploaderFoldersWithMediaFiles": "Папки с медиафайлами будут обрабатываться как отдельные элементы библиотеки.", "NoteUploaderFoldersWithMediaFiles": "Папки с медиафайлами будут обрабатываться как отдельные элементы библиотеки.",
"NoteUploaderOnlyAudioFiles": "Если загружать только аудиофайлы, то каждый аудиофайл будет обрабатываться как отдельная аудиокнига.", "NoteUploaderOnlyAudioFiles": "Если загружать только аудиофайлы, то каждый аудиофайл будет обрабатываться как отдельная аудиокнига.",
"NoteUploaderUnsupportedFiles": "Неподдерживаемые файлы игнорируются. При выборе или удалении папки другие файлы, не находящиеся в папке элемента, игнорируются.", "NoteUploaderUnsupportedFiles": "Неподдерживаемые файлы игнорируются. При выборе или удалении папки другие файлы, не находящиеся в папке элемента, игнорируются.",
"NotificationOnBackupCompletedDescription": "Запускается при завершении резервного копирования",
"NotificationOnBackupFailedDescription": "Срабатывает при сбое резервного копирования",
"NotificationOnEpisodeDownloadedDescription": "Запускается при автоматической загрузке эпизода подкаста",
"NotificationOnTestDescription": "Событие для тестирования системы оповещения",
"PlaceholderNewCollection": "Новое имя коллекции", "PlaceholderNewCollection": "Новое имя коллекции",
"PlaceholderNewFolderPath": "Путь к новой папке", "PlaceholderNewFolderPath": "Путь к новой папке",
"PlaceholderNewPlaylist": "Новое название плейлиста", "PlaceholderNewPlaylist": "Новое название плейлиста",
@@ -819,6 +915,7 @@
"StatsYearInReview": "ИТОГИ ГОДА", "StatsYearInReview": "ИТОГИ ГОДА",
"ToastAccountUpdateSuccess": "Учетная запись обновлена", "ToastAccountUpdateSuccess": "Учетная запись обновлена",
"ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise", "ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise",
"ToastAsinRequired": "Требуется ASIN",
"ToastAuthorImageRemoveSuccess": "Изображение автора удалено", "ToastAuthorImageRemoveSuccess": "Изображение автора удалено",
"ToastAuthorNotFound": "Автор \"{0}\" не найден", "ToastAuthorNotFound": "Автор \"{0}\" не найден",
"ToastAuthorRemoveSuccess": "Автор удален", "ToastAuthorRemoveSuccess": "Автор удален",
@@ -838,6 +935,8 @@
"ToastBackupUploadSuccess": "Бэкап загружен", "ToastBackupUploadSuccess": "Бэкап загружен",
"ToastBatchDeleteFailed": "Не удалось выполнить пакетное удаление", "ToastBatchDeleteFailed": "Не удалось выполнить пакетное удаление",
"ToastBatchDeleteSuccess": "Успешное пакетное удаление", "ToastBatchDeleteSuccess": "Успешное пакетное удаление",
"ToastBatchQuickMatchFailed": "Не удалось выполнить пакетное быстрое сопоставление!",
"ToastBatchQuickMatchStarted": "Начато пакетное быстрое сопоставление {0} книг!",
"ToastBatchUpdateFailed": "Сбой пакетного обновления", "ToastBatchUpdateFailed": "Сбой пакетного обновления",
"ToastBatchUpdateSuccess": "Успешное пакетное обновление", "ToastBatchUpdateSuccess": "Успешное пакетное обновление",
"ToastBookmarkCreateFailed": "Не удалось создать закладку", "ToastBookmarkCreateFailed": "Не удалось создать закладку",
@@ -849,6 +948,7 @@
"ToastChaptersHaveErrors": "Главы имеют ошибки", "ToastChaptersHaveErrors": "Главы имеют ошибки",
"ToastChaptersMustHaveTitles": "Главы должны содержать названия", "ToastChaptersMustHaveTitles": "Главы должны содержать названия",
"ToastChaptersRemoved": "Удалены главы", "ToastChaptersRemoved": "Удалены главы",
"ToastChaptersUpdated": "Обновленные главы",
"ToastCollectionItemsAddFailed": "Не удалось добавить элемент(ы) в коллекцию", "ToastCollectionItemsAddFailed": "Не удалось добавить элемент(ы) в коллекцию",
"ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию", "ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию",
"ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции", "ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции",
@@ -866,10 +966,14 @@
"ToastEncodeCancelSucces": "Кодирование отменено", "ToastEncodeCancelSucces": "Кодирование отменено",
"ToastEpisodeDownloadQueueClearFailed": "Не удалось очистить очередь", "ToastEpisodeDownloadQueueClearFailed": "Не удалось очистить очередь",
"ToastEpisodeDownloadQueueClearSuccess": "Очередь загрузки эпизода очищена", "ToastEpisodeDownloadQueueClearSuccess": "Очередь загрузки эпизода очищена",
"ToastEpisodeUpdateSuccess": "{0 эпизодов обновлено",
"ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве", "ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве",
"ToastFailedToLoadData": "Не удалось загрузить данные", "ToastFailedToLoadData": "Не удалось загрузить данные",
"ToastFailedToMatch": "Не удалось найти совпадения",
"ToastFailedToShare": "Не удалось поделиться", "ToastFailedToShare": "Не удалось поделиться",
"ToastFailedToUpdate": "Не удалось обновить",
"ToastInvalidImageUrl": "Неверный URL изображения", "ToastInvalidImageUrl": "Неверный URL изображения",
"ToastInvalidMaxEpisodesToDownload": "Недопустимое максимальное количество загружаемых эпизодов",
"ToastInvalidUrl": "Неверный URL", "ToastInvalidUrl": "Неверный URL",
"ToastItemCoverUpdateSuccess": "Обложка элемента обновлена", "ToastItemCoverUpdateSuccess": "Обложка элемента обновлена",
"ToastItemDeletedFailed": "Не удалось удалить элемент", "ToastItemDeletedFailed": "Не удалось удалить элемент",
@@ -887,14 +991,22 @@
"ToastLibraryScanFailedToStart": "Не удалось запустить сканирование", "ToastLibraryScanFailedToStart": "Не удалось запустить сканирование",
"ToastLibraryScanStarted": "Запущено сканирование библиотеки", "ToastLibraryScanStarted": "Запущено сканирование библиотеки",
"ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена", "ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена",
"ToastMatchAllAuthorsFailed": "Не удалось найти совпадения со всеми авторами",
"ToastMetadataFilesRemovedError": "Ошибка при удалении файлов metadata.{0}",
"ToastMetadataFilesRemovedNoneFound": "В библиотеке не найдено файлов metadata.{0}",
"ToastMetadataFilesRemovedNoneRemoved": "Нет удаленных файлов metadata.{0}",
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1} файлов удалено",
"ToastMustHaveAtLeastOnePath": "Должен быть хотя бы один путь",
"ToastNameEmailRequired": "Имя и адрес электронной почты обязательны", "ToastNameEmailRequired": "Имя и адрес электронной почты обязательны",
"ToastNameRequired": "Имя обязательно для заполнения", "ToastNameRequired": "Имя обязательно для заполнения",
"ToastNewEpisodesFound": "{0} новых эпизодов найдено",
"ToastNewUserCreatedFailed": "Не удалось создать учетную запись: \"{0}\"", "ToastNewUserCreatedFailed": "Не удалось создать учетную запись: \"{0}\"",
"ToastNewUserCreatedSuccess": "Новая учетная запись создана", "ToastNewUserCreatedSuccess": "Новая учетная запись создана",
"ToastNewUserLibraryError": "Необходимо выбрать хотя бы одну библиотеку", "ToastNewUserLibraryError": "Необходимо выбрать хотя бы одну библиотеку",
"ToastNewUserPasswordError": "Должен иметь пароль, только пользователь root может иметь пустой пароль", "ToastNewUserPasswordError": "Должен иметь пароль, только пользователь root может иметь пустой пароль",
"ToastNewUserTagError": "Необходимо выбрать хотя бы один тег", "ToastNewUserTagError": "Необходимо выбрать хотя бы один тег",
"ToastNewUserUsernameError": "Введите имя пользователя", "ToastNewUserUsernameError": "Введите имя пользователя",
"ToastNoNewEpisodesFound": "Новых эпизодов не найдено",
"ToastNoUpdatesNecessary": "Обновления не требуются", "ToastNoUpdatesNecessary": "Обновления не требуются",
"ToastNotificationCreateFailed": "Не удалось создать уведомление", "ToastNotificationCreateFailed": "Не удалось создать уведомление",
"ToastNotificationDeleteFailed": "Не удалось удалить уведомление", "ToastNotificationDeleteFailed": "Не удалось удалить уведомление",
@@ -913,6 +1025,7 @@
"ToastPodcastGetFeedFailed": "Не удалось получить ленту подкастов", "ToastPodcastGetFeedFailed": "Не удалось получить ленту подкастов",
"ToastPodcastNoEpisodesInFeed": "В RSS-ленте эпизодов не найдено", "ToastPodcastNoEpisodesInFeed": "В RSS-ленте эпизодов не найдено",
"ToastPodcastNoRssFeed": "В подкасте нет RSS-канала", "ToastPodcastNoRssFeed": "В подкасте нет RSS-канала",
"ToastProgressIsNotBeingSynced": "Прогресс не синхронизируется, перезапустите воспроизведение",
"ToastProviderCreatedFailed": "Не удалось добавить провайдера", "ToastProviderCreatedFailed": "Не удалось добавить провайдера",
"ToastProviderCreatedSuccess": "Добавлен новый провайдер", "ToastProviderCreatedSuccess": "Добавлен новый провайдер",
"ToastProviderNameAndUrlRequired": "Имя и URL обязательные", "ToastProviderNameAndUrlRequired": "Имя и URL обязательные",
@@ -939,6 +1052,7 @@
"ToastSessionCloseFailed": "Не удалось закрыть сеанс", "ToastSessionCloseFailed": "Не удалось закрыть сеанс",
"ToastSessionDeleteFailed": "Не удалось удалить сеанс", "ToastSessionDeleteFailed": "Не удалось удалить сеанс",
"ToastSessionDeleteSuccess": "Сеанс удален", "ToastSessionDeleteSuccess": "Сеанс удален",
"ToastSleepTimerDone": "Выполнен таймер сна... Хр-р-р-р",
"ToastSlugMustChange": "Slug содержит недопустимые символы", "ToastSlugMustChange": "Slug содержит недопустимые символы",
"ToastSlugRequired": "Требуется Slug", "ToastSlugRequired": "Требуется Slug",
"ToastSocketConnected": "Сокет подключен", "ToastSocketConnected": "Сокет подключен",
+84 -6
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "Počisti predpomnilnik elementov", "ButtonPurgeItemsCache": "Počisti predpomnilnik elementov",
"ButtonQueueAddItem": "Dodaj v čakalno vrsto", "ButtonQueueAddItem": "Dodaj v čakalno vrsto",
"ButtonQueueRemoveItem": "Odstrani iz čakalne vrste", "ButtonQueueRemoveItem": "Odstrani iz čakalne vrste",
"ButtonQuickEmbed": "Hitra vdelava",
"ButtonQuickEmbedMetadata": "Hitra vdelava metapodatkov", "ButtonQuickEmbedMetadata": "Hitra vdelava metapodatkov",
"ButtonQuickMatch": "Hitro ujemanje", "ButtonQuickMatch": "Hitro ujemanje",
"ButtonReScan": "Ponovno pregledovanje", "ButtonReScan": "Ponovno pregledovanje",
@@ -162,6 +163,7 @@
"HeaderNotificationUpdate": "Posodobi obvestilo", "HeaderNotificationUpdate": "Posodobi obvestilo",
"HeaderNotifications": "Obvestila", "HeaderNotifications": "Obvestila",
"HeaderOpenIDConnectAuthentication": "Prijava z OpenID Connect", "HeaderOpenIDConnectAuthentication": "Prijava z OpenID Connect",
"HeaderOpenListeningSessions": "Odprte seje poslušanja",
"HeaderOpenRSSFeed": "Odpri vir RSS", "HeaderOpenRSSFeed": "Odpri vir RSS",
"HeaderOtherFiles": "Ostale datoteke", "HeaderOtherFiles": "Ostale datoteke",
"HeaderPasswordAuthentication": "Preverjanje pristnosti z geslom", "HeaderPasswordAuthentication": "Preverjanje pristnosti z geslom",
@@ -179,6 +181,7 @@
"HeaderRemoveEpisodes": "Odstrani {0} epizod", "HeaderRemoveEpisodes": "Odstrani {0} epizod",
"HeaderSavedMediaProgress": "Shranjen napredek predstavnosti", "HeaderSavedMediaProgress": "Shranjen napredek predstavnosti",
"HeaderSchedule": "Načrtovanje", "HeaderSchedule": "Načrtovanje",
"HeaderScheduleEpisodeDownloads": "Načrtovanje samodejnega prenosa epizod",
"HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice", "HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice",
"HeaderSession": "Seja", "HeaderSession": "Seja",
"HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja", "HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja",
@@ -224,7 +227,11 @@
"LabelAllUsersExcludingGuests": "Vsi uporabniki razen gosti", "LabelAllUsersExcludingGuests": "Vsi uporabniki razen gosti",
"LabelAllUsersIncludingGuests": "Vsi uporabniki vključno z gosti", "LabelAllUsersIncludingGuests": "Vsi uporabniki vključno z gosti",
"LabelAlreadyInYourLibrary": "Že v tvoji knjižnici", "LabelAlreadyInYourLibrary": "Že v tvoji knjižnici",
"LabelApiToken": "API žeton",
"LabelAppend": "Priloži", "LabelAppend": "Priloži",
"LabelAudioBitrate": "Avdio bitna hitrost (npr. 128k)",
"LabelAudioChannels": "Avdio kanali (1 ali 2)",
"LabelAudioCodec": "Avdio kodek",
"LabelAuthor": "Avtor", "LabelAuthor": "Avtor",
"LabelAuthorFirstLast": "Avtor (ime priimek)", "LabelAuthorFirstLast": "Avtor (ime priimek)",
"LabelAuthorLastFirst": "Avtor (priimek, ime)", "LabelAuthorLastFirst": "Avtor (priimek, ime)",
@@ -237,7 +244,8 @@
"LabelAutoRegister": "Samodejna registracija", "LabelAutoRegister": "Samodejna registracija",
"LabelAutoRegisterDescription": "Po prijavi samodejno ustvari nove uporabnike", "LabelAutoRegisterDescription": "Po prijavi samodejno ustvari nove uporabnike",
"LabelBackToUser": "Nazaj na uporabnika", "LabelBackToUser": "Nazaj na uporabnika",
"LabelBackupLocation": "Lokacija rezervne kopije", "LabelBackupAudioFiles": "Varnostno kopiranje zvočnih datotek",
"LabelBackupLocation": "Lokacija varnostnih kopij",
"LabelBackupsEnableAutomaticBackups": "Omogoči samodejno varnostno kopiranje", "LabelBackupsEnableAutomaticBackups": "Omogoči samodejno varnostno kopiranje",
"LabelBackupsEnableAutomaticBackupsHelp": "Varnostne kopije shranjene v /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Varnostne kopije shranjene v /metadata/backups",
"LabelBackupsMaxBackupSize": "Največja velikost varnostne kopije (v GB) (0 za neomejeno)", "LabelBackupsMaxBackupSize": "Največja velikost varnostne kopije (v GB) (0 za neomejeno)",
@@ -245,15 +253,18 @@
"LabelBackupsNumberToKeep": "Število varnostnih kopij, ki jih je treba hraniti", "LabelBackupsNumberToKeep": "Število varnostnih kopij, ki jih je treba hraniti",
"LabelBackupsNumberToKeepHelp": "Naenkrat bo odstranjena samo ena varnostna kopija, če že imate več varnostnih kopij, jih odstranite ročno.", "LabelBackupsNumberToKeepHelp": "Naenkrat bo odstranjena samo ena varnostna kopija, če že imate več varnostnih kopij, jih odstranite ročno.",
"LabelBitrate": "Bitna hitrost", "LabelBitrate": "Bitna hitrost",
"LabelBonus": "Bonus",
"LabelBooks": "knjig", "LabelBooks": "knjig",
"LabelButtonText": "Besedilo gumba", "LabelButtonText": "Besedilo gumba",
"LabelByAuthor": "od {0}", "LabelByAuthor": "od {0}",
"LabelChangePassword": "Spremeni geslo", "LabelChangePassword": "Spremeni geslo",
"LabelChannels": "Kanali", "LabelChannels": "Kanali",
"LabelChapterCount": "{0} poglavij",
"LabelChapterTitle": "Naslov poglavja", "LabelChapterTitle": "Naslov poglavja",
"LabelChapters": "Poglavja", "LabelChapters": "Poglavja",
"LabelChaptersFound": "najdenih poglavij", "LabelChaptersFound": "najdenih poglavij",
"LabelClickForMoreInfo": "Klikni za več informacij", "LabelClickForMoreInfo": "Klikni za več informacij",
"LabelClickToUseCurrentValue": "Klikni za uporabo trenutne vrednosti",
"LabelClosePlayer": "Zapri predvajalnik", "LabelClosePlayer": "Zapri predvajalnik",
"LabelCodec": "Kodek", "LabelCodec": "Kodek",
"LabelCollapseSeries": "Strni serije", "LabelCollapseSeries": "Strni serije",
@@ -303,12 +314,25 @@
"LabelEmailSettingsTestAddress": "Testiraj naslov", "LabelEmailSettingsTestAddress": "Testiraj naslov",
"LabelEmbeddedCover": "Vdelana naslovnica", "LabelEmbeddedCover": "Vdelana naslovnica",
"LabelEnable": "Omogoči", "LabelEnable": "Omogoči",
"LabelEncodingBackupLocation": "Varnostna kopija vaših izvirnih zvočnih datotek bo shranjena v:",
"LabelEncodingChaptersNotEmbedded": "Poglavja niso vdelana v zvočne knjige z večimi sledmi.",
"LabelEncodingClearItemCache": "Občasno počistite predpomnilnik elementov.",
"LabelEncodingFinishedM4B": "Končana M4B datoteka bo shranjena v vaši mapi z zvočnimi knjigami:",
"LabelEncodingInfoEmbedded": "Metapodatki bodo vdelani v zvočne posnetke znotraj vaše mape zvočne knjige.",
"LabelEncodingStartedNavigation": "Ko se opravilo začne, lahko zapustite to stran.",
"LabelEncodingTimeWarning": "Enkodiranje lahko traja tudi do 30 minut.",
"LabelEncodingWarningAdvancedSettings": "Opozorilo: Ne posodabljajte teh nastavitev, razen če poznate možnosti ekodiranja s programom ffmpeg.",
"LabelEncodingWatcherDisabled": "Če ste spremljanje datotečnega sistema onemogočili, boste morali pozneje ponovno pregledati to zvočno knjigo.",
"LabelEnd": "Konec", "LabelEnd": "Konec",
"LabelEndOfChapter": "Konec poglavja", "LabelEndOfChapter": "Konec poglavja",
"LabelEpisode": "Epizoda", "LabelEpisode": "Epizoda",
"LabelEpisodeNotLinkedToRssFeed": "Epizoda ni povezana z virom RSS",
"LabelEpisodeNumber": "{0}. epizoda",
"LabelEpisodeTitle": "Naslov epizode", "LabelEpisodeTitle": "Naslov epizode",
"LabelEpisodeType": "Tip epizode", "LabelEpisodeType": "Tip epizode",
"LabelEpisodeUrlFromRssFeed": "URL epizode iz vira RSS",
"LabelEpisodes": "Epizode", "LabelEpisodes": "Epizode",
"LabelEpisodic": "Epizodično",
"LabelExample": "Primer", "LabelExample": "Primer",
"LabelExpandSeries": "Razširi serije", "LabelExpandSeries": "Razširi serije",
"LabelExpandSubSeries": "Razširi podserije", "LabelExpandSubSeries": "Razširi podserije",
@@ -336,6 +360,7 @@
"LabelFontScale": "Merilo pisave", "LabelFontScale": "Merilo pisave",
"LabelFontStrikethrough": "Prečrtano", "LabelFontStrikethrough": "Prečrtano",
"LabelFormat": "Oblika", "LabelFormat": "Oblika",
"LabelFull": "Polno",
"LabelGenre": "Žanr", "LabelGenre": "Žanr",
"LabelGenres": "Žanri", "LabelGenres": "Žanri",
"LabelHardDeleteFile": "Trdo brisanje datoteke", "LabelHardDeleteFile": "Trdo brisanje datoteke",
@@ -350,7 +375,7 @@
"LabelImageURLFromTheWeb": "URL slike iz spleta", "LabelImageURLFromTheWeb": "URL slike iz spleta",
"LabelInProgress": "V teku", "LabelInProgress": "V teku",
"LabelIncludeInTracklist": "Vključi v seznam skladb", "LabelIncludeInTracklist": "Vključi v seznam skladb",
"LabelIncomplete": "Nepopolno", "LabelIncomplete": "Nedokončano",
"LabelInterval": "Interval", "LabelInterval": "Interval",
"LabelIntervalCustomDailyWeekly": "Dnevno/tedensko po meri", "LabelIntervalCustomDailyWeekly": "Dnevno/tedensko po meri",
"LabelIntervalEvery12Hours": "Vsakih 12 ur", "LabelIntervalEvery12Hours": "Vsakih 12 ur",
@@ -370,7 +395,7 @@
"LabelLastBookAdded": "Zadnja dodana knjiga", "LabelLastBookAdded": "Zadnja dodana knjiga",
"LabelLastBookUpdated": "Zadnja posodobljena knjiga", "LabelLastBookUpdated": "Zadnja posodobljena knjiga",
"LabelLastSeen": "Nazadnje viden", "LabelLastSeen": "Nazadnje viden",
"LabelLastTime": "Zadnji čas", "LabelLastTime": "Nazadnje",
"LabelLastUpdate": "Zadnja posodobitev", "LabelLastUpdate": "Zadnja posodobitev",
"LabelLayout": "Postavitev", "LabelLayout": "Postavitev",
"LabelLayoutSinglePage": "Ena stran", "LabelLayoutSinglePage": "Ena stran",
@@ -391,6 +416,10 @@
"LabelLowestPriority": "Najnižja prioriteta", "LabelLowestPriority": "Najnižja prioriteta",
"LabelMatchExistingUsersBy": "Poveži obstoječe uporabnike po", "LabelMatchExistingUsersBy": "Poveži obstoječe uporabnike po",
"LabelMatchExistingUsersByDescription": "Uporablja se za povezovanje obstoječih uporabnikov. Ko se vzpostavi povezava, se bodo uporabniki ujemali z enoličnim ID-jem vašega ponudnika SSO", "LabelMatchExistingUsersByDescription": "Uporablja se za povezovanje obstoječih uporabnikov. Ko se vzpostavi povezava, se bodo uporabniki ujemali z enoličnim ID-jem vašega ponudnika SSO",
"LabelMaxEpisodesToDownload": "Največje število epizod za prenos. Uporabite 0 za neomejeno.",
"LabelMaxEpisodesToDownloadPerCheck": "Največje število novih epizod za prenos ob preverjanju",
"LabelMaxEpisodesToKeep": "Največje število epizod, ki jih lahko obdržite",
"LabelMaxEpisodesToKeepHelp": "Vrednost 0 ne omejuje navišjega števila. Ko se nova epizoda samodejno prenese, se bo izbrisala najstarejša epizoda, če imate več kot X epizod. S tem boste izbrisali samo 1 epizodo na nov prenos.",
"LabelMediaPlayer": "Medijski predvajalnik", "LabelMediaPlayer": "Medijski predvajalnik",
"LabelMediaType": "Vrsta medija", "LabelMediaType": "Vrsta medija",
"LabelMetaTag": "Meta oznaka", "LabelMetaTag": "Meta oznaka",
@@ -422,7 +451,7 @@
"LabelNotes": "Opombe", "LabelNotes": "Opombe",
"LabelNotificationAppriseURL": "Apprise URL(ji)", "LabelNotificationAppriseURL": "Apprise URL(ji)",
"LabelNotificationAvailableVariables": "Razpoložljive spremenljivke", "LabelNotificationAvailableVariables": "Razpoložljive spremenljivke",
"LabelNotificationBodyTemplate": "Predloga telesa", "LabelNotificationBodyTemplate": "Predloga vsebime",
"LabelNotificationEvent": "Dogodek obvestila", "LabelNotificationEvent": "Dogodek obvestila",
"LabelNotificationTitleTemplate": "Predloga naslova", "LabelNotificationTitleTemplate": "Predloga naslova",
"LabelNotificationsMaxFailedAttempts": "Najvišje število neuspelih poskusov", "LabelNotificationsMaxFailedAttempts": "Najvišje število neuspelih poskusov",
@@ -430,18 +459,20 @@
"LabelNotificationsMaxQueueSize": "Največja velikost čakalne vrste za dogodke obvestil", "LabelNotificationsMaxQueueSize": "Največja velikost čakalne vrste za dogodke obvestil",
"LabelNotificationsMaxQueueSizeHelp": "Dogodki so omejeni na sprožitev 1 na sekundo. Dogodki bodo prezrti, če je čakalna vrsta najvišja. To preprečuje neželeno pošiljanje obvestil.", "LabelNotificationsMaxQueueSizeHelp": "Dogodki so omejeni na sprožitev 1 na sekundo. Dogodki bodo prezrti, če je čakalna vrsta najvišja. To preprečuje neželeno pošiljanje obvestil.",
"LabelNumberOfBooks": "Število knjig", "LabelNumberOfBooks": "Število knjig",
"LabelNumberOfEpisodes": "# od epizod", "LabelNumberOfEpisodes": "število epizod",
"LabelOpenIDAdvancedPermsClaimDescription": "Ime zahtevka OpenID, ki vsebuje napredna dovoljenja za uporabniška dejanja v aplikaciji, ki bodo veljala za neskrbniške vloge (<b>če je konfigurirano</b>). Če trditev manjka v odgovoru, bo dostop do ABS zavrnjen. Če ena možnost manjka, bo obravnavana kot <code>false</code>. Zagotovite, da se zahtevek ponudnika identitete ujema s pričakovano strukturo:", "LabelOpenIDAdvancedPermsClaimDescription": "Ime zahtevka OpenID, ki vsebuje napredna dovoljenja za uporabniška dejanja v aplikaciji, ki bodo veljala za neskrbniške vloge (<b>če je konfigurirano</b>). Če trditev manjka v odgovoru, bo dostop do ABS zavrnjen. Če ena možnost manjka, bo obravnavana kot <code>false</code>. Zagotovite, da se zahtevek ponudnika identitete ujema s pričakovano strukturo:",
"LabelOpenIDClaims": "Pustite naslednje možnosti prazne, da onemogočite napredno dodeljevanje skupin in dovoljenj, nato pa samodejno dodelite skupino 'Uporabnik'.", "LabelOpenIDClaims": "Pustite naslednje možnosti prazne, da onemogočite napredno dodeljevanje skupin in dovoljenj, nato pa samodejno dodelite skupino 'Uporabnik'.",
"LabelOpenIDGroupClaimDescription": "Ime zahtevka OpenID, ki vsebuje seznam uporabnikovih skupin. Običajno imenovane <code>skupine</code>. <b>Če je konfigurirana</b>, bo aplikacija samodejno dodelila vloge na podlagi članstva v skupini uporabnika, pod pogojem, da so te skupine v zahtevku poimenovane 'admin', 'user' ali 'guest' brez razlikovanja med velikimi in malimi črkami. Zahtevek mora vsebovati seznam in če uporabnik pripada več skupinam, mu aplikacija dodeli vlogo, ki ustreza najvišjemu nivoju dostopa. Če se nobena skupina ne ujema, bo dostop zavrnjen.", "LabelOpenIDGroupClaimDescription": "Ime zahtevka OpenID, ki vsebuje seznam uporabnikovih skupin. Običajno imenovane <code>skupine</code>. <b>Če je konfigurirana</b>, bo aplikacija samodejno dodelila vloge na podlagi članstva v skupini uporabnika, pod pogojem, da so te skupine v zahtevku poimenovane 'admin', 'user' ali 'guest' brez razlikovanja med velikimi in malimi črkami. Zahtevek mora vsebovati seznam in če uporabnik pripada več skupinam, mu aplikacija dodeli vlogo, ki ustreza najvišjemu nivoju dostopa. Če se nobena skupina ne ujema, bo dostop zavrnjen.",
"LabelOpenRSSFeed": "Odpri vir RSS", "LabelOpenRSSFeed": "Odpri vir RSS",
"LabelOverwrite": "Prepiši", "LabelOverwrite": "Prepiši",
"LabelPaginationPageXOfY": "Stran {0} od {1}",
"LabelPassword": "Geslo", "LabelPassword": "Geslo",
"LabelPath": "Pot", "LabelPath": "Pot",
"LabelPermanent": "Trajno", "LabelPermanent": "Trajno",
"LabelPermissionsAccessAllLibraries": "Lahko dostopa do vseh knjižnic", "LabelPermissionsAccessAllLibraries": "Lahko dostopa do vseh knjižnic",
"LabelPermissionsAccessAllTags": "Lahko dostopa do vseh oznak", "LabelPermissionsAccessAllTags": "Lahko dostopa do vseh oznak",
"LabelPermissionsAccessExplicitContent": "Lahko dostopa do eksplicitne vsebine", "LabelPermissionsAccessExplicitContent": "Lahko dostopa do eksplicitne vsebine",
"LabelPermissionsCreateEreader": "Lahko ustvari e-bralnik",
"LabelPermissionsDelete": "Lahko briše", "LabelPermissionsDelete": "Lahko briše",
"LabelPermissionsDownload": "Lahko prenaša", "LabelPermissionsDownload": "Lahko prenaša",
"LabelPermissionsUpdate": "Lahko posodablja", "LabelPermissionsUpdate": "Lahko posodablja",
@@ -486,21 +517,28 @@
"LabelRedo": "Ponovi", "LabelRedo": "Ponovi",
"LabelRegion": "Regija", "LabelRegion": "Regija",
"LabelReleaseDate": "Datum izdaje", "LabelReleaseDate": "Datum izdaje",
"LabelRemoveAllMetadataAbs": "Odstrani vse datoteke metadata.abs",
"LabelRemoveAllMetadataJson": "Odstrani vse datoteke metadata.json",
"LabelRemoveCover": "Odstrani naslovnico", "LabelRemoveCover": "Odstrani naslovnico",
"LabelRemoveMetadataFile": "Odstrani datoteke z metapodatki v mapah elementov knjižnice",
"LabelRemoveMetadataFileHelp": "Odstrani vse datoteke metadata.json in metadata.abs v svojih mapah {0}.",
"LabelRowsPerPage": "Vrstic na stran", "LabelRowsPerPage": "Vrstic na stran",
"LabelSearchTerm": "Iskalni pojem", "LabelSearchTerm": "Iskalni pojem",
"LabelSearchTitle": "Naslov iskanja", "LabelSearchTitle": "Naslov iskanja",
"LabelSearchTitleOrASIN": "Naslov iskanja ali ASIN", "LabelSearchTitleOrASIN": "Naslov iskanja ali ASIN",
"LabelSeason": "Sezona", "LabelSeason": "Sezona",
"LabelSeasonNumber": "Sezona #{0}",
"LabelSelectAll": "Izberite vse", "LabelSelectAll": "Izberite vse",
"LabelSelectAllEpisodes": "Izberite vse epizode", "LabelSelectAllEpisodes": "Izberite vse epizode",
"LabelSelectEpisodesShowing": "Izberi {0} prikazanih epizod", "LabelSelectEpisodesShowing": "Izberi {0} prikazanih epizod",
"LabelSelectUsers": "Izberite uporabnike", "LabelSelectUsers": "Izberite uporabnike",
"LabelSendEbookToDevice": "Pošlji eknjigo k...", "LabelSendEbookToDevice": "Pošlji eknjigo k...",
"LabelSequence": "Zaporedje", "LabelSequence": "Zaporedje",
"LabelSerial": "Serija",
"LabelSeries": "Serije", "LabelSeries": "Serije",
"LabelSeriesName": "Ime serije", "LabelSeriesName": "Ime serije",
"LabelSeriesProgress": "Napredek serije", "LabelSeriesProgress": "Napredek serije",
"LabelServerLogLevel": "Raven dnevnika strežnika",
"LabelServerYearReview": "Pregled leta strežnika ({0})", "LabelServerYearReview": "Pregled leta strežnika ({0})",
"LabelSetEbookAsPrimary": "Nastavi kot primarno", "LabelSetEbookAsPrimary": "Nastavi kot primarno",
"LabelSetEbookAsSupplementary": "Nastavi kot dodatno", "LabelSetEbookAsSupplementary": "Nastavi kot dodatno",
@@ -525,6 +563,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "Serije, ki imajo eno knjigo, bodo skrite na strani serije in policah domače strani.", "LabelSettingsHideSingleBookSeriesHelp": "Serije, ki imajo eno knjigo, bodo skrite na strani serije in policah domače strani.",
"LabelSettingsHomePageBookshelfView": "Domača stran bo imela pogled knjižne police", "LabelSettingsHomePageBookshelfView": "Domača stran bo imela pogled knjižne police",
"LabelSettingsLibraryBookshelfView": "Knjižnična uporaba pogleda knjižne police", "LabelSettingsLibraryBookshelfView": "Knjižnična uporaba pogleda knjižne police",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Odstotek dokončanega je večji od",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Preostali čas je manj kot (sekund)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Označi medijski element kot končan, ko",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči prejšnje knjige v nadaljevanju serije", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči prejšnje knjige v nadaljevanju serije",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Polica z domačo stranjo Nadaljuj serijo prikazuje prvo nezačeto knjigo v seriji, ki ima vsaj eno dokončano knjigo in ni nobene knjige v teku. Če omogočite to nastavitev, se bo serija nadaljevala od najbolj dokončane knjige namesto od prve nezačete knjige.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Polica z domačo stranjo Nadaljuj serijo prikazuje prvo nezačeto knjigo v seriji, ki ima vsaj eno dokončano knjigo in ni nobene knjige v teku. Če omogočite to nastavitev, se bo serija nadaljevala od najbolj dokončane knjige namesto od prve nezačete knjige.",
"LabelSettingsParseSubtitles": "Uporabi podnapise", "LabelSettingsParseSubtitles": "Uporabi podnapise",
@@ -552,7 +593,7 @@
"LabelSleepTimer": "Časovnik za spanje", "LabelSleepTimer": "Časovnik za spanje",
"LabelSlug": "Slug", "LabelSlug": "Slug",
"LabelStart": "Začetek", "LabelStart": "Začetek",
"LabelStartTime": "Začetni čas", "LabelStartTime": "Čas začetka",
"LabelStarted": "Začeto", "LabelStarted": "Začeto",
"LabelStartedAt": "Začeto ob", "LabelStartedAt": "Začeto ob",
"LabelStatsAudioTracks": "Zvočni posnetki", "LabelStatsAudioTracks": "Zvočni posnetki",
@@ -589,6 +630,7 @@
"LabelTimeDurationXMinutes": "{0} minut", "LabelTimeDurationXMinutes": "{0} minut",
"LabelTimeDurationXSeconds": "{0} sekund", "LabelTimeDurationXSeconds": "{0} sekund",
"LabelTimeInMinutes": "Čas v minutah", "LabelTimeInMinutes": "Čas v minutah",
"LabelTimeLeft": "{0} še preostane",
"LabelTimeListened": "Čas poslušanja", "LabelTimeListened": "Čas poslušanja",
"LabelTimeListenedToday": "Čas poslušanja danes", "LabelTimeListenedToday": "Čas poslušanja danes",
"LabelTimeRemaining": "Še {0}", "LabelTimeRemaining": "Še {0}",
@@ -596,6 +638,7 @@
"LabelTitle": "Naslov", "LabelTitle": "Naslov",
"LabelToolsEmbedMetadata": "Vdelaj metapodatke", "LabelToolsEmbedMetadata": "Vdelaj metapodatke",
"LabelToolsEmbedMetadataDescription": "Vdelajte metapodatke v zvočne datoteke, vključno s sliko naslovnice in poglavji.", "LabelToolsEmbedMetadataDescription": "Vdelajte metapodatke v zvočne datoteke, vključno s sliko naslovnice in poglavji.",
"LabelToolsM4bEncoder": "M4B enkoder",
"LabelToolsMakeM4b": "Ustvari M4B datoteko zvočne knjige", "LabelToolsMakeM4b": "Ustvari M4B datoteko zvočne knjige",
"LabelToolsMakeM4bDescription": "Ustvari zvočno knjigo v .M4B obliki z vdelanimi metapodatki, sliko naslovnice in poglavji.", "LabelToolsMakeM4bDescription": "Ustvari zvočno knjigo v .M4B obliki z vdelanimi metapodatki, sliko naslovnice in poglavji.",
"LabelToolsSplitM4b": "Razdeli M4B v MP3 datoteke", "LabelToolsSplitM4b": "Razdeli M4B v MP3 datoteke",
@@ -608,6 +651,7 @@
"LabelTracksMultiTrack": "Več posnetkov", "LabelTracksMultiTrack": "Več posnetkov",
"LabelTracksNone": "Brez posnetka", "LabelTracksNone": "Brez posnetka",
"LabelTracksSingleTrack": "Enojni posnetek", "LabelTracksSingleTrack": "Enojni posnetek",
"LabelTrailer": "Napovednik",
"LabelType": "Vrsta", "LabelType": "Vrsta",
"LabelUnabridged": "Neskrajšano", "LabelUnabridged": "Neskrajšano",
"LabelUndo": "Razveljavi", "LabelUndo": "Razveljavi",
@@ -621,8 +665,10 @@
"LabelUploaderDragAndDrop": "Povleci in spusti datoteke ali mape", "LabelUploaderDragAndDrop": "Povleci in spusti datoteke ali mape",
"LabelUploaderDropFiles": "Spusti datoteke", "LabelUploaderDropFiles": "Spusti datoteke",
"LabelUploaderItemFetchMetadataHelp": "Samodejno pridobi naslov, avtorja in serijo", "LabelUploaderItemFetchMetadataHelp": "Samodejno pridobi naslov, avtorja in serijo",
"LabelUseAdvancedOptions": "Uporabi napredne možnosti",
"LabelUseChapterTrack": "Uporabi posnetek poglavij", "LabelUseChapterTrack": "Uporabi posnetek poglavij",
"LabelUseFullTrack": "Uporabi celoten posnetek", "LabelUseFullTrack": "Uporabi celoten posnetek",
"LabelUseZeroForUnlimited": "Uporabi 0 za neomejeno",
"LabelUser": "Uporabnik", "LabelUser": "Uporabnik",
"LabelUsername": "Uporabniško ime", "LabelUsername": "Uporabniško ime",
"LabelValue": "Vrednost", "LabelValue": "Vrednost",
@@ -669,6 +715,7 @@
"MessageConfirmDeleteMetadataProvider": "Ali ste prepričani, da želite izbrisati ponudnika metapodatkov po meri \"{0}\"?", "MessageConfirmDeleteMetadataProvider": "Ali ste prepričani, da želite izbrisati ponudnika metapodatkov po meri \"{0}\"?",
"MessageConfirmDeleteNotification": "Ali ste prepričani, da želite izbrisati to obvestilo?", "MessageConfirmDeleteNotification": "Ali ste prepričani, da želite izbrisati to obvestilo?",
"MessageConfirmDeleteSession": "Ali ste prepričani, da želite izbrisati to sejo?", "MessageConfirmDeleteSession": "Ali ste prepričani, da želite izbrisati to sejo?",
"MessageConfirmEmbedMetadataInAudioFiles": "Ali ste prepričani, da želite vdelati metapodatke v {0} zvočnih datotek?",
"MessageConfirmForceReScan": "Ali ste prepričani, da želite vsiliti ponovno pregledovanje?", "MessageConfirmForceReScan": "Ali ste prepričani, da želite vsiliti ponovno pregledovanje?",
"MessageConfirmMarkAllEpisodesFinished": "Ali ste prepričani, da želite označiti vse epizode kot dokončane?", "MessageConfirmMarkAllEpisodesFinished": "Ali ste prepričani, da želite označiti vse epizode kot dokončane?",
"MessageConfirmMarkAllEpisodesNotFinished": "Ali ste prepričani, da želite vse epizode označiti kot nedokončane?", "MessageConfirmMarkAllEpisodesNotFinished": "Ali ste prepričani, da želite vse epizode označiti kot nedokončane?",
@@ -680,6 +727,7 @@
"MessageConfirmPurgeCache": "Čiščenje predpomnilnika bo izbrisalo celoten imenik v <code>/metadata/cache</code>. <br /><br />Ali ste prepričani, da želite odstraniti imenik predpomnilnika?", "MessageConfirmPurgeCache": "Čiščenje predpomnilnika bo izbrisalo celoten imenik v <code>/metadata/cache</code>. <br /><br />Ali ste prepričani, da želite odstraniti imenik predpomnilnika?",
"MessageConfirmPurgeItemsCache": "Čiščenje predpomnilnika elementov bo izbrisalo celoten imenik na <code>/metadata/cache/items</code>.<br />Ste prepričani?", "MessageConfirmPurgeItemsCache": "Čiščenje predpomnilnika elementov bo izbrisalo celoten imenik na <code>/metadata/cache/items</code>.<br />Ste prepričani?",
"MessageConfirmQuickEmbed": "Opozorilo! Hitra vdelava ne bo varnostno kopirala vaših zvočnih datotek. Prepričajte se, da imate varnostno kopijo zvočnih datotek. <br><br>Ali želite nadaljevati?", "MessageConfirmQuickEmbed": "Opozorilo! Hitra vdelava ne bo varnostno kopirala vaših zvočnih datotek. Prepričajte se, da imate varnostno kopijo zvočnih datotek. <br><br>Ali želite nadaljevati?",
"MessageConfirmQuickMatchEpisodes": "Hitro ujemanja epizod bo prepisalo podrobnosti, če se najde ujemanje. Posodobljene bodo samo epizode, ki se ne ujemajo. Ste prepričani?",
"MessageConfirmReScanLibraryItems": "Ali ste prepričani, da želite ponovno pregledati {0} elementov?", "MessageConfirmReScanLibraryItems": "Ali ste prepričani, da želite ponovno pregledati {0} elementov?",
"MessageConfirmRemoveAllChapters": "Ali ste prepričani, da želite odstraniti vsa poglavja?", "MessageConfirmRemoveAllChapters": "Ali ste prepričani, da želite odstraniti vsa poglavja?",
"MessageConfirmRemoveAuthor": "Ali ste prepričani, da želite odstraniti avtorja \"{0}\"?", "MessageConfirmRemoveAuthor": "Ali ste prepričani, da želite odstraniti avtorja \"{0}\"?",
@@ -687,6 +735,7 @@
"MessageConfirmRemoveEpisode": "Ali ste prepričani, da želite odstraniti epizodo \"{0}\"?", "MessageConfirmRemoveEpisode": "Ali ste prepričani, da želite odstraniti epizodo \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Ali ste prepričani, da želite odstraniti {0} epizod?", "MessageConfirmRemoveEpisodes": "Ali ste prepričani, da želite odstraniti {0} epizod?",
"MessageConfirmRemoveListeningSessions": "Ali ste prepričani, da želite odstraniti {0} sej poslušanja?", "MessageConfirmRemoveListeningSessions": "Ali ste prepričani, da želite odstraniti {0} sej poslušanja?",
"MessageConfirmRemoveMetadataFiles": "Ali ste prepričani, da želite odstraniti vse metapodatke.{0} v mapah elementov knjižnice?",
"MessageConfirmRemoveNarrator": "Ali ste prepričani, da želite odstraniti bralca \"{0}\"?", "MessageConfirmRemoveNarrator": "Ali ste prepričani, da želite odstraniti bralca \"{0}\"?",
"MessageConfirmRemovePlaylist": "Ali ste prepričani, da želite odstraniti svoj seznam predvajanja \"{0}\"?", "MessageConfirmRemovePlaylist": "Ali ste prepričani, da želite odstraniti svoj seznam predvajanja \"{0}\"?",
"MessageConfirmRenameGenre": "Ali ste prepričani, da želite preimenovati žanr \"{0}\" v \"{1}\" za vse elemente?", "MessageConfirmRenameGenre": "Ali ste prepričani, da želite preimenovati žanr \"{0}\" v \"{1}\" za vse elemente?",
@@ -702,6 +751,7 @@
"MessageDragFilesIntoTrackOrder": "Povlecite datoteke v pravilen vrstni red posnetkov", "MessageDragFilesIntoTrackOrder": "Povlecite datoteke v pravilen vrstni red posnetkov",
"MessageEmbedFailed": "Vdelava ni uspela!", "MessageEmbedFailed": "Vdelava ni uspela!",
"MessageEmbedFinished": "Vdelava končana!", "MessageEmbedFinished": "Vdelava končana!",
"MessageEmbedQueue": "V čakalni vrsta za vdelavo metapodatkov ({0} v čakalni vrsti)",
"MessageEpisodesQueuedForDownload": "{0} epizod v čakalni vrsti za prenos", "MessageEpisodesQueuedForDownload": "{0} epizod v čakalni vrsti za prenos",
"MessageEreaderDevices": "Da zagotovite dostavo e-knjig, boste morda morali dodati zgornji e-poštni naslov kot veljavnega pošiljatelja za vsako spodaj navedeno napravo.", "MessageEreaderDevices": "Da zagotovite dostavo e-knjig, boste morda morali dodati zgornji e-poštni naslov kot veljavnega pošiljatelja za vsako spodaj navedeno napravo.",
"MessageFeedURLWillBe": "URL vira bo {0}", "MessageFeedURLWillBe": "URL vira bo {0}",
@@ -746,6 +796,7 @@
"MessageNoLogs": "Ni dnevnikov", "MessageNoLogs": "Ni dnevnikov",
"MessageNoMediaProgress": "Ni medijskega napredka", "MessageNoMediaProgress": "Ni medijskega napredka",
"MessageNoNotifications": "Ni obvestil", "MessageNoNotifications": "Ni obvestil",
"MessageNoPodcastFeed": "Neveljaven podcast: Ni vira",
"MessageNoPodcastsFound": "Ni podcastov", "MessageNoPodcastsFound": "Ni podcastov",
"MessageNoResults": "Ni rezultatov", "MessageNoResults": "Ni rezultatov",
"MessageNoSearchResultsFor": "Ni rezultatov iskanja za \"{0}\"", "MessageNoSearchResultsFor": "Ni rezultatov iskanja za \"{0}\"",
@@ -762,6 +813,10 @@
"MessagePlaylistCreateFromCollection": "Ustvari seznam predvajanja iz zbirke", "MessagePlaylistCreateFromCollection": "Ustvari seznam predvajanja iz zbirke",
"MessagePleaseWait": "Prosim počakajte...", "MessagePleaseWait": "Prosim počakajte...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nima URL-ja vira RSS, ki bi ga lahko uporabil za ujemanje", "MessagePodcastHasNoRSSFeedForMatching": "Podcast nima URL-ja vira RSS, ki bi ga lahko uporabil za ujemanje",
"MessagePodcastSearchField": "Vnesite iskalni izraz ali URL vira RSS",
"MessageQuickEmbedInProgress": "Hitra vdelava je v teku",
"MessageQuickEmbedQueue": "V čakalni vrsti za hitro vdelavo ({0} v čakalni vrsti)",
"MessageQuickMatchAllEpisodes": "Hitro ujemanje vseh epizod",
"MessageQuickMatchDescription": "Izpolni prazne podrobnosti elementa in naslovnico s prvim rezultatom ujemanja iz '{0}'. Ne prepiše podrobnosti, razen če je omogočena nastavitev strežnika 'Prednostno ujemajoči se metapodatki'.", "MessageQuickMatchDescription": "Izpolni prazne podrobnosti elementa in naslovnico s prvim rezultatom ujemanja iz '{0}'. Ne prepiše podrobnosti, razen če je omogočena nastavitev strežnika 'Prednostno ujemajoči se metapodatki'.",
"MessageRemoveChapter": "Odstrani poglavje", "MessageRemoveChapter": "Odstrani poglavje",
"MessageRemoveEpisodes": "Odstrani toliko epizod: {0}", "MessageRemoveEpisodes": "Odstrani toliko epizod: {0}",
@@ -804,6 +859,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "Podcast že obstaja na tej poti", "MessageTaskOpmlImportFeedPodcastExists": "Podcast že obstaja na tej poti",
"MessageTaskOpmlImportFeedPodcastFailed": "Podcasta ni bilo mogoče ustvariti", "MessageTaskOpmlImportFeedPodcastFailed": "Podcasta ni bilo mogoče ustvariti",
"MessageTaskOpmlImportFinished": "Dodanih {0} podcastov", "MessageTaskOpmlImportFinished": "Dodanih {0} podcastov",
"MessageTaskOpmlParseFailed": "Datoteke OPML ni bilo mogoče razčleniti",
"MessageTaskOpmlParseFastFail": "Neveljavna OPMPL datoteka, oznake <opml> ni bilo mogoče najti ALI oznake <outline> ni bilo mogoče najti",
"MessageTaskOpmlParseNoneFound": "V datoteki OPML ni virov",
"MessageTaskScanItemsAdded": "{0} dodano", "MessageTaskScanItemsAdded": "{0} dodano",
"MessageTaskScanItemsMissing": "{0} manjka", "MessageTaskScanItemsMissing": "{0} manjka",
"MessageTaskScanItemsUpdated": "{0} posodobljeno", "MessageTaskScanItemsUpdated": "{0} posodobljeno",
@@ -828,6 +886,10 @@
"NoteUploaderFoldersWithMediaFiles": "Mape z predstavnostnimi datotekami bodo obravnavane kot ločene postavke knjižnice.", "NoteUploaderFoldersWithMediaFiles": "Mape z predstavnostnimi datotekami bodo obravnavane kot ločene postavke knjižnice.",
"NoteUploaderOnlyAudioFiles": "Če nalagate samo zvočne datoteke, bo vsaka zvočna datoteka obravnavana kot ločena zvočna knjiga.", "NoteUploaderOnlyAudioFiles": "Če nalagate samo zvočne datoteke, bo vsaka zvočna datoteka obravnavana kot ločena zvočna knjiga.",
"NoteUploaderUnsupportedFiles": "Nepodprte datoteke so prezrte. Ko izberete ali spustite mapo, se druge datoteke, ki niso v mapi elementov, prezrejo.", "NoteUploaderUnsupportedFiles": "Nepodprte datoteke so prezrte. Ko izberete ali spustite mapo, se druge datoteke, ki niso v mapi elementov, prezrejo.",
"NotificationOnBackupCompletedDescription": "Sproži se, ko je varnostno kopiranje končano",
"NotificationOnBackupFailedDescription": "Sproži se, ko varnostno kopiranje ne uspe",
"NotificationOnEpisodeDownloadedDescription": "Sproži se, ko se epizoda podcasta samodejno prenese",
"NotificationOnTestDescription": "Dogodek za testiranje sistema obveščanja",
"PlaceholderNewCollection": "Novo ime zbirke", "PlaceholderNewCollection": "Novo ime zbirke",
"PlaceholderNewFolderPath": "Pot nove mape", "PlaceholderNewFolderPath": "Pot nove mape",
"PlaceholderNewPlaylist": "Novo ime seznama predvajanja", "PlaceholderNewPlaylist": "Novo ime seznama predvajanja",
@@ -853,6 +915,7 @@
"StatsYearInReview": "PREGLED LETA", "StatsYearInReview": "PREGLED LETA",
"ToastAccountUpdateSuccess": "Račun posodobljen", "ToastAccountUpdateSuccess": "Račun posodobljen",
"ToastAppriseUrlRequired": "Vnesti morate Apprise URL", "ToastAppriseUrlRequired": "Vnesti morate Apprise URL",
"ToastAsinRequired": "ASIN koda je obvezen podatek",
"ToastAuthorImageRemoveSuccess": "Slika avtorja je odstranjena", "ToastAuthorImageRemoveSuccess": "Slika avtorja je odstranjena",
"ToastAuthorNotFound": "Avtor \"{0}\" ni bil najden", "ToastAuthorNotFound": "Avtor \"{0}\" ni bil najden",
"ToastAuthorRemoveSuccess": "Avtor odstranjen", "ToastAuthorRemoveSuccess": "Avtor odstranjen",
@@ -872,6 +935,8 @@
"ToastBackupUploadSuccess": "Varnostna kopija je naložena", "ToastBackupUploadSuccess": "Varnostna kopija je naložena",
"ToastBatchDeleteFailed": "Paketno brisanje ni uspelo", "ToastBatchDeleteFailed": "Paketno brisanje ni uspelo",
"ToastBatchDeleteSuccess": "Paketno brisanje je bilo uspešno", "ToastBatchDeleteSuccess": "Paketno brisanje je bilo uspešno",
"ToastBatchQuickMatchFailed": "Paketno hitro ujemanje ni uspelo!",
"ToastBatchQuickMatchStarted": "Paketno hitro ujemanje {0} knjig se je začelo!",
"ToastBatchUpdateFailed": "Paketna posodobitev ni uspela", "ToastBatchUpdateFailed": "Paketna posodobitev ni uspela",
"ToastBatchUpdateSuccess": "Paketna posodobitev je uspela", "ToastBatchUpdateSuccess": "Paketna posodobitev je uspela",
"ToastBookmarkCreateFailed": "Zaznamka ni bilo mogoče ustvariti", "ToastBookmarkCreateFailed": "Zaznamka ni bilo mogoče ustvariti",
@@ -883,6 +948,7 @@
"ToastChaptersHaveErrors": "Poglavja imajo napake", "ToastChaptersHaveErrors": "Poglavja imajo napake",
"ToastChaptersMustHaveTitles": "Poglavja morajo imeti naslove", "ToastChaptersMustHaveTitles": "Poglavja morajo imeti naslove",
"ToastChaptersRemoved": "Poglavja so odstranjena", "ToastChaptersRemoved": "Poglavja so odstranjena",
"ToastChaptersUpdated": "Poglavja so posodobljena",
"ToastCollectionItemsAddFailed": "Dodajanje elementov v zbirko ni uspelo", "ToastCollectionItemsAddFailed": "Dodajanje elementov v zbirko ni uspelo",
"ToastCollectionItemsAddSuccess": "Dodajanje elementov v zbirko je bilo uspešno", "ToastCollectionItemsAddSuccess": "Dodajanje elementov v zbirko je bilo uspešno",
"ToastCollectionItemsRemoveSuccess": "Elementi so bili odstranjeni iz zbirke", "ToastCollectionItemsRemoveSuccess": "Elementi so bili odstranjeni iz zbirke",
@@ -900,11 +966,14 @@
"ToastEncodeCancelSucces": "Prekodiranje prekinjeno", "ToastEncodeCancelSucces": "Prekodiranje prekinjeno",
"ToastEpisodeDownloadQueueClearFailed": "Čiščenje čakalne vrste ni uspelo", "ToastEpisodeDownloadQueueClearFailed": "Čiščenje čakalne vrste ni uspelo",
"ToastEpisodeDownloadQueueClearSuccess": "Čakalna vrsta za prenos epizod je počiščena", "ToastEpisodeDownloadQueueClearSuccess": "Čakalna vrsta za prenos epizod je počiščena",
"ToastEpisodeUpdateSuccess": "Število posodobljenih epizod: {0}",
"ToastErrorCannotShare": "V tej napravi ni mogoče dati v skupno rabo", "ToastErrorCannotShare": "V tej napravi ni mogoče dati v skupno rabo",
"ToastFailedToLoadData": "Podatkov ni bilo mogoče naložiti", "ToastFailedToLoadData": "Podatkov ni bilo mogoče naložiti",
"ToastFailedToMatch": "Ujemanje ni uspelo",
"ToastFailedToShare": "Skupna raba ni uspela", "ToastFailedToShare": "Skupna raba ni uspela",
"ToastFailedToUpdate": "Napaka pri posodobitvi", "ToastFailedToUpdate": "Napaka pri posodobitvi",
"ToastInvalidImageUrl": "Neveljaven URL slike", "ToastInvalidImageUrl": "Neveljaven URL slike",
"ToastInvalidMaxEpisodesToDownload": "Neveljavno največje število epizod za prenos",
"ToastInvalidUrl": "Neveljaven URL", "ToastInvalidUrl": "Neveljaven URL",
"ToastItemCoverUpdateSuccess": "Naslovnica elementa je bila posodobljena", "ToastItemCoverUpdateSuccess": "Naslovnica elementa je bila posodobljena",
"ToastItemDeletedFailed": "Elementa ni bilo mogoče izbrisati", "ToastItemDeletedFailed": "Elementa ni bilo mogoče izbrisati",
@@ -923,14 +992,21 @@
"ToastLibraryScanStarted": "Pregled knjižnice se je začel", "ToastLibraryScanStarted": "Pregled knjižnice se je začel",
"ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" je bila posodobljena", "ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" je bila posodobljena",
"ToastMatchAllAuthorsFailed": "Ujemanje vseh avtorjev ni bilo uspešno", "ToastMatchAllAuthorsFailed": "Ujemanje vseh avtorjev ni bilo uspešno",
"ToastMetadataFilesRemovedError": "Napaka pri odstranjevanju metapodatkov.{0} datotek",
"ToastMetadataFilesRemovedNoneFound": "Ni metapodatkov.{0} datotek, najdenih v knjižnici",
"ToastMetadataFilesRemovedNoneRemoved": "Ni metapodatkov.{0} datotek odstranjenih",
"ToastMetadataFilesRemovedSuccess": "{0} metapodatki.{1} datotek odstranjenih",
"ToastMustHaveAtLeastOnePath": "Imeti mora vsaj eno pot",
"ToastNameEmailRequired": "Ime in e-pošta sta obvezna", "ToastNameEmailRequired": "Ime in e-pošta sta obvezna",
"ToastNameRequired": "Ime je obvezno", "ToastNameRequired": "Ime je obvezno",
"ToastNewEpisodesFound": "Število najdenih novih epizod: {0}",
"ToastNewUserCreatedFailed": "Računa ni bilo mogoče ustvariti: \"{0}\"", "ToastNewUserCreatedFailed": "Računa ni bilo mogoče ustvariti: \"{0}\"",
"ToastNewUserCreatedSuccess": "Nov račun je bil ustvarjen", "ToastNewUserCreatedSuccess": "Nov račun je bil ustvarjen",
"ToastNewUserLibraryError": "Izbrati morate vsaj eno knjižnico", "ToastNewUserLibraryError": "Izbrati morate vsaj eno knjižnico",
"ToastNewUserPasswordError": "Mora imeti geslo, samo korenski uporabnik ima lahko prazno geslo", "ToastNewUserPasswordError": "Mora imeti geslo, samo korenski uporabnik ima lahko prazno geslo",
"ToastNewUserTagError": "Izbrati morate vsaj eno oznako", "ToastNewUserTagError": "Izbrati morate vsaj eno oznako",
"ToastNewUserUsernameError": "Vnesite uporabniško ime", "ToastNewUserUsernameError": "Vnesite uporabniško ime",
"ToastNoNewEpisodesFound": "Ni novih epizod",
"ToastNoUpdatesNecessary": "Posodobitve niso potrebne", "ToastNoUpdatesNecessary": "Posodobitve niso potrebne",
"ToastNotificationCreateFailed": "Obvestila ni bilo mogoče ustvariti", "ToastNotificationCreateFailed": "Obvestila ni bilo mogoče ustvariti",
"ToastNotificationDeleteFailed": "Brisanje obvestila ni uspelo", "ToastNotificationDeleteFailed": "Brisanje obvestila ni uspelo",
@@ -949,6 +1025,7 @@
"ToastPodcastGetFeedFailed": "Vira podcasta ni bilo mogoče pridobiti", "ToastPodcastGetFeedFailed": "Vira podcasta ni bilo mogoče pridobiti",
"ToastPodcastNoEpisodesInFeed": "V viru RSS ni bilo mogoče najti nobene epizode", "ToastPodcastNoEpisodesInFeed": "V viru RSS ni bilo mogoče najti nobene epizode",
"ToastPodcastNoRssFeed": "Podcast nima vira RSS", "ToastPodcastNoRssFeed": "Podcast nima vira RSS",
"ToastProgressIsNotBeingSynced": "Napredek se ne sinhronizira, znova zaženite predvajanje",
"ToastProviderCreatedFailed": "Ponudnika ni bilo mogoče dodati", "ToastProviderCreatedFailed": "Ponudnika ni bilo mogoče dodati",
"ToastProviderCreatedSuccess": "Dodan je bil nov ponudnik", "ToastProviderCreatedSuccess": "Dodan je bil nov ponudnik",
"ToastProviderNameAndUrlRequired": "Obvezen podatek sta ime in URL", "ToastProviderNameAndUrlRequired": "Obvezen podatek sta ime in URL",
@@ -975,6 +1052,7 @@
"ToastSessionCloseFailed": "Seje ni bilo mogoče zapreti", "ToastSessionCloseFailed": "Seje ni bilo mogoče zapreti",
"ToastSessionDeleteFailed": "Brisanje seje ni uspelo", "ToastSessionDeleteFailed": "Brisanje seje ni uspelo",
"ToastSessionDeleteSuccess": "Seja je bila izbrisana", "ToastSessionDeleteSuccess": "Seja je bila izbrisana",
"ToastSleepTimerDone": "Časovnik za spanje se je končal... zZzzZz",
"ToastSlugMustChange": "Slug vsebuje neveljavne znake", "ToastSlugMustChange": "Slug vsebuje neveljavne znake",
"ToastSlugRequired": "Slug je obvezen podatek", "ToastSlugRequired": "Slug je obvezen podatek",
"ToastSocketConnected": "Omrežna povezava je priklopljena", "ToastSocketConnected": "Omrežna povezava je priklopljena",
+87 -6
View File
@@ -66,6 +66,7 @@
"ButtonPurgeItemsCache": "清理项目缓存", "ButtonPurgeItemsCache": "清理项目缓存",
"ButtonQueueAddItem": "添加到队列", "ButtonQueueAddItem": "添加到队列",
"ButtonQueueRemoveItem": "从队列中移除", "ButtonQueueRemoveItem": "从队列中移除",
"ButtonQuickEmbed": "快速嵌入",
"ButtonQuickEmbedMetadata": "快速嵌入元数据", "ButtonQuickEmbedMetadata": "快速嵌入元数据",
"ButtonQuickMatch": "快速匹配", "ButtonQuickMatch": "快速匹配",
"ButtonReScan": "重新扫描", "ButtonReScan": "重新扫描",
@@ -162,6 +163,7 @@
"HeaderNotificationUpdate": "更新通知", "HeaderNotificationUpdate": "更新通知",
"HeaderNotifications": "通知", "HeaderNotifications": "通知",
"HeaderOpenIDConnectAuthentication": "OpenID 连接身份验证", "HeaderOpenIDConnectAuthentication": "OpenID 连接身份验证",
"HeaderOpenListeningSessions": "打开收听会话",
"HeaderOpenRSSFeed": "打开 RSS 源", "HeaderOpenRSSFeed": "打开 RSS 源",
"HeaderOtherFiles": "其他文件", "HeaderOtherFiles": "其他文件",
"HeaderPasswordAuthentication": "密码认证", "HeaderPasswordAuthentication": "密码认证",
@@ -179,6 +181,7 @@
"HeaderRemoveEpisodes": "移除 {0} 剧集", "HeaderRemoveEpisodes": "移除 {0} 剧集",
"HeaderSavedMediaProgress": "保存媒体进度", "HeaderSavedMediaProgress": "保存媒体进度",
"HeaderSchedule": "计划任务", "HeaderSchedule": "计划任务",
"HeaderScheduleEpisodeDownloads": "设置自动下载剧集",
"HeaderScheduleLibraryScans": "自动扫描媒体库", "HeaderScheduleLibraryScans": "自动扫描媒体库",
"HeaderSession": "会话", "HeaderSession": "会话",
"HeaderSetBackupSchedule": "设置备份计划任务", "HeaderSetBackupSchedule": "设置备份计划任务",
@@ -224,7 +227,11 @@
"LabelAllUsersExcludingGuests": "除访客外的所有用户", "LabelAllUsersExcludingGuests": "除访客外的所有用户",
"LabelAllUsersIncludingGuests": "包括访客的所有用户", "LabelAllUsersIncludingGuests": "包括访客的所有用户",
"LabelAlreadyInYourLibrary": "已存在你的库中", "LabelAlreadyInYourLibrary": "已存在你的库中",
"LabelApiToken": "API 令牌",
"LabelAppend": "附加", "LabelAppend": "附加",
"LabelAudioBitrate": "音频比特率 (例如: 128k)",
"LabelAudioChannels": "音频通道 (1 或 2)",
"LabelAudioCodec": "音频编解码器",
"LabelAuthor": "作者", "LabelAuthor": "作者",
"LabelAuthorFirstLast": "作者 (姓 名)", "LabelAuthorFirstLast": "作者 (姓 名)",
"LabelAuthorLastFirst": "作者 (名, 姓)", "LabelAuthorLastFirst": "作者 (名, 姓)",
@@ -237,6 +244,7 @@
"LabelAutoRegister": "自动注册", "LabelAutoRegister": "自动注册",
"LabelAutoRegisterDescription": "登录后自动创建新用户", "LabelAutoRegisterDescription": "登录后自动创建新用户",
"LabelBackToUser": "返回到用户", "LabelBackToUser": "返回到用户",
"LabelBackupAudioFiles": "备份音频文件",
"LabelBackupLocation": "备份位置", "LabelBackupLocation": "备份位置",
"LabelBackupsEnableAutomaticBackups": "启用自动备份", "LabelBackupsEnableAutomaticBackups": "启用自动备份",
"LabelBackupsEnableAutomaticBackupsHelp": "备份保存到 /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "备份保存到 /metadata/backups",
@@ -245,15 +253,18 @@
"LabelBackupsNumberToKeep": "要保留的备份个数", "LabelBackupsNumberToKeep": "要保留的备份个数",
"LabelBackupsNumberToKeepHelp": "一次只能删除一个备份, 因此如果你已经有超过此数量的备份, 则应手动删除它们.", "LabelBackupsNumberToKeepHelp": "一次只能删除一个备份, 因此如果你已经有超过此数量的备份, 则应手动删除它们.",
"LabelBitrate": "比特率", "LabelBitrate": "比特率",
"LabelBonus": "额外",
"LabelBooks": "图书", "LabelBooks": "图书",
"LabelButtonText": "按钮文本", "LabelButtonText": "按钮文本",
"LabelByAuthor": "由 {0}", "LabelByAuthor": "由 {0}",
"LabelChangePassword": "修改密码", "LabelChangePassword": "修改密码",
"LabelChannels": "声道", "LabelChannels": "声道",
"LabelChapterCount": "{0} 章节",
"LabelChapterTitle": "章节标题", "LabelChapterTitle": "章节标题",
"LabelChapters": "章节", "LabelChapters": "章节",
"LabelChaptersFound": "找到的章节", "LabelChaptersFound": "找到的章节",
"LabelClickForMoreInfo": "点击了解更多信息", "LabelClickForMoreInfo": "点击了解更多信息",
"LabelClickToUseCurrentValue": "点击使用当前值",
"LabelClosePlayer": "关闭播放器", "LabelClosePlayer": "关闭播放器",
"LabelCodec": "编解码", "LabelCodec": "编解码",
"LabelCollapseSeries": "折叠系列", "LabelCollapseSeries": "折叠系列",
@@ -303,12 +314,25 @@
"LabelEmailSettingsTestAddress": "测试地址", "LabelEmailSettingsTestAddress": "测试地址",
"LabelEmbeddedCover": "嵌入封面", "LabelEmbeddedCover": "嵌入封面",
"LabelEnable": "启用", "LabelEnable": "启用",
"LabelEncodingBackupLocation": "你的原始音频文件的备份将存储在:",
"LabelEncodingChaptersNotEmbedded": "多轨有声读物中未嵌入章节.",
"LabelEncodingClearItemCache": "确保定期清除项目缓存.",
"LabelEncodingFinishedM4B": "完成的 M4B 将被放入你的有声读物文件夹中:",
"LabelEncodingInfoEmbedded": "元数据将嵌入有声读物文件夹内的音轨中.",
"LabelEncodingStartedNavigation": "一旦任务开始, 你就可以离开此页面.",
"LabelEncodingTimeWarning": "编码最多可能需要 30 分钟.",
"LabelEncodingWarningAdvancedSettings": "警告: 除非你熟悉 ffmpeg 编码选项, 否则请不要更新这些设置.",
"LabelEncodingWatcherDisabled": "如果你禁用了监视器, 则随后需要重新扫描此有声读物.",
"LabelEnd": "结束", "LabelEnd": "结束",
"LabelEndOfChapter": "章节结束", "LabelEndOfChapter": "章节结束",
"LabelEpisode": "剧集", "LabelEpisode": "剧集",
"LabelEpisodeNotLinkedToRssFeed": "剧集没有链接到RSS源",
"LabelEpisodeNumber": "剧集 #{0}",
"LabelEpisodeTitle": "剧集标题", "LabelEpisodeTitle": "剧集标题",
"LabelEpisodeType": "剧集类型", "LabelEpisodeType": "剧集类型",
"LabelEpisodeUrlFromRssFeed": "来自 RSS 订阅的剧集 URL",
"LabelEpisodes": "剧集", "LabelEpisodes": "剧集",
"LabelEpisodic": "剧集",
"LabelExample": "示例", "LabelExample": "示例",
"LabelExpandSeries": "展开系列", "LabelExpandSeries": "展开系列",
"LabelExpandSubSeries": "展开子系列", "LabelExpandSubSeries": "展开子系列",
@@ -336,6 +360,7 @@
"LabelFontScale": "字体比例", "LabelFontScale": "字体比例",
"LabelFontStrikethrough": "删除线", "LabelFontStrikethrough": "删除线",
"LabelFormat": "编码格式", "LabelFormat": "编码格式",
"LabelFull": "完整",
"LabelGenre": "流派", "LabelGenre": "流派",
"LabelGenres": "流派", "LabelGenres": "流派",
"LabelHardDeleteFile": "完全删除文件", "LabelHardDeleteFile": "完全删除文件",
@@ -391,6 +416,10 @@
"LabelLowestPriority": "最低优先级", "LabelLowestPriority": "最低优先级",
"LabelMatchExistingUsersBy": "匹配现有用户", "LabelMatchExistingUsersBy": "匹配现有用户",
"LabelMatchExistingUsersByDescription": "用于连接现有用户. 连接后, 用户将通过 SSO 提供商提供的唯一 id 进行匹配", "LabelMatchExistingUsersByDescription": "用于连接现有用户. 连接后, 用户将通过 SSO 提供商提供的唯一 id 进行匹配",
"LabelMaxEpisodesToDownload": "可下载的最大集数. 输入 0 表示无限制.",
"LabelMaxEpisodesToDownloadPerCheck": "每次检查最多可下载新剧集数",
"LabelMaxEpisodesToKeep": "要保留的最大剧集数",
"LabelMaxEpisodesToKeepHelp": "值为 0 时, 不设置最大限制. 自动下载新剧集后, 如果您有超过 X 个剧集, 它将删除最旧的剧集. 每次新下载时, 只会删除 1 个剧集.",
"LabelMediaPlayer": "媒体播放器", "LabelMediaPlayer": "媒体播放器",
"LabelMediaType": "媒体类型", "LabelMediaType": "媒体类型",
"LabelMetaTag": "元数据标签", "LabelMetaTag": "元数据标签",
@@ -436,12 +465,14 @@
"LabelOpenIDGroupClaimDescription": "OpenID 声明的名称, 该声明包含用户组的列表. 通常称为<code>组</code><b>如果已配置</b>, 应用程序将根据用户的组成员身份自动分配角色, 前提是这些组在声明中以不区分大小写的方式命名为 'Admin', 'User' 或 'Guest'. 声明应包含一个列表, 如果用户属于多个组, 则应用程序将分配与最高访问级别相对应的角色. 如果没有组匹配, 访问将被拒绝.", "LabelOpenIDGroupClaimDescription": "OpenID 声明的名称, 该声明包含用户组的列表. 通常称为<code>组</code><b>如果已配置</b>, 应用程序将根据用户的组成员身份自动分配角色, 前提是这些组在声明中以不区分大小写的方式命名为 'Admin', 'User' 或 'Guest'. 声明应包含一个列表, 如果用户属于多个组, 则应用程序将分配与最高访问级别相对应的角色. 如果没有组匹配, 访问将被拒绝.",
"LabelOpenRSSFeed": "打开 RSS 源", "LabelOpenRSSFeed": "打开 RSS 源",
"LabelOverwrite": "覆盖", "LabelOverwrite": "覆盖",
"LabelPaginationPageXOfY": "第 {0} 页 共 {1} 页",
"LabelPassword": "密码", "LabelPassword": "密码",
"LabelPath": "路径", "LabelPath": "路径",
"LabelPermanent": "永久的", "LabelPermanent": "永久的",
"LabelPermissionsAccessAllLibraries": "可以访问所有媒体库", "LabelPermissionsAccessAllLibraries": "可以访问所有媒体库",
"LabelPermissionsAccessAllTags": "可以访问所有标签", "LabelPermissionsAccessAllTags": "可以访问所有标签",
"LabelPermissionsAccessExplicitContent": "可以访问显式内容", "LabelPermissionsAccessExplicitContent": "可以访问显式内容",
"LabelPermissionsCreateEreader": "可以创建电子阅读器",
"LabelPermissionsDelete": "可以删除", "LabelPermissionsDelete": "可以删除",
"LabelPermissionsDownload": "可以下载", "LabelPermissionsDownload": "可以下载",
"LabelPermissionsUpdate": "可以更新", "LabelPermissionsUpdate": "可以更新",
@@ -465,6 +496,8 @@
"LabelPubDate": "出版日期", "LabelPubDate": "出版日期",
"LabelPublishYear": "发布年份", "LabelPublishYear": "发布年份",
"LabelPublishedDate": "已发布 {0}", "LabelPublishedDate": "已发布 {0}",
"LabelPublishedDecade": "出版年代",
"LabelPublishedDecades": "出版年代",
"LabelPublisher": "出版商", "LabelPublisher": "出版商",
"LabelPublishers": "出版商", "LabelPublishers": "出版商",
"LabelRSSFeedCustomOwnerEmail": "自定义所有者电子邮件", "LabelRSSFeedCustomOwnerEmail": "自定义所有者电子邮件",
@@ -484,21 +517,28 @@
"LabelRedo": "重做", "LabelRedo": "重做",
"LabelRegion": "区域", "LabelRegion": "区域",
"LabelReleaseDate": "发布日期", "LabelReleaseDate": "发布日期",
"LabelRemoveAllMetadataAbs": "删除所有 metadata.abs 文件",
"LabelRemoveAllMetadataJson": "删除所有 metadata.json 文件",
"LabelRemoveCover": "移除封面", "LabelRemoveCover": "移除封面",
"LabelRemoveMetadataFile": "删除库项目文件夹中的元数据文件",
"LabelRemoveMetadataFileHelp": "删除 {0} 文件夹中的所有 metadata.json 和 metadata.abs 文件.",
"LabelRowsPerPage": "每页行数", "LabelRowsPerPage": "每页行数",
"LabelSearchTerm": "搜索项", "LabelSearchTerm": "搜索项",
"LabelSearchTitle": "搜索标题", "LabelSearchTitle": "搜索标题",
"LabelSearchTitleOrASIN": "搜索标题或 ASIN", "LabelSearchTitleOrASIN": "搜索标题或 ASIN",
"LabelSeason": "季", "LabelSeason": "季",
"LabelSeasonNumber": "第 {0} 季",
"LabelSelectAll": "全选", "LabelSelectAll": "全选",
"LabelSelectAllEpisodes": "选择所有剧集", "LabelSelectAllEpisodes": "选择所有剧集",
"LabelSelectEpisodesShowing": "选择正在播放的 {0} 剧集", "LabelSelectEpisodesShowing": "选择正在播放的 {0} 剧集",
"LabelSelectUsers": "选择用户", "LabelSelectUsers": "选择用户",
"LabelSendEbookToDevice": "发送电子书到...", "LabelSendEbookToDevice": "发送电子书到...",
"LabelSequence": "序列", "LabelSequence": "序列",
"LabelSerial": "系列",
"LabelSeries": "系列", "LabelSeries": "系列",
"LabelSeriesName": "系列名称", "LabelSeriesName": "系列名称",
"LabelSeriesProgress": "系列进度", "LabelSeriesProgress": "系列进度",
"LabelServerLogLevel": "服务器日志级别",
"LabelServerYearReview": "服务器年度回顾 ({0})", "LabelServerYearReview": "服务器年度回顾 ({0})",
"LabelSetEbookAsPrimary": "设置为主", "LabelSetEbookAsPrimary": "设置为主",
"LabelSetEbookAsSupplementary": "设置为补充", "LabelSetEbookAsSupplementary": "设置为补充",
@@ -523,6 +563,9 @@
"LabelSettingsHideSingleBookSeriesHelp": "只有一本书的系列将从系列页面和主页书架中隐藏.", "LabelSettingsHideSingleBookSeriesHelp": "只有一本书的系列将从系列页面和主页书架中隐藏.",
"LabelSettingsHomePageBookshelfView": "首页使用书架视图", "LabelSettingsHomePageBookshelfView": "首页使用书架视图",
"LabelSettingsLibraryBookshelfView": "媒体库使用书架视图", "LabelSettingsLibraryBookshelfView": "媒体库使用书架视图",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "完成百分比大于",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "剩余时间少于 (秒)",
"LabelSettingsLibraryMarkAsFinishedWhen": "当发生以下情况时将媒体项目标记为已完成",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "跳过继续系列中的早期书籍", "LabelSettingsOnlyShowLaterBooksInContinueSeries": "跳过继续系列中的早期书籍",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "继续系列主页书架显示系列中未开始的第一本书, 该系列至少有一本书已完成且没有正在进行的书. 启用此设置将从最远完成的书开始系列, 而不是从第一本书开始.", "LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "继续系列主页书架显示系列中未开始的第一本书, 该系列至少有一本书已完成且没有正在进行的书. 启用此设置将从最远完成的书开始系列, 而不是从第一本书开始.",
"LabelSettingsParseSubtitles": "解析副标题", "LabelSettingsParseSubtitles": "解析副标题",
@@ -587,6 +630,7 @@
"LabelTimeDurationXMinutes": "{0} 分钟", "LabelTimeDurationXMinutes": "{0} 分钟",
"LabelTimeDurationXSeconds": "{0} 秒", "LabelTimeDurationXSeconds": "{0} 秒",
"LabelTimeInMinutes": "时间 (分钟)", "LabelTimeInMinutes": "时间 (分钟)",
"LabelTimeLeft": "剩余 {0}",
"LabelTimeListened": "收听时间", "LabelTimeListened": "收听时间",
"LabelTimeListenedToday": "今日收听的时间", "LabelTimeListenedToday": "今日收听的时间",
"LabelTimeRemaining": "剩余 {0}", "LabelTimeRemaining": "剩余 {0}",
@@ -594,6 +638,7 @@
"LabelTitle": "标题", "LabelTitle": "标题",
"LabelToolsEmbedMetadata": "嵌入元数据", "LabelToolsEmbedMetadata": "嵌入元数据",
"LabelToolsEmbedMetadataDescription": "将元数据嵌入音频文件, 包括封面图像和章节.", "LabelToolsEmbedMetadataDescription": "将元数据嵌入音频文件, 包括封面图像和章节.",
"LabelToolsM4bEncoder": "M4B 编码器",
"LabelToolsMakeM4b": "制作 M4B 有声读物文件", "LabelToolsMakeM4b": "制作 M4B 有声读物文件",
"LabelToolsMakeM4bDescription": "生成带有嵌入元数据, 封面图像和章节的 .M4B 有声读物文件.", "LabelToolsMakeM4bDescription": "生成带有嵌入元数据, 封面图像和章节的 .M4B 有声读物文件.",
"LabelToolsSplitM4b": "将 M4B 文件拆分为 MP3 文件", "LabelToolsSplitM4b": "将 M4B 文件拆分为 MP3 文件",
@@ -606,6 +651,7 @@
"LabelTracksMultiTrack": "多轨", "LabelTracksMultiTrack": "多轨",
"LabelTracksNone": "没有音轨", "LabelTracksNone": "没有音轨",
"LabelTracksSingleTrack": "单轨", "LabelTracksSingleTrack": "单轨",
"LabelTrailer": "预告",
"LabelType": "类型", "LabelType": "类型",
"LabelUnabridged": "未删节", "LabelUnabridged": "未删节",
"LabelUndo": "撤消", "LabelUndo": "撤消",
@@ -619,8 +665,10 @@
"LabelUploaderDragAndDrop": "拖放文件或文件夹", "LabelUploaderDragAndDrop": "拖放文件或文件夹",
"LabelUploaderDropFiles": "删除文件", "LabelUploaderDropFiles": "删除文件",
"LabelUploaderItemFetchMetadataHelp": "自动获取标题, 作者和系列", "LabelUploaderItemFetchMetadataHelp": "自动获取标题, 作者和系列",
"LabelUseAdvancedOptions": "使用高级选项",
"LabelUseChapterTrack": "使用章节音轨", "LabelUseChapterTrack": "使用章节音轨",
"LabelUseFullTrack": "使用完整音轨", "LabelUseFullTrack": "使用完整音轨",
"LabelUseZeroForUnlimited": "使用 0 表示无限制",
"LabelUser": "用户", "LabelUser": "用户",
"LabelUsername": "用户名", "LabelUsername": "用户名",
"LabelValue": "值", "LabelValue": "值",
@@ -659,25 +707,27 @@
"MessageCheckingCron": "检查计划任务...", "MessageCheckingCron": "检查计划任务...",
"MessageConfirmCloseFeed": "你确定要关闭此订阅源吗?", "MessageConfirmCloseFeed": "你确定要关闭此订阅源吗?",
"MessageConfirmDeleteBackup": "你确定要删除备份 {0}?", "MessageConfirmDeleteBackup": "你确定要删除备份 {0}?",
"MessageConfirmDeleteDevice": "确定要删除电子阅读器设备 \"{0}\" 吗?", "MessageConfirmDeleteDevice": "确定要删除电子阅读器设备 \"{0}\" 吗?",
"MessageConfirmDeleteFile": "这将从文件系统中删除该文件. 你确定吗?", "MessageConfirmDeleteFile": "这将从文件系统中删除该文件. 你确定吗?",
"MessageConfirmDeleteLibrary": "你确定要永久删除媒体库 \"{0}\"?", "MessageConfirmDeleteLibrary": "你确定要永久删除媒体库 \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "这将从数据库和文件系统中删除库项目. 你确定吗?", "MessageConfirmDeleteLibraryItem": "这将从数据库和文件系统中删除库项目. 你确定吗?",
"MessageConfirmDeleteLibraryItems": "这将从数据库和文件系统中删除 {0} 个库项目. 你确定吗?", "MessageConfirmDeleteLibraryItems": "这将从数据库和文件系统中删除 {0} 个库项目. 你确定吗?",
"MessageConfirmDeleteMetadataProvider": "是否确实要删除自定义元数据提供商 \"{0}\" ?", "MessageConfirmDeleteMetadataProvider": "是否确实要删除自定义元数据提供商 \"{0}\" ?",
"MessageConfirmDeleteNotification": "确定要删除此通知吗?", "MessageConfirmDeleteNotification": "确定要删除此通知吗?",
"MessageConfirmDeleteSession": "你确定要删除此会话吗?", "MessageConfirmDeleteSession": "你确定要删除此会话吗?",
"MessageConfirmEmbedMetadataInAudioFiles": "你确定要将元数据嵌入到 {0} 个音频文件中吗?",
"MessageConfirmForceReScan": "你确定要强制重新扫描吗?", "MessageConfirmForceReScan": "你确定要强制重新扫描吗?",
"MessageConfirmMarkAllEpisodesFinished": "你确定要将所有剧集都标记为已完成吗?", "MessageConfirmMarkAllEpisodesFinished": "你确定要将所有剧集都标记为已完成吗?",
"MessageConfirmMarkAllEpisodesNotFinished": "你确定要将所有剧集都标记为未完成吗?", "MessageConfirmMarkAllEpisodesNotFinished": "你确定要将所有剧集都标记为未完成吗?",
"MessageConfirmMarkItemFinished": "确定要将 \"{0}\" 标记为已完成吗?", "MessageConfirmMarkItemFinished": "确定要将 \"{0}\" 标记为已完成吗?",
"MessageConfirmMarkItemNotFinished": "确定要将 \"{0}\" 标记为未完成吗?", "MessageConfirmMarkItemNotFinished": "确定要将 \"{0}\" 标记为未完成吗?",
"MessageConfirmMarkSeriesFinished": "你确定要将此系列中的所有书籍都标记为已听完吗?", "MessageConfirmMarkSeriesFinished": "你确定要将此系列中的所有书籍都标记为已听完吗?",
"MessageConfirmMarkSeriesNotFinished": "你确定要将此系列中的所有书籍都标记为未听完吗?", "MessageConfirmMarkSeriesNotFinished": "你确定要将此系列中的所有书籍都标记为未听完吗?",
"MessageConfirmNotificationTestTrigger": "使用测试数据触发此通知吗?", "MessageConfirmNotificationTestTrigger": "使用测试数据触发此通知吗?",
"MessageConfirmPurgeCache": "清除缓存将删除 <code>/metadata/cache</code> 整个目录. <br /><br />你确定要删除缓存目录吗?", "MessageConfirmPurgeCache": "清除缓存将删除 <code>/metadata/cache</code> 整个目录. <br /><br />你确定要删除缓存目录吗?",
"MessageConfirmPurgeItemsCache": "清除项目缓存将删除 <code>/metadata/cache/items</code> 整个目录.<br />你确定吗?", "MessageConfirmPurgeItemsCache": "清除项目缓存将删除 <code>/metadata/cache/items</code> 整个目录.<br />你确定吗?",
"MessageConfirmQuickEmbed": "警告! 快速嵌入不会备份你的音频文件. 确保你有音频文件的备份. <br><br>你是否想继续吗?", "MessageConfirmQuickEmbed": "警告! 快速嵌入不会备份你的音频文件. 确保你有音频文件的备份. <br><br>你是否想继续吗?",
"MessageConfirmQuickMatchEpisodes": "如果找到匹配项, 快速匹配的剧集将覆盖详细信息. 只有不匹配的剧集才会更新. 你确定吗?",
"MessageConfirmReScanLibraryItems": "你确定要重新扫描 {0} 个项目吗?", "MessageConfirmReScanLibraryItems": "你确定要重新扫描 {0} 个项目吗?",
"MessageConfirmRemoveAllChapters": "你确定要移除所有章节吗?", "MessageConfirmRemoveAllChapters": "你确定要移除所有章节吗?",
"MessageConfirmRemoveAuthor": "你确定要删除作者 \"{0}\"?", "MessageConfirmRemoveAuthor": "你确定要删除作者 \"{0}\"?",
@@ -685,6 +735,7 @@
"MessageConfirmRemoveEpisode": "你确定要移除剧集 \"{0}\"?", "MessageConfirmRemoveEpisode": "你确定要移除剧集 \"{0}\"?",
"MessageConfirmRemoveEpisodes": "你确定要移除 {0} 剧集?", "MessageConfirmRemoveEpisodes": "你确定要移除 {0} 剧集?",
"MessageConfirmRemoveListeningSessions": "你确定要移除 {0} 收听会话吗?", "MessageConfirmRemoveListeningSessions": "你确定要移除 {0} 收听会话吗?",
"MessageConfirmRemoveMetadataFiles": "你确实要删除库项目文件夹中的所有 metadata.{0} 文件吗?",
"MessageConfirmRemoveNarrator": "你确定要删除演播者 \"{0}\"?", "MessageConfirmRemoveNarrator": "你确定要删除演播者 \"{0}\"?",
"MessageConfirmRemovePlaylist": "你确定要移除播放列表 \"{0}\"?", "MessageConfirmRemovePlaylist": "你确定要移除播放列表 \"{0}\"?",
"MessageConfirmRenameGenre": "你确定要将所有项目流派 \"{0}\" 重命名到 \"{1}\"?", "MessageConfirmRenameGenre": "你确定要将所有项目流派 \"{0}\" 重命名到 \"{1}\"?",
@@ -695,11 +746,12 @@
"MessageConfirmRenameTagWarning": "警告! 已经存在有大小写不同的类似标签 \"{0}\".", "MessageConfirmRenameTagWarning": "警告! 已经存在有大小写不同的类似标签 \"{0}\".",
"MessageConfirmResetProgress": "你确定要重置进度吗?", "MessageConfirmResetProgress": "你确定要重置进度吗?",
"MessageConfirmSendEbookToDevice": "你确定要发送 {0} 电子书 \"{1}\" 到设备 \"{2}\"?", "MessageConfirmSendEbookToDevice": "你确定要发送 {0} 电子书 \"{1}\" 到设备 \"{2}\"?",
"MessageConfirmUnlinkOpenId": "确定要取消该用户与 OpenID 的链接吗?", "MessageConfirmUnlinkOpenId": "确定要取消该用户与 OpenID 的链接吗?",
"MessageDownloadingEpisode": "正在下载剧集", "MessageDownloadingEpisode": "正在下载剧集",
"MessageDragFilesIntoTrackOrder": "将文件拖动到正确的音轨顺序", "MessageDragFilesIntoTrackOrder": "将文件拖动到正确的音轨顺序",
"MessageEmbedFailed": "嵌入失败!", "MessageEmbedFailed": "嵌入失败!",
"MessageEmbedFinished": "嵌入完成!", "MessageEmbedFinished": "嵌入完成!",
"MessageEmbedQueue": "已排队等待元数据嵌入 (队列中有 {0} 个)",
"MessageEpisodesQueuedForDownload": "{0} 个剧集排队等待下载", "MessageEpisodesQueuedForDownload": "{0} 个剧集排队等待下载",
"MessageEreaderDevices": "为了确保电子书的送达, 你可能需要将上述电子邮件地址添加为下列每台设备的有效发件人.", "MessageEreaderDevices": "为了确保电子书的送达, 你可能需要将上述电子邮件地址添加为下列每台设备的有效发件人.",
"MessageFeedURLWillBe": "源 URL 将改为 {0}", "MessageFeedURLWillBe": "源 URL 将改为 {0}",
@@ -744,6 +796,7 @@
"MessageNoLogs": "无日志", "MessageNoLogs": "无日志",
"MessageNoMediaProgress": "无媒体进度", "MessageNoMediaProgress": "无媒体进度",
"MessageNoNotifications": "无通知", "MessageNoNotifications": "无通知",
"MessageNoPodcastFeed": "无效播客: 无源",
"MessageNoPodcastsFound": "未找到播客", "MessageNoPodcastsFound": "未找到播客",
"MessageNoResults": "无结果", "MessageNoResults": "无结果",
"MessageNoSearchResultsFor": "没有搜索到结果 \"{0}\"", "MessageNoSearchResultsFor": "没有搜索到结果 \"{0}\"",
@@ -760,6 +813,10 @@
"MessagePlaylistCreateFromCollection": "从收藏中创建播放列表", "MessagePlaylistCreateFromCollection": "从收藏中创建播放列表",
"MessagePleaseWait": "请稍等...", "MessagePleaseWait": "请稍等...",
"MessagePodcastHasNoRSSFeedForMatching": "播客没有可用于匹配 RSS 源的 url", "MessagePodcastHasNoRSSFeedForMatching": "播客没有可用于匹配 RSS 源的 url",
"MessagePodcastSearchField": "输入搜索词或 RSS 源 URL",
"MessageQuickEmbedInProgress": "正在进行快速嵌入",
"MessageQuickEmbedQueue": "已排队等待快速嵌入 (队列中有 {0} 个)",
"MessageQuickMatchAllEpisodes": "快速匹配所有剧集",
"MessageQuickMatchDescription": "使用来自 '{0}' 的第一个匹配结果填充空白详细信息和封面. 除非启用 '首选匹配元数据' 服务器设置, 否则不会覆盖详细信息.", "MessageQuickMatchDescription": "使用来自 '{0}' 的第一个匹配结果填充空白详细信息和封面. 除非启用 '首选匹配元数据' 服务器设置, 否则不会覆盖详细信息.",
"MessageRemoveChapter": "移除章节", "MessageRemoveChapter": "移除章节",
"MessageRemoveEpisodes": "移除 {0} 剧集", "MessageRemoveEpisodes": "移除 {0} 剧集",
@@ -802,6 +859,9 @@
"MessageTaskOpmlImportFeedPodcastExists": "播客已存在于路径中", "MessageTaskOpmlImportFeedPodcastExists": "播客已存在于路径中",
"MessageTaskOpmlImportFeedPodcastFailed": "无法创建播客", "MessageTaskOpmlImportFeedPodcastFailed": "无法创建播客",
"MessageTaskOpmlImportFinished": "已添加 {0} 播客", "MessageTaskOpmlImportFinished": "已添加 {0} 播客",
"MessageTaskOpmlParseFailed": "无法解析 OPML 文件",
"MessageTaskOpmlParseFastFail": "未找到无效的 OPML 文件 <opml> 标签或未找到 <outline> 标签",
"MessageTaskOpmlParseNoneFound": "OPML 文件中未找到任何信息",
"MessageTaskScanItemsAdded": "{0} 已添加", "MessageTaskScanItemsAdded": "{0} 已添加",
"MessageTaskScanItemsMissing": "{0} 已缺失", "MessageTaskScanItemsMissing": "{0} 已缺失",
"MessageTaskScanItemsUpdated": "{0} 已更新", "MessageTaskScanItemsUpdated": "{0} 已更新",
@@ -826,6 +886,10 @@
"NoteUploaderFoldersWithMediaFiles": "包含媒体文件的文件夹将作为单独的媒体库项目处理.", "NoteUploaderFoldersWithMediaFiles": "包含媒体文件的文件夹将作为单独的媒体库项目处理.",
"NoteUploaderOnlyAudioFiles": "如果只上传音频文件, 则每个音频文件将作为单独的有声读物处理.", "NoteUploaderOnlyAudioFiles": "如果只上传音频文件, 则每个音频文件将作为单独的有声读物处理.",
"NoteUploaderUnsupportedFiles": "不支持的文件将被忽略. 选择或删除文件夹时, 将忽略不在项目文件夹中的其他文件.", "NoteUploaderUnsupportedFiles": "不支持的文件将被忽略. 选择或删除文件夹时, 将忽略不在项目文件夹中的其他文件.",
"NotificationOnBackupCompletedDescription": "备份完成时触发",
"NotificationOnBackupFailedDescription": "备份失败时触发",
"NotificationOnEpisodeDownloadedDescription": "当播客节目自动下载时触发",
"NotificationOnTestDescription": "测试通知系统的事件",
"PlaceholderNewCollection": "输入收藏夹名称", "PlaceholderNewCollection": "输入收藏夹名称",
"PlaceholderNewFolderPath": "输入文件夹路径", "PlaceholderNewFolderPath": "输入文件夹路径",
"PlaceholderNewPlaylist": "输入播放列表名称", "PlaceholderNewPlaylist": "输入播放列表名称",
@@ -837,7 +901,7 @@
"StatsBooksFinished": "已完成书籍", "StatsBooksFinished": "已完成书籍",
"StatsBooksFinishedThisYear": "今年完成的一些书…", "StatsBooksFinishedThisYear": "今年完成的一些书…",
"StatsBooksListenedTo": "听过的书", "StatsBooksListenedTo": "听过的书",
"StatsCollectionGrewTo": "的藏书已增长到…", "StatsCollectionGrewTo": "的藏书已增长到…",
"StatsSessions": "会话", "StatsSessions": "会话",
"StatsSpentListening": "花时间聆听", "StatsSpentListening": "花时间聆听",
"StatsTopAuthor": "热门作者", "StatsTopAuthor": "热门作者",
@@ -851,6 +915,7 @@
"StatsYearInReview": "年度回顾", "StatsYearInReview": "年度回顾",
"ToastAccountUpdateSuccess": "帐户已更新", "ToastAccountUpdateSuccess": "帐户已更新",
"ToastAppriseUrlRequired": "必须输入 Apprise URL", "ToastAppriseUrlRequired": "必须输入 Apprise URL",
"ToastAsinRequired": "需要 ASIN",
"ToastAuthorImageRemoveSuccess": "作者图像已删除", "ToastAuthorImageRemoveSuccess": "作者图像已删除",
"ToastAuthorNotFound": "未找到作者 \"{0}\"", "ToastAuthorNotFound": "未找到作者 \"{0}\"",
"ToastAuthorRemoveSuccess": "作者已删除", "ToastAuthorRemoveSuccess": "作者已删除",
@@ -870,6 +935,8 @@
"ToastBackupUploadSuccess": "备份已上传", "ToastBackupUploadSuccess": "备份已上传",
"ToastBatchDeleteFailed": "批量删除失败", "ToastBatchDeleteFailed": "批量删除失败",
"ToastBatchDeleteSuccess": "批量删除成功", "ToastBatchDeleteSuccess": "批量删除成功",
"ToastBatchQuickMatchFailed": "批量快速匹配失败!",
"ToastBatchQuickMatchStarted": "批量快速匹配 {0} 图书已开始!",
"ToastBatchUpdateFailed": "批量更新失败", "ToastBatchUpdateFailed": "批量更新失败",
"ToastBatchUpdateSuccess": "批量更新成功", "ToastBatchUpdateSuccess": "批量更新成功",
"ToastBookmarkCreateFailed": "创建书签失败", "ToastBookmarkCreateFailed": "创建书签失败",
@@ -881,6 +948,7 @@
"ToastChaptersHaveErrors": "章节有错误", "ToastChaptersHaveErrors": "章节有错误",
"ToastChaptersMustHaveTitles": "章节必须有标题", "ToastChaptersMustHaveTitles": "章节必须有标题",
"ToastChaptersRemoved": "已删除章节", "ToastChaptersRemoved": "已删除章节",
"ToastChaptersUpdated": "章节已更新",
"ToastCollectionItemsAddFailed": "项目添加到收藏夹失败", "ToastCollectionItemsAddFailed": "项目添加到收藏夹失败",
"ToastCollectionItemsAddSuccess": "项目添加到收藏夹成功", "ToastCollectionItemsAddSuccess": "项目添加到收藏夹成功",
"ToastCollectionItemsRemoveSuccess": "项目从收藏夹移除", "ToastCollectionItemsRemoveSuccess": "项目从收藏夹移除",
@@ -898,11 +966,14 @@
"ToastEncodeCancelSucces": "编码已取消", "ToastEncodeCancelSucces": "编码已取消",
"ToastEpisodeDownloadQueueClearFailed": "无法清除队列", "ToastEpisodeDownloadQueueClearFailed": "无法清除队列",
"ToastEpisodeDownloadQueueClearSuccess": "剧集下载队列已清空", "ToastEpisodeDownloadQueueClearSuccess": "剧集下载队列已清空",
"ToastEpisodeUpdateSuccess": "已更新 {0} 剧集",
"ToastErrorCannotShare": "无法在此设备上本地共享", "ToastErrorCannotShare": "无法在此设备上本地共享",
"ToastFailedToLoadData": "加载数据失败", "ToastFailedToLoadData": "加载数据失败",
"ToastFailedToMatch": "匹配失败",
"ToastFailedToShare": "分享失败", "ToastFailedToShare": "分享失败",
"ToastFailedToUpdate": "更新失败", "ToastFailedToUpdate": "更新失败",
"ToastInvalidImageUrl": "图片网址无效", "ToastInvalidImageUrl": "图片网址无效",
"ToastInvalidMaxEpisodesToDownload": "可下载的最大集数无效",
"ToastInvalidUrl": "网址无效", "ToastInvalidUrl": "网址无效",
"ToastItemCoverUpdateSuccess": "项目封面已更新", "ToastItemCoverUpdateSuccess": "项目封面已更新",
"ToastItemDeletedFailed": "删除项目失败", "ToastItemDeletedFailed": "删除项目失败",
@@ -920,14 +991,22 @@
"ToastLibraryScanFailedToStart": "无法启动扫描", "ToastLibraryScanFailedToStart": "无法启动扫描",
"ToastLibraryScanStarted": "媒体库扫描已启动", "ToastLibraryScanStarted": "媒体库扫描已启动",
"ToastLibraryUpdateSuccess": "媒体库 \"{0}\" 已更新", "ToastLibraryUpdateSuccess": "媒体库 \"{0}\" 已更新",
"ToastMatchAllAuthorsFailed": "无法匹配所有作者",
"ToastMetadataFilesRemovedError": "删除 metadata.{0} 文件时出错",
"ToastMetadataFilesRemovedNoneFound": "在库中没有找到 metadata.{0} 文件",
"ToastMetadataFilesRemovedNoneRemoved": "没有 metadata.{0} 文件被删除",
"ToastMetadataFilesRemovedSuccess": "{0} 个 metadata.{1} 文件被删除",
"ToastMustHaveAtLeastOnePath": "必须至少有一个路径",
"ToastNameEmailRequired": "姓名和电子邮件为必填项", "ToastNameEmailRequired": "姓名和电子邮件为必填项",
"ToastNameRequired": "姓名为必填项", "ToastNameRequired": "姓名为必填项",
"ToastNewEpisodesFound": "找到 {0} 个新剧集",
"ToastNewUserCreatedFailed": "无法创建帐户: \"{0}\"", "ToastNewUserCreatedFailed": "无法创建帐户: \"{0}\"",
"ToastNewUserCreatedSuccess": "已创建新帐户", "ToastNewUserCreatedSuccess": "已创建新帐户",
"ToastNewUserLibraryError": "必须至少选择一个图书馆", "ToastNewUserLibraryError": "必须至少选择一个图书馆",
"ToastNewUserPasswordError": "必须有密码, 只有root用户可以有空密码", "ToastNewUserPasswordError": "必须有密码, 只有root用户可以有空密码",
"ToastNewUserTagError": "必须至少选择一个标签", "ToastNewUserTagError": "必须至少选择一个标签",
"ToastNewUserUsernameError": "输入用户名", "ToastNewUserUsernameError": "输入用户名",
"ToastNoNewEpisodesFound": "没有找到新剧集",
"ToastNoUpdatesNecessary": "无需更新", "ToastNoUpdatesNecessary": "无需更新",
"ToastNotificationCreateFailed": "无法创建通知", "ToastNotificationCreateFailed": "无法创建通知",
"ToastNotificationDeleteFailed": "删除通知失败", "ToastNotificationDeleteFailed": "删除通知失败",
@@ -946,6 +1025,7 @@
"ToastPodcastGetFeedFailed": "无法获取播客信息", "ToastPodcastGetFeedFailed": "无法获取播客信息",
"ToastPodcastNoEpisodesInFeed": "RSS 订阅中未找到任何剧集", "ToastPodcastNoEpisodesInFeed": "RSS 订阅中未找到任何剧集",
"ToastPodcastNoRssFeed": "播客没有 RSS 源", "ToastPodcastNoRssFeed": "播客没有 RSS 源",
"ToastProgressIsNotBeingSynced": "进度未同步, 请重新开始播放",
"ToastProviderCreatedFailed": "无法添加提供商", "ToastProviderCreatedFailed": "无法添加提供商",
"ToastProviderCreatedSuccess": "已添加新提供商", "ToastProviderCreatedSuccess": "已添加新提供商",
"ToastProviderNameAndUrlRequired": "名称和网址必需填写", "ToastProviderNameAndUrlRequired": "名称和网址必需填写",
@@ -972,6 +1052,7 @@
"ToastSessionCloseFailed": "关闭会话失败", "ToastSessionCloseFailed": "关闭会话失败",
"ToastSessionDeleteFailed": "删除会话失败", "ToastSessionDeleteFailed": "删除会话失败",
"ToastSessionDeleteSuccess": "会话已删除", "ToastSessionDeleteSuccess": "会话已删除",
"ToastSleepTimerDone": "睡眠定时完成... zZzzZz",
"ToastSlugMustChange": "Slug 包含无效字符", "ToastSlugMustChange": "Slug 包含无效字符",
"ToastSlugRequired": "Slug 是必填项", "ToastSlugRequired": "Slug 是必填项",
"ToastSocketConnected": "网络已连接", "ToastSocketConnected": "网络已连接",
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.15.0", "version": "2.16.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.15.0", "version": "2.16.2",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.15.0", "version": "2.16.2",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast server", "description": "Self-hosted audiobook and podcast server",
"main": "index.js", "main": "index.js",
+22 -18
View File
@@ -92,29 +92,33 @@ Toggle websockets support.
Add this to the site config file on your nginx server after you have changed the relevant parts in the <> brackets, and inserted your certificate paths. Add this to the site config file on your nginx server after you have changed the relevant parts in the <> brackets, and inserted your certificate paths.
```bash ```bash
server server {
{ listen 443 ssl;
listen 443 ssl; server_name <sub>.<domain>.<tld>;
server_name <sub>.<domain>.<tld>;
access_log /var/log/nginx/audiobookshelf.access.log; access_log /var/log/nginx/audiobookshelf.access.log;
error_log /var/log/nginx/audiobookshelf.error.log; error_log /var/log/nginx/audiobookshelf.error.log;
ssl_certificate /path/to/certificate; ssl_certificate /path/to/certificate;
ssl_certificate_key /path/to/key; ssl_certificate_key /path/to/key;
location / { location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; proxy_set_header Connection "upgrade";
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_pass http://<URL_to_forward_to>; proxy_pass http://<URL_to_forward_to>;
proxy_redirect http:// https://; proxy_redirect http:// https://;
}
# Prevent 413 Request Entity Too Large error
# by increasing the maximum allowed size of the client request body
# For example, set it to 10 GiB
client_max_body_size 10240M;
}
} }
``` ```
+10 -1
View File
@@ -243,6 +243,15 @@ class Server {
await this.auth.initPassportJs() await this.auth.initPassportJs()
const router = express.Router() const router = express.Router()
// if RouterBasePath is set, modify all requests to include the base path
if (global.RouterBasePath) {
app.use((req, res, next) => {
if (!req.url.startsWith(global.RouterBasePath)) {
req.url = `${global.RouterBasePath}${req.url}`
}
next()
})
}
app.use(global.RouterBasePath, router) app.use(global.RouterBasePath, router)
app.disable('x-powered-by') app.disable('x-powered-by')
@@ -340,7 +349,7 @@ class Server {
Logger.info('Received ping') Logger.info('Received ping')
res.json({ success: true }) res.json({ success: true })
}) })
app.get('/healthcheck', (req, res) => res.sendStatus(200)) router.get('/healthcheck', (req, res) => res.sendStatus(200))
this.server.listen(this.Port, this.Host, () => { this.server.listen(this.Port, this.Host, () => {
if (this.Host) Logger.info(`Listening on http://${this.Host}:${this.Port}`) if (this.Host) Logger.info(`Listening on http://${this.Host}:${this.Port}`)
+2 -1
View File
@@ -103,7 +103,8 @@ class SocketAuthority {
cors: { cors: {
origin: '*', origin: '*',
methods: ['GET', 'POST'] methods: ['GET', 'POST']
} },
path: `${global.RouterBasePath}/socket.io`
}) })
this.io.on('connection', (socket) => { this.io.on('connection', (socket) => {
+44 -2
View File
@@ -235,12 +235,14 @@ class LibraryController {
for (const key of keysToCheck) { for (const key of keysToCheck) {
if (!req.body[key]) continue if (!req.body[key]) continue
if (typeof req.body[key] !== 'string') { if (typeof req.body[key] !== 'string') {
Logger.error(`[LibraryController] Invalid request. ${key} must be a string`)
return res.status(400).send(`Invalid request. ${key} must be a string`) return res.status(400).send(`Invalid request. ${key} must be a string`)
} }
updatePayload[key] = req.body[key] updatePayload[key] = req.body[key]
} }
if (req.body.displayOrder !== undefined) { if (req.body.displayOrder !== undefined) {
if (isNaN(req.body.displayOrder)) { if (isNaN(req.body.displayOrder)) {
Logger.error(`[LibraryController] Invalid request. displayOrder must be a number`)
return res.status(400).send('Invalid request. displayOrder must be a number') return res.status(400).send('Invalid request. displayOrder must be a number')
} }
updatePayload.displayOrder = req.body.displayOrder updatePayload.displayOrder = req.body.displayOrder
@@ -255,18 +257,29 @@ class LibraryController {
} }
// Validate settings // Validate settings
const defaultLibrarySettings = Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType)
const updatedSettings = { const updatedSettings = {
...(req.library.settings || Database.libraryModel.getDefaultLibrarySettingsForMediaType(req.library.mediaType)) ...(req.library.settings || defaultLibrarySettings)
} }
// In case new settings are added in the future, ensure all settings are present
for (const key in defaultLibrarySettings) {
if (updatedSettings[key] === undefined) {
updatedSettings[key] = defaultLibrarySettings[key]
}
}
let hasUpdates = false let hasUpdates = false
let hasUpdatedDisableWatcher = false let hasUpdatedDisableWatcher = false
let hasUpdatedScanCron = false let hasUpdatedScanCron = false
if (req.body.settings) { if (req.body.settings) {
for (const key in req.body.settings) { for (const key in req.body.settings) {
if (updatedSettings[key] === undefined) continue if (!Object.keys(defaultLibrarySettings).includes(key)) {
continue
}
if (key === 'metadataPrecedence') { if (key === 'metadataPrecedence') {
if (!Array.isArray(req.body.settings[key])) { if (!Array.isArray(req.body.settings[key])) {
Logger.error(`[LibraryController] Invalid request. Settings "metadataPrecedence" must be an array`)
return res.status(400).send('Invalid request. Settings "metadataPrecedence" must be an array') return res.status(400).send('Invalid request. Settings "metadataPrecedence" must be an array')
} }
if (JSON.stringify(req.body.settings[key]) !== JSON.stringify(updatedSettings[key])) { if (JSON.stringify(req.body.settings[key]) !== JSON.stringify(updatedSettings[key])) {
@@ -276,6 +289,7 @@ class LibraryController {
} }
} else if (key === 'autoScanCronExpression' || key === 'podcastSearchRegion') { } else if (key === 'autoScanCronExpression' || key === 'podcastSearchRegion') {
if (req.body.settings[key] !== null && typeof req.body.settings[key] !== 'string') { if (req.body.settings[key] !== null && typeof req.body.settings[key] !== 'string') {
Logger.error(`[LibraryController] Invalid request. Settings "${key}" must be a string`)
return res.status(400).send(`Invalid request. Settings "${key}" must be a string`) return res.status(400).send(`Invalid request. Settings "${key}" must be a string`)
} }
if (req.body.settings[key] !== updatedSettings[key]) { if (req.body.settings[key] !== updatedSettings[key]) {
@@ -285,8 +299,35 @@ class LibraryController {
updatedSettings[key] = req.body.settings[key] updatedSettings[key] = req.body.settings[key]
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`) Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
} }
} else if (key === 'markAsFinishedPercentComplete') {
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be a number`)
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
} else if (req.body.settings[key] !== null && (Number(req.body.settings[key]) < 0 || Number(req.body.settings[key]) > 100)) {
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be between 0 and 100`)
return res.status(400).send(`Invalid request. Setting "${key}" must be between 0 and 100`)
}
if (req.body.settings[key] !== updatedSettings[key]) {
hasUpdates = true
updatedSettings[key] = Number(req.body.settings[key])
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
}
} else if (key === 'markAsFinishedTimeRemaining') {
if (req.body.settings[key] !== null && isNaN(req.body.settings[key])) {
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be a number`)
return res.status(400).send(`Invalid request. Setting "${key}" must be a number`)
} else if (req.body.settings[key] !== null && Number(req.body.settings[key]) < 0) {
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be greater than or equal to 0`)
return res.status(400).send(`Invalid request. Setting "${key}" must be greater than or equal to 0`)
}
if (req.body.settings[key] !== updatedSettings[key]) {
hasUpdates = true
updatedSettings[key] = Number(req.body.settings[key])
Logger.debug(`[LibraryController] Library "${req.library.name}" updating setting "${key}" to "${updatedSettings[key]}"`)
}
} else { } else {
if (typeof req.body.settings[key] !== typeof updatedSettings[key]) { if (typeof req.body.settings[key] !== typeof updatedSettings[key]) {
Logger.error(`[LibraryController] Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`) return res.status(400).send(`Invalid request. Setting "${key}" must be of type ${typeof updatedSettings[key]}`)
} }
if (req.body.settings[key] !== updatedSettings[key]) { if (req.body.settings[key] !== updatedSettings[key]) {
@@ -328,6 +369,7 @@ class LibraryController {
return false return false
}) })
if (!success) { if (!success) {
Logger.error(`[LibraryController] Invalid folder directory "${path}"`)
return res.status(400).send(`Invalid folder directory "${path}"`) return res.status(400).send(`Invalid folder directory "${path}"`)
} }
} }
+44 -17
View File
@@ -115,6 +115,16 @@ class LibraryItemController {
res.sendStatus(200) res.sendStatus(200)
} }
static handleDownloadError(error, res) {
if (!res.headersSent) {
if (error.code === 'ENOENT') {
return res.status(404).send('File not found')
} else {
return res.status(500).send('Download failed')
}
}
}
/** /**
* GET: /api/items/:id/download * GET: /api/items/:id/download
* Download library item. Zip file if multiple files. * Download library item. Zip file if multiple files.
@@ -122,7 +132,7 @@ class LibraryItemController {
* @param {RequestWithUser} req * @param {RequestWithUser} req
* @param {Response} res * @param {Response} res
*/ */
download(req, res) { async download(req, res) {
if (!req.user.canDownload) { if (!req.user.canDownload) {
Logger.warn(`User "${req.user.username}" attempted to download without permission`) Logger.warn(`User "${req.user.username}" attempted to download without permission`)
return res.sendStatus(403) return res.sendStatus(403)
@@ -130,21 +140,26 @@ class LibraryItemController {
const libraryItemPath = req.libraryItem.path const libraryItemPath = req.libraryItem.path
const itemTitle = req.libraryItem.media.metadata.title const itemTitle = req.libraryItem.media.metadata.title
// If library item is a single file in root dir then no need to zip
if (req.libraryItem.isFile) {
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(libraryItemPath))
if (audioMimeType) {
res.setHeader('Content-Type', audioMimeType)
}
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
res.download(libraryItemPath, req.libraryItem.relPath)
return
}
Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`) Logger.info(`[LibraryItemController] User "${req.user.username}" requested download for item "${itemTitle}" at "${libraryItemPath}"`)
const filename = `${itemTitle}.zip`
zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res) try {
// If library item is a single file in root dir then no need to zip
if (req.libraryItem.isFile) {
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(libraryItemPath))
if (audioMimeType) {
res.setHeader('Content-Type', audioMimeType)
}
await new Promise((resolve, reject) => res.download(libraryItemPath, req.libraryItem.relPath, (error) => (error ? reject(error) : resolve())))
} else {
const filename = `${itemTitle}.zip`
await zipHelpers.zipDirectoryPipe(libraryItemPath, filename, res)
}
Logger.info(`[LibraryItemController] Downloaded item "${itemTitle}" at "${libraryItemPath}"`)
} catch (error) {
Logger.error(`[LibraryItemController] Download failed for item "${itemTitle}" at "${libraryItemPath}"`, error)
LibraryItemController.handleDownloadError(error, res)
}
} }
/** /**
@@ -845,7 +860,13 @@ class LibraryItemController {
res.setHeader('Content-Type', audioMimeType) res.setHeader('Content-Type', audioMimeType)
} }
res.download(libraryFile.metadata.path, libraryFile.metadata.filename) try {
await new Promise((resolve, reject) => res.download(libraryFile.metadata.path, libraryFile.metadata.filename, (error) => (error ? reject(error) : resolve())))
Logger.info(`[LibraryItemController] Downloaded file "${libraryFile.metadata.path}"`)
} catch (error) {
Logger.error(`[LibraryItemController] Failed to download file "${libraryFile.metadata.path}"`, error)
LibraryItemController.handleDownloadError(error, res)
}
} }
/** /**
@@ -883,7 +904,13 @@ class LibraryItemController {
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send() return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
} }
res.sendFile(ebookFilePath) try {
await new Promise((resolve, reject) => res.sendFile(ebookFilePath, (error) => (error ? reject(error) : resolve())))
Logger.info(`[LibraryItemController] Downloaded ebook file "${ebookFilePath}"`)
} catch (error) {
Logger.error(`[LibraryItemController] Failed to download ebook file "${ebookFilePath}"`, error)
LibraryItemController.handleDownloadError(error, res)
}
} }
/** /**
+52
View File
@@ -394,6 +394,58 @@ class MeController {
res.json(req.user.toOldJSONForBrowser()) res.json(req.user.toOldJSONForBrowser())
} }
/**
* POST: /api/me/ereader-devices
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async updateUserEReaderDevices(req, res) {
if (!req.body.ereaderDevices || !Array.isArray(req.body.ereaderDevices)) {
return res.status(400).send('Invalid payload. ereaderDevices array required')
}
const userEReaderDevices = req.body.ereaderDevices
for (const device of userEReaderDevices) {
if (!device.name || !device.email) {
return res.status(400).send('Invalid payload. ereaderDevices array items must have name and email')
} else if (device.availabilityOption !== 'specificUsers' || device.users?.length !== 1 || device.users[0] !== req.user.id) {
return res.status(400).send('Invalid payload. ereaderDevices array items must have availabilityOption "specificUsers" and only the current user')
}
}
const otherDevices = Database.emailSettings.ereaderDevices.filter((device) => {
return !Database.emailSettings.checkUserCanAccessDevice(device, req.user) || device.users?.length !== 1
})
const ereaderDevices = otherDevices.concat(userEReaderDevices)
// Check for duplicate names
const nameSet = new Set()
const hasDupes = ereaderDevices.some((device) => {
if (nameSet.has(device.name)) {
return true // Duplicate found
}
nameSet.add(device.name)
return false
})
if (hasDupes) {
return res.status(400).send('Invalid payload. Duplicate "name" field found.')
}
const updated = Database.emailSettings.update({ ereaderDevices })
if (updated) {
await Database.updateSetting(Database.emailSettings)
SocketAuthority.clientEmitter(req.user.id, 'ereader-devices-updated', {
ereaderDevices: Database.emailSettings.ereaderDevices
})
}
res.json({
ereaderDevices: Database.emailSettings.getEReaderDevices(req.user)
})
}
/** /**
* GET: /api/me/stats/year/:year * GET: /api/me/stats/year/:year
* *
+1 -1
View File
@@ -130,7 +130,7 @@ class MigrationManager {
async initUmzug(umzugStorage = new SequelizeStorage({ sequelize: this.sequelize })) { async initUmzug(umzugStorage = new SequelizeStorage({ sequelize: this.sequelize })) {
// This check is for dependency injection in tests // This check is for dependency injection in tests
const files = (await fs.readdir(this.migrationsDir)).map((file) => path.join(this.migrationsDir, file)) const files = (await fs.readdir(this.migrationsDir)).filter((file) => !file.startsWith('.')).map((file) => path.join(this.migrationsDir, file))
const parent = new Umzug({ const parent = new Umzug({
migrations: { migrations: {
+29 -4
View File
@@ -119,6 +119,7 @@ class PlaybackSessionManager {
* @returns * @returns
*/ */
async syncLocalSession(user, sessionJson, deviceInfo) { async syncLocalSession(user, sessionJson, deviceInfo) {
// TODO: Combine libraryItem query with library query
const libraryItem = await Database.libraryItemModel.getOldById(sessionJson.libraryItemId) const libraryItem = await Database.libraryItemModel.getOldById(sessionJson.libraryItemId)
const episode = sessionJson.episodeId && libraryItem && libraryItem.isPodcast ? libraryItem.media.getEpisode(sessionJson.episodeId) : null const episode = sessionJson.episodeId && libraryItem && libraryItem.isPodcast ? libraryItem.media.getEpisode(sessionJson.episodeId) : null
if (!libraryItem || (libraryItem.isPodcast && !episode)) { if (!libraryItem || (libraryItem.isPodcast && !episode)) {
@@ -130,6 +131,16 @@ class PlaybackSessionManager {
} }
} }
const library = await Database.libraryModel.findByPk(libraryItem.libraryId)
if (!library) {
Logger.error(`[PlaybackSessionManager] syncLocalSession: Library not found for session "${sessionJson.displayTitle}" (${sessionJson.id})`)
return {
id: sessionJson.id,
success: false,
error: 'Library not found'
}
}
sessionJson.userId = user.id sessionJson.userId = user.id
sessionJson.serverVersion = serverVersion sessionJson.serverVersion = serverVersion
@@ -199,7 +210,9 @@ class PlaybackSessionManager {
const updateResponse = await user.createUpdateMediaProgressFromPayload({ const updateResponse = await user.createUpdateMediaProgressFromPayload({
libraryItemId: libraryItem.id, libraryItemId: libraryItem.id,
episodeId: session.episodeId, episodeId: session.episodeId,
...session.mediaProgressObject ...session.mediaProgressObject,
markAsFinishedPercentComplete: library.librarySettings.markAsFinishedPercentComplete,
markAsFinishedTimeRemaining: library.librarySettings.markAsFinishedTimeRemaining
}) })
result.progressSynced = !!updateResponse.mediaProgress result.progressSynced = !!updateResponse.mediaProgress
if (result.progressSynced) { if (result.progressSynced) {
@@ -211,7 +224,9 @@ class PlaybackSessionManager {
const updateResponse = await user.createUpdateMediaProgressFromPayload({ const updateResponse = await user.createUpdateMediaProgressFromPayload({
libraryItemId: libraryItem.id, libraryItemId: libraryItem.id,
episodeId: session.episodeId, episodeId: session.episodeId,
...session.mediaProgressObject ...session.mediaProgressObject,
markAsFinishedPercentComplete: library.librarySettings.markAsFinishedPercentComplete,
markAsFinishedTimeRemaining: library.librarySettings.markAsFinishedTimeRemaining
}) })
result.progressSynced = !!updateResponse.mediaProgress result.progressSynced = !!updateResponse.mediaProgress
if (result.progressSynced) { if (result.progressSynced) {
@@ -330,12 +345,19 @@ class PlaybackSessionManager {
* @returns * @returns
*/ */
async syncSession(user, session, syncData) { async syncSession(user, session, syncData) {
// TODO: Combine libraryItem query with library query
const libraryItem = await Database.libraryItemModel.getOldById(session.libraryItemId) const libraryItem = await Database.libraryItemModel.getOldById(session.libraryItemId)
if (!libraryItem) { if (!libraryItem) {
Logger.error(`[PlaybackSessionManager] syncSession Library Item not found "${session.libraryItemId}"`) Logger.error(`[PlaybackSessionManager] syncSession Library Item not found "${session.libraryItemId}"`)
return null return null
} }
const library = await Database.libraryModel.findByPk(libraryItem.libraryId)
if (!library) {
Logger.error(`[PlaybackSessionManager] syncSession Library not found "${libraryItem.libraryId}"`)
return null
}
session.currentTime = syncData.currentTime session.currentTime = syncData.currentTime
session.addListeningTime(syncData.timeListened) session.addListeningTime(syncData.timeListened)
Logger.debug(`[PlaybackSessionManager] syncSession "${session.id}" (Device: ${session.deviceDescription}) | Total Time Listened: ${session.timeListening}`) Logger.debug(`[PlaybackSessionManager] syncSession "${session.id}" (Device: ${session.deviceDescription}) | Total Time Listened: ${session.timeListening}`)
@@ -343,9 +365,12 @@ class PlaybackSessionManager {
const updateResponse = await user.createUpdateMediaProgressFromPayload({ const updateResponse = await user.createUpdateMediaProgressFromPayload({
libraryItemId: libraryItem.id, libraryItemId: libraryItem.id,
episodeId: session.episodeId, episodeId: session.episodeId,
duration: syncData.duration, // duration no longer required (v2.15.1) but used if available
duration: syncData.duration || session.duration || 0,
currentTime: syncData.currentTime, currentTime: syncData.currentTime,
progress: session.progress progress: session.progress,
markAsFinishedTimeRemaining: library.librarySettings.markAsFinishedTimeRemaining,
markAsFinishedPercentComplete: library.librarySettings.markAsFinishedPercentComplete
}) })
if (updateResponse.mediaProgress) { if (updateResponse.mediaProgress) {
SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', { SocketAuthority.clientEmitter(user.id, 'user_item_progress_updated', {
+5 -3
View File
@@ -2,6 +2,8 @@
Please add a record of every database migration that you create to this file. This will help us keep track of changes to the database schema over time. Please add a record of every database migration that you create to this file. This will help us keep track of changes to the database schema over time.
| Server Version | Migration Script Name | Description | | Server Version | Migration Script Name | Description |
| -------------- | ---------------------------- | ------------------------------------------------- | | -------------- | ---------------------------- | ------------------------------------------------------------------------------------ |
| v2.15.0 | v2.15.0-series-column-unique | Series must have unique names in the same library | | v2.15.0 | v2.15.0-series-column-unique | Series must have unique names in the same library |
| v2.15.1 | v2.15.1-reindex-nocase | Fix potential db corruption issues due to bad sqlite extension introduced in v2.12.0 |
| v2.15.2 | v2.15.2-index-creation | Creates author, series, and podcast episode indexes |
@@ -18,6 +18,10 @@ async function up({ context: { queryInterface, logger } }) {
// Upwards migration script // Upwards migration script
logger.info('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique ') logger.info('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique ')
// Run reindex nocase to fix potential corruption issues due to the bad sqlite extension introduced in v2.12.0
logger.info('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues')
await queryInterface.sequelize.query('REINDEX NOCASE;')
// Check if the unique index already exists // Check if the unique index already exists
const seriesIndexes = await queryInterface.showIndex('Series') const seriesIndexes = await queryInterface.showIndex('Series')
if (seriesIndexes.some((index) => index.name === 'unique_series_name_per_library')) { if (seriesIndexes.some((index) => index.name === 'unique_series_name_per_library')) {
@@ -0,0 +1,43 @@
/**
* @typedef MigrationContext
* @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object.
* @property {import('../Logger')} logger - a Logger object.
*
* @typedef MigrationOptions
* @property {MigrationContext} context - an object containing the migration context.
*/
/**
* This upward migration script fixes old database corruptions due to the a bad sqlite extension introduced in v2.12.0.
*
* @param {MigrationOptions} options - an object containing the migration context.
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
*/
async function up({ context: { queryInterface, logger } }) {
// Upwards migration script
logger.info('[2.15.1 migration] UPGRADE BEGIN: 2.15.1-reindex-nocase ')
// Run reindex nocase to fix potential corruption issues due to the bad sqlite extension introduced in v2.12.0
logger.info('[2.15.1 migration] Reindexing NOCASE indices to fix potential hidden corruption issues')
await queryInterface.sequelize.query('REINDEX NOCASE;')
logger.info('[2.15.1 migration] UPGRADE END: 2.15.1-reindex-nocase ')
}
/**
* This downward migration script is a no-op.
*
* @param {MigrationOptions} options - an object containing the migration context.
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
*/
async function down({ context: { queryInterface, logger } }) {
// Downward migration script
logger.info('[2.15.1 migration] DOWNGRADE BEGIN: 2.15.1-reindex-nocase ')
// This migration is a no-op
logger.info('[2.15.1 migration] No action required for downgrade')
logger.info('[2.15.1 migration] DOWNGRADE END: 2.15.1-reindex-nocase ')
}
module.exports = { up, down }
@@ -0,0 +1,93 @@
/**
* @typedef MigrationContext
* @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object.
* @property {import('../Logger')} logger - a Logger object.
*
* @typedef MigrationOptions
* @property {MigrationContext} context - an object containing the migration context.
*/
/**
* This upward migration script adds indexes to speed up queries on the `BookAuthor`, `BookSeries`, and `podcastEpisodes` tables.
*
* @param {MigrationOptions} options - an object containing the migration context.
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
*/
async function up({ context: { queryInterface, logger } }) {
// Upwards migration script
logger.info('[2.15.2 migration] UPGRADE BEGIN: 2.15.2-index-creation')
// Create index for bookAuthors
logger.info('[2.15.2 migration] Creating index for bookAuthors')
const bookAuthorsIndexes = await queryInterface.showIndex('bookAuthors')
if (!bookAuthorsIndexes.some((index) => index.name === 'bookAuthor_authorId')) {
await queryInterface.addIndex('bookAuthors', ['authorId'], {
name: 'bookAuthor_authorId'
})
} else {
logger.info('[2.15.2 migration] Index bookAuthor_authorId already exists')
}
// Create index for bookSeries
logger.info('[2.15.2 migration] Creating index for bookSeries')
const bookSeriesIndexes = await queryInterface.showIndex('bookSeries')
if (!bookSeriesIndexes.some((index) => index.name === 'bookSeries_seriesId')) {
await queryInterface.addIndex('bookSeries', ['seriesId'], {
name: 'bookSeries_seriesId'
})
} else {
logger.info('[2.15.2 migration] Index bookSeries_seriesId already exists')
}
// Delete existing podcastEpisode index
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
await queryInterface.removeIndex('podcastEpisodes', 'podcast_episodes_created_at')
// Create index for podcastEpisode and createdAt
logger.info('[2.15.2 migration] Creating index for podcastEpisode and createdAt')
const podcastEpisodesIndexes = await queryInterface.showIndex('podcastEpisodes')
if (!podcastEpisodesIndexes.some((index) => index.name === 'podcastEpisode_createdAt_podcastId')) {
await queryInterface.addIndex('podcastEpisodes', ['createdAt', 'podcastId'], {
name: 'podcastEpisode_createdAt_podcastId'
})
} else {
logger.info('[2.15.2 migration] Index podcastEpisode_createdAt_podcastId already exists')
}
// Completed migration
logger.info('[2.15.2 migration] UPGRADE END: 2.15.2-index-creation')
}
/**
* This downward migration script removes the newly created indexes and re-adds the old index on the `podcastEpisodes` table.
*
* @param {MigrationOptions} options - an object containing the migration context.
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
*/
async function down({ context: { queryInterface, logger } }) {
// Downward migration script
logger.info('[2.15.2 migration] DOWNGRADE BEGIN: 2.15.2-index-creation')
// Remove index for bookAuthors
logger.info('[2.15.2 migration] Removing index for bookAuthors')
await queryInterface.removeIndex('bookAuthors', 'bookAuthor_authorId')
// Remove index for bookSeries
logger.info('[2.15.2 migration] Removing index for bookSeries')
await queryInterface.removeIndex('bookSeries', 'bookSeries_seriesId')
// Delete existing podcastEpisode index
logger.info('[2.15.2 migration] Deleting existing podcastEpisode index')
await queryInterface.removeIndex('podcastEpisodes', 'podcastEpisode_createdAt_podcastId')
// Create index for podcastEpisode and createdAt
logger.info('[2.15.2 migration] Creating original index for podcastEpisode createdAt')
await queryInterface.addIndex('podcastEpisodes', ['createdAt'], {
name: 'podcast_episodes_created_at'
})
// Finished migration
logger.info('[2.15.2 migration] DOWNGRADE END: 2.15.2-index-creation')
}
module.exports = { up, down }
+7 -1
View File
@@ -54,7 +54,13 @@ class BookAuthor extends Model {
sequelize, sequelize,
modelName: 'bookAuthor', modelName: 'bookAuthor',
timestamps: true, timestamps: true,
updatedAt: false updatedAt: false,
indexes: [
{
name: 'bookAuthor_authorId',
fields: ['authorId']
}
]
} }
) )
+7 -1
View File
@@ -43,7 +43,13 @@ class BookSeries extends Model {
sequelize, sequelize,
modelName: 'bookSeries', modelName: 'bookSeries',
timestamps: true, timestamps: true,
updatedAt: false updatedAt: false,
indexes: [
{
name: 'bookSeries_seriesId',
fields: ['seriesId']
}
]
} }
) )
+15 -2
View File
@@ -12,6 +12,8 @@ const Logger = require('../Logger')
* @property {boolean} hideSingleBookSeries Do not show series that only have 1 book * @property {boolean} hideSingleBookSeries Do not show series that only have 1 book
* @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read * @property {boolean} onlyShowLaterBooksInContinueSeries Skip showing books that are earlier than the max sequence read
* @property {string[]} metadataPrecedence * @property {string[]} metadataPrecedence
* @property {number} markAsFinishedTimeRemaining Time remaining in seconds to mark as finished. (defaults to 10s)
* @property {number} markAsFinishedPercentComplete Percent complete to mark as finished (0-100). If this is set it will be used over markAsFinishedTimeRemaining.
*/ */
class Library extends Model { class Library extends Model {
@@ -57,7 +59,9 @@ class Library extends Model {
coverAspectRatio: 1, // Square coverAspectRatio: 1, // Square
disableWatcher: false, disableWatcher: false,
autoScanCronExpression: null, autoScanCronExpression: null,
podcastSearchRegion: 'us' podcastSearchRegion: 'us',
markAsFinishedPercentComplete: null,
markAsFinishedTimeRemaining: 10
} }
} else { } else {
return { return {
@@ -70,7 +74,9 @@ class Library extends Model {
epubsAllowScriptedContent: false, epubsAllowScriptedContent: false,
hideSingleBookSeries: false, hideSingleBookSeries: false,
onlyShowLaterBooksInContinueSeries: false, onlyShowLaterBooksInContinueSeries: false,
metadataPrecedence: this.defaultMetadataPrecedence metadataPrecedence: this.defaultMetadataPrecedence,
markAsFinishedPercentComplete: null,
markAsFinishedTimeRemaining: 10
} }
} }
} }
@@ -196,6 +202,13 @@ class Library extends Model {
return this.extraData?.lastScanMetadataPrecedence || [] return this.extraData?.lastScanMetadataPrecedence || []
} }
/**
* @returns {LibrarySettingsObject}
*/
get librarySettings() {
return this.settings || Library.getDefaultLibrarySettingsForMediaType(this.mediaType)
}
/** /**
* TODO: Update to use new model * TODO: Update to use new model
*/ */
+31 -4
View File
@@ -1,4 +1,6 @@
const { DataTypes, Model } = require('sequelize') const { DataTypes, Model } = require('sequelize')
const Logger = require('../Logger')
const { isNullOrNaN } = require('../utils')
class MediaProgress extends Model { class MediaProgress extends Model {
constructor(values, options) { constructor(values, options) {
@@ -183,10 +185,16 @@ class MediaProgress extends Model {
} }
} }
get progress() {
// Value between 0 and 1
if (!this.duration) return 0
return Math.max(0, Math.min(this.currentTime / this.duration, 1))
}
/** /**
* Apply update to media progress * Apply update to media progress
* *
* @param {Object} progress * @param {import('./User').ProgressUpdatePayload} progressPayload
* @returns {Promise<MediaProgress>} * @returns {Promise<MediaProgress>}
*/ */
applyProgressUpdate(progressPayload) { applyProgressUpdate(progressPayload) {
@@ -219,13 +227,32 @@ class MediaProgress extends Model {
} }
const timeRemaining = this.duration - this.currentTime const timeRemaining = this.duration - this.currentTime
// Set to finished if time remaining is less than 5 seconds
if (!this.isFinished && this.duration && timeRemaining < 5) { // Check if progress is far enough to mark as finished
// - If markAsFinishedPercentComplete is provided, use that otherwise use markAsFinishedTimeRemaining (default 10 seconds)
let shouldMarkAsFinished = false
if (this.duration) {
if (!isNullOrNaN(progressPayload.markAsFinishedPercentComplete) && progressPayload.markAsFinishedPercentComplete > 0) {
const markAsFinishedPercentComplete = Number(progressPayload.markAsFinishedPercentComplete) / 100
shouldMarkAsFinished = markAsFinishedPercentComplete < this.progress
if (shouldMarkAsFinished) {
Logger.debug(`[MediaProgress] Marking media progress as finished because progress (${this.progress}) is greater than ${markAsFinishedPercentComplete}`)
}
} else {
const markAsFinishedTimeRemaining = isNullOrNaN(progressPayload.markAsFinishedTimeRemaining) ? 10 : Number(progressPayload.markAsFinishedTimeRemaining)
shouldMarkAsFinished = timeRemaining < markAsFinishedTimeRemaining
if (shouldMarkAsFinished) {
Logger.debug(`[MediaProgress] Marking media progress as finished because time remaining (${timeRemaining}) is less than ${markAsFinishedTimeRemaining} seconds`)
}
}
}
if (!this.isFinished && shouldMarkAsFinished) {
this.isFinished = true this.isFinished = true
this.finishedAt = this.finishedAt || Date.now() this.finishedAt = this.finishedAt || Date.now()
this.extraData.progress = 1 this.extraData.progress = 1
this.changed('extraData', true) this.changed('extraData', true)
} else if (this.isFinished && this.changed('currentTime') && this.currentTime < this.duration) { } else if (this.isFinished && this.changed('currentTime') && !shouldMarkAsFinished) {
this.isFinished = false this.isFinished = false
this.finishedAt = null this.finishedAt = null
} }
+2 -1
View File
@@ -157,7 +157,8 @@ class PodcastEpisode extends Model {
modelName: 'podcastEpisode', modelName: 'podcastEpisode',
indexes: [ indexes: [
{ {
fields: ['createdAt'] name: 'podcastEpisode_createdAt_podcastId',
fields: ['createdAt', 'podcastId']
} }
] ]
} }
+19 -13
View File
@@ -14,6 +14,23 @@ const { DataTypes, Model } = sequelize
* @property {number} createdAt * @property {number} createdAt
*/ */
/**
* @typedef ProgressUpdatePayload
* @property {string} libraryItemId
* @property {string} [episodeId]
* @property {number} [duration]
* @property {number} [progress]
* @property {number} [currentTime]
* @property {boolean} [isFinished]
* @property {boolean} [hideFromContinueListening]
* @property {string} [ebookLocation]
* @property {number} [ebookProgress]
* @property {string} [finishedAt]
* @property {number} [lastUpdate]
* @property {number} [markAsFinishedTimeRemaining]
* @property {number} [markAsFinishedPercentComplete]
*/
class User extends Model { class User extends Model {
constructor(values, options) { constructor(values, options) {
super(values, options) super(values, options)
@@ -65,6 +82,7 @@ class User extends Model {
canAccessExplicitContent: 'accessExplicitContent', canAccessExplicitContent: 'accessExplicitContent',
canAccessAllLibraries: 'accessAllLibraries', canAccessAllLibraries: 'accessAllLibraries',
canAccessAllTags: 'accessAllTags', canAccessAllTags: 'accessAllTags',
canCreateEReader: 'createEreader',
tagsAreDenylist: 'selectedTagsNotAccessible', tagsAreDenylist: 'selectedTagsNotAccessible',
// Direct mapping for array-based permissions // Direct mapping for array-based permissions
allowedLibraries: 'librariesAccessible', allowedLibraries: 'librariesAccessible',
@@ -105,6 +123,7 @@ class User extends Model {
update: type === 'root' || type === 'admin', update: type === 'root' || type === 'admin',
delete: type === 'root', delete: type === 'root',
upload: type === 'root' || type === 'admin', upload: type === 'root' || type === 'admin',
createEreader: type === 'root' || type === 'admin',
accessAllLibraries: true, accessAllLibraries: true,
accessAllTags: true, accessAllTags: true,
accessExplicitContent: type === 'root' || type === 'admin', accessExplicitContent: type === 'root' || type === 'admin',
@@ -515,19 +534,6 @@ class User extends Model {
/** /**
* TODO: Uses old model and should account for the different between ebook/audiobook progress * TODO: Uses old model and should account for the different between ebook/audiobook progress
* *
* @typedef ProgressUpdatePayload
* @property {string} libraryItemId
* @property {string} [episodeId]
* @property {number} [duration]
* @property {number} [progress]
* @property {number} [currentTime]
* @property {boolean} [isFinished]
* @property {boolean} [hideFromContinueListening]
* @property {string} [ebookLocation]
* @property {number} [ebookProgress]
* @property {string} [finishedAt]
* @property {number} [lastUpdate]
*
* @param {ProgressUpdatePayload} progressPayload * @param {ProgressUpdatePayload} progressPayload
* @returns {Promise<{ mediaProgress: import('./MediaProgress'), error: [string], statusCode: [number] }>} * @returns {Promise<{ mediaProgress: import('./MediaProgress'), error: [string], statusCode: [number] }>}
*/ */
+4
View File
@@ -9,6 +9,7 @@ class AudioMetaTags {
this.tagTitleSort = null this.tagTitleSort = null
this.tagSeries = null this.tagSeries = null
this.tagSeriesPart = null this.tagSeriesPart = null
this.tagGrouping = null
this.tagTrack = null this.tagTrack = null
this.tagDisc = null this.tagDisc = null
this.tagSubtitle = null this.tagSubtitle = null
@@ -116,6 +117,7 @@ class AudioMetaTags {
this.tagTitleSort = metadata.tagTitleSort || null this.tagTitleSort = metadata.tagTitleSort || null
this.tagSeries = metadata.tagSeries || null this.tagSeries = metadata.tagSeries || null
this.tagSeriesPart = metadata.tagSeriesPart || null this.tagSeriesPart = metadata.tagSeriesPart || null
this.tagGrouping = metadata.tagGrouping || null
this.tagTrack = metadata.tagTrack || null this.tagTrack = metadata.tagTrack || null
this.tagDisc = metadata.tagDisc || null this.tagDisc = metadata.tagDisc || null
this.tagSubtitle = metadata.tagSubtitle || null this.tagSubtitle = metadata.tagSubtitle || null
@@ -156,6 +158,7 @@ class AudioMetaTags {
this.tagTitleSort = payload.file_tag_titlesort || null this.tagTitleSort = payload.file_tag_titlesort || null
this.tagSeries = payload.file_tag_series || null this.tagSeries = payload.file_tag_series || null
this.tagSeriesPart = payload.file_tag_seriespart || null this.tagSeriesPart = payload.file_tag_seriespart || null
this.tagGrouping = payload.file_tag_grouping || null
this.tagTrack = payload.file_tag_track || null this.tagTrack = payload.file_tag_track || null
this.tagDisc = payload.file_tag_disc || null this.tagDisc = payload.file_tag_disc || null
this.tagSubtitle = payload.file_tag_subtitle || null this.tagSubtitle = payload.file_tag_subtitle || null
@@ -196,6 +199,7 @@ class AudioMetaTags {
tagTitleSort: payload.file_tag_titlesort || null, tagTitleSort: payload.file_tag_titlesort || null,
tagSeries: payload.file_tag_series || null, tagSeries: payload.file_tag_series || null,
tagSeriesPart: payload.file_tag_seriespart || null, tagSeriesPart: payload.file_tag_seriespart || null,
tagGrouping: payload.file_tag_grouping || null,
tagTrack: payload.file_tag_track || null, tagTrack: payload.file_tag_track || null,
tagDisc: payload.file_tag_disc || null, tagDisc: payload.file_tag_disc || null,
tagSubtitle: payload.file_tag_subtitle || null, tagSubtitle: payload.file_tag_subtitle || null,
+1
View File
@@ -190,6 +190,7 @@ class ApiRouter {
this.router.get('/me/series/:id/remove-from-continue-listening', MeController.removeSeriesFromContinueListening.bind(this)) this.router.get('/me/series/:id/remove-from-continue-listening', MeController.removeSeriesFromContinueListening.bind(this))
this.router.get('/me/series/:id/readd-to-continue-listening', MeController.readdSeriesFromContinueListening.bind(this)) this.router.get('/me/series/:id/readd-to-continue-listening', MeController.readdSeriesFromContinueListening.bind(this))
this.router.get('/me/stats/year/:year', MeController.getStatsForYear.bind(this)) this.router.get('/me/stats/year/:year', MeController.getStatsForYear.bind(this))
this.router.post('/me/ereader-devices', MeController.updateUserEReaderDevices.bind(this))
// //
// Backup Routes // Backup Routes
+25 -5
View File
@@ -4,6 +4,7 @@ const prober = require('../utils/prober')
const { LogLevel } = require('../utils/constants') const { LogLevel } = require('../utils/constants')
const { parseOverdriveMediaMarkersAsChapters } = require('../utils/parsers/parseOverdriveMediaMarkers') const { parseOverdriveMediaMarkersAsChapters } = require('../utils/parsers/parseOverdriveMediaMarkers')
const parseNameString = require('../utils/parsers/parseNameString') const parseNameString = require('../utils/parsers/parseNameString')
const parseSeriesString = require('../utils/parsers/parseSeriesString')
const LibraryItem = require('../models/LibraryItem') const LibraryItem = require('../models/LibraryItem')
const AudioFile = require('../objects/files/AudioFile') const AudioFile = require('../objects/files/AudioFile')
@@ -256,6 +257,7 @@ class AudioFileScanner {
}, },
{ {
tag: 'tagSeries', tag: 'tagSeries',
altTag: 'tagGrouping',
key: 'series' key: 'series'
}, },
{ {
@@ -276,8 +278,10 @@ class AudioFileScanner {
const audioFileMetaTags = firstScannedFile.metaTags const audioFileMetaTags = firstScannedFile.metaTags
MetadataMapArray.forEach((mapping) => { MetadataMapArray.forEach((mapping) => {
let value = audioFileMetaTags[mapping.tag] let value = audioFileMetaTags[mapping.tag]
let isAltTag = false
if (!value && mapping.altTag) { if (!value && mapping.altTag) {
value = audioFileMetaTags[mapping.altTag] value = audioFileMetaTags[mapping.altTag]
isAltTag = true
} }
if (value && typeof value === 'string') { if (value && typeof value === 'string') {
@@ -290,12 +294,28 @@ class AudioFileScanner {
} else if (mapping.key === 'genres') { } else if (mapping.key === 'genres') {
bookMetadata.genres = this.parseGenresString(value) bookMetadata.genres = this.parseGenresString(value)
} else if (mapping.key === 'series') { } else if (mapping.key === 'series') {
bookMetadata.series = [ // If series was embedded in the grouping tag, then parse it with semicolon separator and sequence in the same string
{ // e.g. "Test Series; Series Name #1; Other Series #2"
name: value, if (isAltTag) {
sequence: audioFileMetaTags.tagSeriesPart || null const series = value
.split(';')
.map((seriesWithPart) => {
seriesWithPart = seriesWithPart.trim()
return parseSeriesString.parse(seriesWithPart)
})
.filter(Boolean)
if (series.length) {
bookMetadata.series = series
} }
] } else {
// Original embed used "series" and "series-part" tags
bookMetadata.series = [
{
name: value,
sequence: audioFileMetaTags.tagSeriesPart || null
}
]
}
} else { } else {
bookMetadata[mapping.key] = value bookMetadata[mapping.key] = value
} }
+2 -3
View File
@@ -55,7 +55,7 @@ async function extractCoverArt(filepath, outputpath) {
return new Promise((resolve) => { return new Promise((resolve) => {
/** @type {import('../libs/fluentFfmpeg/index').FfmpegCommand} */ /** @type {import('../libs/fluentFfmpeg/index').FfmpegCommand} */
var ffmpeg = Ffmpeg(filepath) var ffmpeg = Ffmpeg(filepath)
ffmpeg.addOption(['-map 0:v', '-frames:v 1']) ffmpeg.addOption(['-map 0:v:0', '-frames:v 1'])
ffmpeg.output(outputpath) ffmpeg.output(outputpath)
ffmpeg.on('start', (cmd) => { ffmpeg.on('start', (cmd) => {
@@ -380,9 +380,8 @@ function getFFMetadataObject(libraryItem, audioFilesLength) {
copyright: metadata.publisher, copyright: metadata.publisher,
publisher: metadata.publisher, // mp3 only publisher: metadata.publisher, // mp3 only
TRACKTOTAL: `${audioFilesLength}`, // mp3 only TRACKTOTAL: `${audioFilesLength}`, // mp3 only
grouping: metadata.series?.map((s) => s.name + (s.sequence ? ` #${s.sequence}` : '')).join(', ') grouping: metadata.series?.map((s) => s.name + (s.sequence ? ` #${s.sequence}` : '')).join('; ')
} }
Object.keys(ffmetadata).forEach((key) => { Object.keys(ffmetadata).forEach((key) => {
if (!ffmetadata[key]) { if (!ffmetadata[key]) {
delete ffmetadata[key] delete ffmetadata[key]
+7 -20
View File
@@ -1,4 +1,5 @@
const Logger = require('../../Logger') const Logger = require('../../Logger')
const parseSeriesString = require('../parsers/parseSeriesString')
function parseJsonMetadataText(text) { function parseJsonMetadataText(text) {
try { try {
@@ -19,39 +20,25 @@ function parseJsonMetadataText(text) {
delete abmetadataData.metadata delete abmetadataData.metadata
if (abmetadataData.series?.length) { if (abmetadataData.series?.length) {
abmetadataData.series = [...new Set(abmetadataData.series.map(t => t?.trim()).filter(t => t))] abmetadataData.series = [...new Set(abmetadataData.series.map((t) => t?.trim()).filter((t) => t))]
abmetadataData.series = abmetadataData.series.map(series => { abmetadataData.series = abmetadataData.series.map((series) => parseSeriesString.parse(series))
let sequence = null
let name = series
// Series sequence match any characters after " #" other than whitespace and another #
// e.g. "Name #1a" is valid. "Name #1#a" or "Name #1 a" is not valid.
const matchResults = series.match(/ #([^#\s]+)$/) // Pull out sequence #
if (matchResults && matchResults.length && matchResults.length > 1) {
sequence = matchResults[1] // Group 1
name = series.replace(matchResults[0], '')
}
return {
name,
sequence
}
})
} }
// clean tags & remove dupes // clean tags & remove dupes
if (abmetadataData.tags?.length) { if (abmetadataData.tags?.length) {
abmetadataData.tags = [...new Set(abmetadataData.tags.map(t => t?.trim()).filter(t => t))] abmetadataData.tags = [...new Set(abmetadataData.tags.map((t) => t?.trim()).filter((t) => t))]
} }
if (abmetadataData.chapters?.length) { if (abmetadataData.chapters?.length) {
abmetadataData.chapters = cleanChaptersArray(abmetadataData.chapters, abmetadataData.title) abmetadataData.chapters = cleanChaptersArray(abmetadataData.chapters, abmetadataData.title)
} }
// clean remove dupes // clean remove dupes
if (abmetadataData.authors?.length) { if (abmetadataData.authors?.length) {
abmetadataData.authors = [...new Set(abmetadataData.authors.map(t => t?.trim()).filter(t => t))] abmetadataData.authors = [...new Set(abmetadataData.authors.map((t) => t?.trim()).filter((t) => t))]
} }
if (abmetadataData.narrators?.length) { if (abmetadataData.narrators?.length) {
abmetadataData.narrators = [...new Set(abmetadataData.narrators.map(t => t?.trim()).filter(t => t))] abmetadataData.narrators = [...new Set(abmetadataData.narrators.map((t) => t?.trim()).filter((t) => t))]
} }
if (abmetadataData.genres?.length) { if (abmetadataData.genres?.length) {
abmetadataData.genres = [...new Set(abmetadataData.genres.map(t => t?.trim()).filter(t => t))] abmetadataData.genres = [...new Set(abmetadataData.genres.map((t) => t?.trim()).filter((t) => t))]
} }
return abmetadataData return abmetadataData
} catch (error) { } catch (error) {
+27
View File
@@ -0,0 +1,27 @@
/**
* Parse a series string into a name and sequence
*
* @example
* Name #1a => { name: 'Name', sequence: '1a' }
* Name #1 => { name: 'Name', sequence: '1' }
*
* @param {string} seriesString
* @returns {{name: string, sequence: string}|null}
*/
module.exports.parse = (seriesString) => {
if (!seriesString || typeof seriesString !== 'string') return null
let sequence = null
let name = seriesString
// Series sequence match any characters after " #" other than whitespace and another #
// e.g. "Name #1a" is valid. "Name #1#a" or "Name #1 a" is not valid.
const matchResults = seriesString.match(/ #([^#\s]+)$/) // Pull out sequence #
if (matchResults && matchResults.length && matchResults.length > 1) {
sequence = matchResults[1] // Group 1
name = seriesString.replace(matchResults[0], '')
}
return {
name,
sequence
}
}
+1
View File
@@ -189,6 +189,7 @@ function parseTags(format, verbose) {
file_tag_genre: tryGrabTags(format, 'genre', 'tcon', 'tco'), file_tag_genre: tryGrabTags(format, 'genre', 'tcon', 'tco'),
file_tag_series: tryGrabTags(format, 'series', 'show', 'mvnm'), file_tag_series: tryGrabTags(format, 'series', 'show', 'mvnm'),
file_tag_seriespart: tryGrabTags(format, 'series-part', 'episode_id', 'mvin', 'part'), file_tag_seriespart: tryGrabTags(format, 'series-part', 'episode_id', 'mvin', 'part'),
file_tag_grouping: tryGrabTags(format, 'grouping'),
file_tag_isbn: tryGrabTags(format, 'isbn'), // custom file_tag_isbn: tryGrabTags(format, 'isbn'), // custom
file_tag_language: tryGrabTags(format, 'language', 'lang'), file_tag_language: tryGrabTags(format, 'language', 'lang'),
file_tag_asin: tryGrabTags(format, 'asin', 'audible_asin'), // custom file_tag_asin: tryGrabTags(format, 'asin', 'audible_asin'), // custom
+3 -3
View File
@@ -508,9 +508,9 @@ module.exports = {
} }
if (book.publisher) data.publishers.add(book.publisher) if (book.publisher) data.publishers.add(book.publisher)
// Check if published year exists and is valid // Check if published year exists and is valid
if (book.publishedYear && !isNaN(book.publishedYear) && book.publishedYear > 0 && book.publishedYear < 3000 && book.publishedYear.toString().length === 4) { if (book.publishedYear && !isNaN(book.publishedYear) && book.publishedYear > 0 && book.publishedYear < 3000) {
const decade = Math.floor(book.publishedYear / 10) * 10 const decade = (Math.floor(book.publishedYear / 10) * 10).toString()
data.publishedDecades.add(decade.toString()) data.publishedDecades.add(decade)
} }
if (book.language) data.languages.add(book.language) if (book.language) data.languages.add(book.language)
} }
@@ -229,10 +229,11 @@ module.exports = {
mediaWhere['$series.id$'] = null mediaWhere['$series.id$'] = null
} }
} else if (group === 'publishedDecades') { } else if (group === 'publishedDecades') {
const year = parseInt(value, 10) const startYear = parseInt(value)
mediaWhere['publishedYear'] = { const endYear = parseInt(value, 10) + 9
[Sequelize.Op.between]: year >= 1000 ? [year, year + 9] : [year * 10, (year + 1) * 10 - 1] mediaWhere = Sequelize.where(Sequelize.literal('CAST(`book`.`publishedYear` AS INTEGER)'), {
} [Sequelize.Op.between]: [startYear, endYear]
})
} }
return { mediaWhere, replacements } return { mediaWhere, replacements }
@@ -504,7 +505,6 @@ module.exports = {
} }
let { mediaWhere, replacements } = this.getMediaGroupQuery(filterGroup, filterValue) let { mediaWhere, replacements } = this.getMediaGroupQuery(filterGroup, filterValue)
let bookWhere = Array.isArray(mediaWhere) ? mediaWhere : [mediaWhere] let bookWhere = Array.isArray(mediaWhere) ? mediaWhere : [mediaWhere]
// User permissions // User permissions
@@ -104,12 +104,13 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(5) expect(loggerInfoStub.callCount).to.equal(6)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// Validate rows in tables // Validate rows in tables
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(3) expect(series).to.have.length(3)
@@ -144,14 +145,15 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(7) expect(loggerInfoStub.callCount).to.equal(8)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 2 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 2 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 3" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 3" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// Validate rows // Validate rows
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(3) expect(series).to.have.length(3)
@@ -181,12 +183,13 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(5) expect(loggerInfoStub.callCount).to.equal(6)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// Validate rows // Validate rows
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(2) expect(series).to.have.length(2)
@@ -211,15 +214,16 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(8) expect(loggerInfoStub.callCount).to.equal(9)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(8).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// validate rows // validate rows
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(1) expect(series).to.have.length(1)
@@ -243,15 +247,16 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(8) expect(loggerInfoStub.callCount).to.equal(9)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(8).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// validate rows // validate rows
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(1) expect(series).to.have.length(1)
@@ -274,15 +279,16 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(8) expect(loggerInfoStub.callCount).to.equal(9)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 1 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplicating series "Series 1" in library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Deduplicating bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] Finished cleanup of bookId 4a38b6e5-0ae4-4de4-b119-4e33891bd63f in series "Series 1" of library 3a5a1c7c-a914-472e-88b0-b871ceae63e7'))).to.be.true
expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(8).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
// validate rows // validate rows
const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT }) const series = await queryInterface.sequelize.query('SELECT "id", "name", "libraryId" FROM Series', { type: queryInterface.sequelize.QueryTypes.SELECT })
expect(series).to.have.length(1) expect(series).to.have.length(1)
@@ -318,15 +324,16 @@ describe('migration-v2.15.0-series-column-unique', () => {
await up({ context: { queryInterface, logger: Logger } }) await up({ context: { queryInterface, logger: Logger } })
await down({ context: { queryInterface, logger: Logger } }) await down({ context: { queryInterface, logger: Logger } })
expect(loggerInfoStub.callCount).to.equal(8) expect(loggerInfoStub.callCount).to.equal(9)
expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(0).calledWith(sinon.match('[2.15.0 migration] UPGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true expect(loggerInfoStub.getCall(1).calledWith(sinon.match('[2.15.0 migration] Reindexing NOCASE indices to fix potential hidden corruption issues'))).to.be.true
expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true expect(loggerInfoStub.getCall(2).calledWith(sinon.match('[2.15.0 migration] Found 0 duplicate series'))).to.be.true
expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(3).calledWith(sinon.match('[2.15.0 migration] Deduplication complete'))).to.be.true
expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(4).calledWith(sinon.match('[2.15.0 migration] Added unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] DOWNGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(5).calledWith(sinon.match('[2.15.0 migration] UPGRADE END: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] Removed unique index on Series.name and Series.libraryId'))).to.be.true expect(loggerInfoStub.getCall(6).calledWith(sinon.match('[2.15.0 migration] DOWNGRADE BEGIN: 2.15.0-series-column-unique '))).to.be.true
expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] DOWNGRADE END: 2.15.0-series-column-unique '))).to.be.true expect(loggerInfoStub.getCall(7).calledWith(sinon.match('[2.15.0 migration] Removed unique index on Series.name and Series.libraryId'))).to.be.true
expect(loggerInfoStub.getCall(8).calledWith(sinon.match('[2.15.0 migration] DOWNGRADE END: 2.15.0-series-column-unique '))).to.be.true
// Ensure index does not exist // Ensure index does not exist
const indexes = await queryInterface.showIndex('Series') const indexes = await queryInterface.showIndex('Series')
expect(indexes).to.not.deep.include({ tableName: 'Series', unique: true, fields: ['name', 'libraryId'], name: 'unique_series_name_per_library' }) expect(indexes).to.not.deep.include({ tableName: 'Series', unique: true, fields: ['name', 'libraryId'], name: 'unique_series_name_per_library' })