Compare commits

...

249 Commits

Author SHA1 Message Date
advplyr
c377b57601 Version bump v2.24.0 2025-06-01 16:00:16 -05:00
advplyr
262d0b46e3 Merge pull request #4350 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-06-01 15:40:16 -05:00
Charlie
32fc4f6555 Translated using Weblate (French)
Currently translated at 99.9% (1104 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fr/
2025-06-01 15:57:47 +02:00
DR
81572adab6 Translated using Weblate (Hebrew)
Currently translated at 76.4% (845 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/he/
2025-06-01 00:37:34 +02:00
kuci-JK
1ad2e71fd5 Translated using Weblate (Czech)
Currently translated at 98.9% (1093 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2025-06-01 00:37:33 +02:00
FiendFEARing
db66b9eaeb Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-06-01 00:37:32 +02:00
Simple16
28c2e62e61 Translated using Weblate (Russian)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-06-01 00:37:32 +02:00
Tommaso Bellandi
96401c377c Translated using Weblate (Italian)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/it/
2025-06-01 00:37:31 +02:00
advplyr
9d45880b37 Merge pull request #4355 from advplyr/sanitize_html_description
Sanitize media item & episode description on update
2025-05-31 17:37:18 -05:00
advplyr
9052ceedd3 Sanitize media item & episode description on update 2025-05-31 17:01:58 -05:00
advplyr
4968864498 Fix safari specific issue with line clamp on description #4348 2025-05-30 17:33:15 -05:00
advplyr
f44c2d9e11 Merge pull request #4349 from advplyr/trix_prevent_attachments
Update rich text editor to prevent pasting in images from the browser
2025-05-29 17:37:31 -05:00
advplyr
0c8e334b1a Update rich text editor to prevent pasting in images from the browser 2025-05-29 17:27:29 -05:00
advplyr
abaa7b5ad0 Add arabic language option 2025-05-28 17:09:39 -05:00
advplyr
df01e493ec Merge pull request #4303 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-05-28 17:05:27 -05:00
Adolfo Jayme Barrientos
949c8ce230 Translated using Weblate (Catalan)
Currently translated at 96.2% (1064 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-27 22:57:04 +00:00
Grzegorz Orlowski
9eaa0c26cd Translated using Weblate (Polish)
Currently translated at 73.3% (810 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/pl/
2025-05-27 22:57:03 +00:00
Adolfo Jayme Barrientos
d71f091e3e Translated using Weblate (Spanish)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-27 22:57:02 +00:00
Biepa
2589121908 Translated using Weblate (German)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-05-27 22:57:02 +00:00
ABS translator
ff425212e7 Translated using Weblate (Arabic)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:57:01 +00:00
thehijacker
243baaf775 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2025-05-27 22:57:00 +00:00
Jan Schoenfeld
7275b1063b Translated using Weblate (German)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-05-27 22:57:00 +00:00
peter cerny
4fd97510b8 Translated using Weblate (Slovak)
Currently translated at 99.9% (1104 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-27 22:56:59 +00:00
Adolfo Jayme Barrientos
6e67b1d9dd Translated using Weblate (Catalan)
Currently translated at 96.0% (1061 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-27 22:56:59 +00:00
SunSpring
0fc6afec26 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-05-27 22:56:58 +00:00
Adolfo Jayme Barrientos
c950ac7d69 Translated using Weblate (Spanish)
Currently translated at 99.9% (1104 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-27 22:56:57 +00:00
Usama Khalil
8979e19e92 Translated using Weblate (Arabic)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:56:57 +00:00
Максим Горпиніч
6a51cb07e8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-05-27 22:56:56 +00:00
biuklija
846a8c3881 Translated using Weblate (Croatian)
Currently translated at 100.0% (1105 of 1105 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2025-05-27 22:56:55 +00:00
peter cerny
0cd698cc8d Translated using Weblate (Slovak)
Currently translated at 99.9% (1103 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-27 22:56:55 +00:00
Antoniy Chonkov
13d9462868 Translated using Weblate (Bulgarian)
Currently translated at 81.7% (903 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/bg/
2025-05-27 22:56:54 +00:00
peter cerny
d8e2ff8b0e Translated using Weblate (Slovak)
Currently translated at 99.5% (1099 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-27 22:56:53 +00:00
Usama Khalil
35c2a5c1a3 Translated using Weblate (Arabic)
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:56:53 +00:00
Antoniy Chonkov
19dc096d22 Translated using Weblate (Bulgarian)
Currently translated at 75.5% (834 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/bg/
2025-05-27 22:56:52 +00:00
Usama Khalil
535ebc10f0 Translated using Weblate (Arabic)
Currently translated at 98.5% (1088 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:56:51 +00:00
SunSpring
7486a0659b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-05-27 22:56:51 +00:00
Usama Khalil
273866fe92 Translated using Weblate (Arabic)
Currently translated at 36.5% (404 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:56:50 +00:00
Usama Khalil
6425d95deb Translated using Weblate (Arabic)
Currently translated at 27.4% (303 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-27 22:56:50 +00:00
Vito0912
68a39449a2 Translated using Weblate (German)
Currently translated at 99.6% (1100 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-05-27 22:56:49 +00:00
advplyr
8e08458ea2 Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2025-05-27 17:56:32 -05:00
advplyr
1119ddef8a Add RSS Feed Open filter for podcast libraries to match book libraries #4335 2025-05-27 17:56:27 -05:00
advplyr
3d0219a866 Merge pull request #4342 from advplyr/check_path_api_fix
Update pathexists file system API endpoint
2025-05-26 17:12:13 -05:00
advplyr
6ce1806359 Update pathexists file system API endpoint 2025-05-26 16:56:50 -05:00
advplyr
f05a513767 Fix m4b encoder bitrate preset selection #4337 2025-05-25 16:12:35 -05:00
advplyr
d03c338b48 Fix log for podcast rss feed with no guid #4325 2025-05-24 17:09:58 -05:00
advplyr
5e5a988f7a Merge pull request #4326 from advplyr/fix_mediaprogress_updatedat
Fix MediaProgress not using the lastUpdate time sent for local progress syncs
2025-05-22 17:43:31 -05:00
advplyr
6d1f0b27df Fix MediaProgress not using the lastUpdate time sent for local progress syncs 2025-05-22 17:30:38 -05:00
advplyr
d01a7cb756 Merge pull request #4318 from advplyr/increase_express_json_limit
Update max allowed json request size #4250
2025-05-20 18:04:02 -05:00
advplyr
cae874ef05 Update max allowed json request size #4250 2025-05-20 17:44:13 -05:00
advplyr
733afc3e29 Update edit series sequence to show error when sequence has spaces #4314 2025-05-19 17:37:11 -05:00
advplyr
0772730336 Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2025-05-16 16:42:05 -05:00
advplyr
8b02fe07c8 Version bump v2.23.0 2025-05-16 16:41:59 -05:00
advplyr
98f93a665c Merge pull request #4288 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-05-16 16:40:31 -05:00
Adolfo Jayme Barrientos
754566b221 Translated using Weblate (Catalan)
Currently translated at 95.5% (1055 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-16 23:20:02 +02:00
Adolfo Jayme Barrientos
f4f9adad35 Translated using Weblate (Spanish)
Currently translated at 99.8% (1102 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-16 23:20:02 +02:00
Adolfo Jayme Barrientos
16f7f1166e Translated using Weblate (Catalan)
Currently translated at 95.0% (1049 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-16 23:20:01 +02:00
Usama Khalil
f527b0f4d5 Translated using Weblate (Arabic)
Currently translated at 24.2% (268 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-16 23:20:00 +02:00
thehijacker
4f41df53c9 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2025-05-16 23:20:00 +02:00
cebo29
8a15f775a2 Translated using Weblate (German)
Currently translated at 99.4% (1098 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-05-16 23:19:59 +02:00
peter cerny
5e83bcd283 Translated using Weblate (Slovak)
Currently translated at 99.6% (1100 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-16 23:19:59 +02:00
Максим Горпиніч
2fd5dfcb66 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-05-16 23:19:58 +02:00
Ivan Smoliakov
872ce4fa38 Translated using Weblate (Russian)
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-05-16 23:19:57 +02:00
J. Lavoie
ba792d91e5 Translated using Weblate (Italian)
Currently translated at 99.9% (1103 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/it/
2025-05-16 23:19:57 +02:00
biuklija
4997c716db Translated using Weblate (Croatian)
Currently translated at 100.0% (1104 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2025-05-16 23:19:56 +02:00
J. Lavoie
fd72d05280 Translated using Weblate (French)
Currently translated at 99.2% (1096 of 1104 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fr/
2025-05-16 23:19:56 +02:00
advplyr
241b56ad45 Merge pull request #4166 from balki/patch-1
Support listening on unix socket
2025-05-16 16:19:47 -05:00
advplyr
635c384952 Handle undefined Host and make chmod async 2025-05-16 16:14:13 -05:00
advplyr
ef930fd1b4 Merge pull request #4299 from advplyr/fix_dockerfile_nunicode
Fix Dockerfile to include nunicode in the final stage
2025-05-16 16:08:13 -05:00
advplyr
49997a1336 Fix Dockerfile to include nunicode in the final stage 2025-05-16 15:23:19 -05:00
advplyr
8d0434143c Merge pull request #4293 from advplyr/search_episodes
Add support for searching podcast episode titles #3301
2025-05-15 17:51:51 -05:00
advplyr
8e0319994e Update total results in global search component 2025-05-15 17:22:20 -05:00
advplyr
0ed6045d1e Add support for searching podcast episode titles #3301 2025-05-15 17:16:15 -05:00
advplyr
25c7e95a64 Version bump v2.22.0 2025-05-14 17:04:01 -05:00
advplyr
1781c4bbcb Merge pull request #4285 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-05-14 17:00:23 -05:00
Michal
c4ce72d44e Translated using Weblate (Slovak)
Currently translated at 99.7% (1100 of 1103 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-13 22:01:14 +00:00
Jaakko Rantamäki
78813c4b28 Translated using Weblate (Finnish)
Currently translated at 99.6% (1099 of 1103 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fi/
2025-05-13 22:01:13 +00:00
peter cerny
990baa2dc6 Translated using Weblate (Slovak)
Currently translated at 99.7% (1100 of 1103 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-13 22:01:12 +00:00
Максим Горпиніч
c85f4467d2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1103 of 1103 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-05-13 22:01:12 +00:00
burghy86
59f7609054 Translated using Weblate (Italian)
Currently translated at 100.0% (1103 of 1103 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/it/
2025-05-13 22:01:11 +00:00
advplyr
2ef827e3fa Add restart server message on authentication page when oidc is enabled #4064 2025-05-13 17:01:00 -05:00
advplyr
5cadc8d90f Merge pull request #4150 from pinjeff/docker-build
Reduce final docker image size
2025-05-12 15:20:51 -05:00
advplyr
40e7e36ef6 Dockerfile unnecessary stage 1 apks 2025-05-12 15:15:18 -05:00
advplyr
d60ad96f8a Update search to exclude returning series with no books #3736 2025-05-11 16:59:11 -05:00
advplyr
46ba342d49 Merge pull request #4237 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-05-10 16:56:33 -05:00
peter cerny
ace6b2b81f Translated using Weblate (Slovak)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
fa7e2dfafe Translated using Weblate (Catalan)
Currently translated at 95.3% (1049 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-10 23:54:41 +02:00
Oleg Ivasenko
015310c15d Translated using Weblate (Russian)
Currently translated at 99.9% (1099 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
f624f04dec Translated using Weblate (Spanish)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-10 23:54:41 +02:00
Michal
7c13cfcda2 Translated using Weblate (Slovak)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Azorimor
fc265dadae Translated using Weblate (German)
Currently translated at 99.6% (1096 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-05-10 23:54:41 +02:00
peter cerny
f9905f887e Translated using Weblate (Slovak)
Currently translated at 96.1% (1058 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Michal
eb72bfbbc0 Translated using Weblate (Slovak)
Currently translated at 96.1% (1058 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
c268cace09 Translated using Weblate (Catalan)
Currently translated at 95.2% (1048 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-10 23:54:41 +02:00
Juraj Borza
9666caf7a3 Translated using Weblate (Slovak)
Currently translated at 80.5% (886 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
9e01e5c24e Translated using Weblate (Catalan)
Currently translated at 94.3% (1038 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
25e613a867 Translated using Weblate (Spanish)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-10 23:54:41 +02:00
Juraj Borza
fe23a86eaa Translated using Weblate (Slovak)
Currently translated at 79.0% (870 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
peter cerny
cb5a7d6aef Translated using Weblate (Slovak)
Currently translated at 79.0% (870 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
peter cerny
7deb89ce7a Translated using Weblate (Slovak)
Currently translated at 76.5% (842 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
1e300c77c9 Translated using Weblate (Catalan)
Currently translated at 94.3% (1038 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-10 23:54:41 +02:00
peter cerny
ed7cc42959 Translated using Weblate (Slovak)
Currently translated at 70.3% (774 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
f681ff68a1 Translated using Weblate (Catalan)
Currently translated at 94.3% (1038 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-05-10 23:54:41 +02:00
thehijacker
ba112bf9c2 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2025-05-10 23:54:41 +02:00
Adolfo Jayme Barrientos
718434545a Translated using Weblate (Spanish)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-05-10 23:54:41 +02:00
Максим Горпиніч
0e9a4c95a9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1100 of 1100 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-05-10 23:54:41 +02:00
ABS translator
3c997c8468 Translated using Weblate (Arabic)
Currently translated at 23.0% (253 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-10 23:54:41 +02:00
burghy86
eb49646256 Translated using Weblate (Italian)
Currently translated at 100.0% (1099 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/it/
2025-05-10 23:54:41 +02:00
ABS translator
c54b5eadfd Translated using Weblate (Arabic)
Currently translated at 20.7% (228 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-05-10 23:54:40 +02:00
advplyr
659c671c25 Merge pull request #4226 from Vito0912/feat/chapterLookUp
Changes to Chapter-Lookup
2025-05-10 16:54:33 -05:00
advplyr
0df5a7816d Update chapter toast strings, update spacing, autoformat 2025-05-10 16:42:34 -05:00
advplyr
26c976b6b9 Merge branch 'master' into feat/chapterLookUp 2025-05-10 16:22:30 -05:00
advplyr
bdeb22615e Merge pull request #4261 from nschum/fix-ignore-parent
Fix .ignore file causing ignores outside the directory
2025-05-09 17:42:26 -05:00
advplyr
257bf2ebe0 Update edit chapters page breakpoint & cleanup padding 2025-05-09 17:24:02 -05:00
advplyr
fc33da447a Remove unused album component 2025-05-09 17:13:17 -05:00
advplyr
df45347690 Merge pull request #4274 from advplyr/audiobook_tools_update
Audiobook tools update
2025-05-08 17:31:46 -05:00
advplyr
b876256736 Audiobook tools page include edit item button and item title linked to item page 2025-05-08 17:17:44 -05:00
advplyr
3ce6e45761 Support m4b encoder tool for single m4b audiobooks 2025-05-08 17:08:11 -05:00
advplyr
5ac6b85da1 Merge pull request #4270 from advplyr/episode_secondary_sorts
Update episode secondary sort to pubDate and episode #4262
2025-05-07 17:45:53 -05:00
advplyr
69e0a0732a Update episode secondary sort to pubDate and episode #4262 2025-05-07 17:30:07 -05:00
advplyr
087835a9f3 Merge pull request #4266 from advplyr/hls_stream_url_update
Update HLS stream endpoints to not include user token
2025-05-06 17:39:16 -05:00
advplyr
1f7b181b7b Update HLS stream endpoints to not include user token 2025-05-06 17:28:19 -05:00
advplyr
1afb8840db Merge pull request #4263 from advplyr/new_session_track_endpoint
Add new api endpoint for direct playing audio files using session id
2025-05-05 17:25:40 -05:00
advplyr
d9531166b6 Fix for HLS transcode urls 2025-05-05 17:07:51 -05:00
advplyr
336de49d8d Add new api endpoint for direct playing audio files using session id #4259 2025-05-05 17:00:43 -05:00
Nikolaj Schumacher
3cc527484d Fix .ignore file causing ignores outside the directory
The file "a/.ignore" should only cause the directory "a" to be ignored.
However, it also ignores all files starting with "a".
After this fix, it will only ignore paths starting with "a/".
2025-05-04 22:43:44 +02:00
advplyr
45987ffd63 Fix library stats returning null instead of 0 #4251 2025-05-03 17:25:01 -05:00
advplyr
1a1ef9c378 Merge pull request #4253 from advplyr/audiobook_tools_enhancements
Audiobook tools enhancements
2025-05-02 17:43:39 -05:00
advplyr
342d100f3e Replace advanced options with presets/advanced card 2025-05-02 17:24:46 -05:00
advplyr
e0b90c6813 Add channels, codec and bitrate to tracks table & breakpoint updates 2025-05-02 15:06:31 -05:00
advplyr
2706a9c4aa Merge pull request #4249 from advplyr/watcher_rescans_update
Update watcher to re-scan library items for non-media file only updates
2025-05-01 17:29:25 -05:00
advplyr
2cc9d1b7f8 Update watcher to re-scan library items when non-media files are added/updated #4245 2025-05-01 17:17:40 -05:00
advplyr
2b7268c952 Merge pull request #4240 from josh-vin/feat/defaultYearInReview
Improves Year in Review display logic
2025-04-30 17:26:00 -05:00
advplyr
e097fe1e88 Merge pull request #4241 from advplyr/player_track_tooltip
Fix player track tooltip overflowing on share player
2025-04-29 18:01:25 -05:00
advplyr
6819c0b108 Fix player track tooltip overflowing on share player 2025-04-29 17:46:54 -05:00
Josh Vincent
58cd751b43 Improves Year in Review display logic 2025-04-28 21:00:22 -06:00
advplyr
9f834a5345 Merge pull request #4234 from advplyr/fix_exclude_prefixes_crash
Fix server crash when updating excluded prefixes #4221
2025-04-28 16:57:38 -05:00
advplyr
5eaf9c69ad Fix server crash when updating excluded prefixes #4221 2025-04-28 16:40:06 -05:00
Vito0912
a1074e69ac Fixed crash 2025-04-27 19:51:56 +02:00
Vito0912
65aec6a099 Adds locale 2025-04-27 19:44:28 +02:00
Vito0912
38957d4f32 fix shift times not works when editing 2025-04-27 19:34:12 +02:00
Vito0912
a2dc76e190 remove brading 2025-04-27 19:21:37 +02:00
advplyr
fd84cd0d7f Version bump v2.21.0 2025-04-27 10:51:31 -05:00
advplyr
db7744eb84 Merge pull request #4192 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-04-27 10:48:14 -05:00
SunSpring
af513a2fb6 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1099 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-04-27 16:27:46 +02:00
Sergey Ponomarev
4cb5c934d5 Translated using Weblate (Russian)
Currently translated at 100.0% (1099 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-04-27 16:27:46 +02:00
biuklija
37f84a0f62 Translated using Weblate (Croatian)
Currently translated at 100.0% (1099 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2025-04-27 16:27:45 +02:00
Bezruchenko Simon
70595181f1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1099 of 1099 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-04-27 16:27:45 +02:00
Fredrik Lindqvist
b357bbed60 Translated using Weblate (Swedish)
Currently translated at 95.8% (1050 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sv/
2025-04-27 16:27:44 +02:00
Robin Stolpe
f7a720c6ac Translated using Weblate (Swedish)
Currently translated at 95.8% (1050 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sv/
2025-04-27 16:27:43 +02:00
dvc05
6549605efd Translated using Weblate (Norwegian Bokmål)
Currently translated at 92.3% (1012 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nb_NO/
2025-04-27 16:27:43 +02:00
kuci-JK
33952fb1fd Translated using Weblate (Czech)
Currently translated at 99.4% (1090 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2025-04-27 16:27:42 +02:00
SunSpring
7b207dc5d8 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-04-27 16:27:42 +02:00
Fredrik Lindqvist
cb24a9c1ec Translated using Weblate (Swedish)
Currently translated at 94.9% (1041 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sv/
2025-04-27 16:27:41 +02:00
Pim
3b42af5213 Translated using Weblate (Dutch)
Currently translated at 98.8% (1083 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/nl/
2025-04-27 16:27:40 +02:00
Kabika82
b56691f1a2 Translated using Weblate (Hungarian)
Currently translated at 95.8% (1051 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hu/
2025-04-27 16:27:40 +02:00
cebo29
ac3154093c Translated using Weblate (German)
Currently translated at 99.7% (1093 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-04-27 16:27:39 +02:00
peter cerny
01ef24f5e6 Translated using Weblate (Slovak)
Currently translated at 66.4% (728 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-27 16:27:39 +02:00
thehijacker
3fb73c7426 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2025-04-27 16:27:38 +02:00
NickSkier
bf3bc06322 Translated using Weblate (Russian)
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-04-27 16:27:37 +02:00
petr-prikryl
2733c28784 Translated using Weblate (Czech)
Currently translated at 98.4% (1079 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/cs/
2025-04-27 16:27:37 +02:00
Jan-Eric Myhrgren
b3dac831e6 Translated using Weblate (Swedish)
Currently translated at 94.8% (1040 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sv/
2025-04-27 16:27:36 +02:00
ABS translator
35702aa770 Translated using Weblate (Arabic)
Currently translated at 19.4% (213 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ar/
2025-04-27 16:27:36 +02:00
Jakob Zoll
b2ffb3b7b9 Translated using Weblate (German)
Currently translated at 99.7% (1093 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-04-27 16:27:35 +02:00
Charlie
c52fe4b583 Translated using Weblate (French)
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fr/
2025-04-27 16:27:34 +02:00
Максим Горпиніч
af8ace7d1f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-04-27 16:27:34 +02:00
biuklija
de37e40a1e Translated using Weblate (Croatian)
Currently translated at 100.0% (1096 of 1096 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2025-04-27 16:27:33 +02:00
polarwood
56f5df91dc Translated using Weblate (Turkish)
Currently translated at 27.2% (298 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/tr/
2025-04-27 16:27:32 +02:00
polarwood
fc590abb09 Translated using Weblate (Turkish)
Currently translated at 24.7% (271 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/tr/
2025-04-27 16:27:32 +02:00
Marc Casalprim
bc7bbc1b7d Translated using Weblate (Catalan)
Currently translated at 94.4% (1034 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-04-27 16:27:31 +02:00
polarwood
4345973213 Translated using Weblate (Turkish)
Currently translated at 23.4% (257 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/tr/
2025-04-27 16:27:30 +02:00
Joao
b4ff9f5944 Translated using Weblate (Portuguese (Brazil))
Currently translated at 71.7% (786 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/pt_BR/
2025-04-27 16:27:30 +02:00
peter cerny
a9a253f769 Translated using Weblate (Slovak)
Currently translated at 64.6% (708 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-27 16:27:29 +02:00
polarwood
a9783efa34 Translated using Weblate (Turkish)
Currently translated at 22.4% (246 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/tr/
2025-04-27 16:27:28 +02:00
peter cerny
a380ee080f Translated using Weblate (Slovak)
Currently translated at 51.6% (566 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-27 16:27:28 +02:00
Ricky Tigg
eabefd099c Translated using Weblate (Finnish)
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/fi/
2025-04-27 16:27:27 +02:00
advplyr
97799919e6 Update tooltip position of sync button on upload page to prevent overlapping 2025-04-27 09:27:19 -05:00
advplyr
35870a0158 Update upload API endpoint to validate request body 2025-04-27 09:18:52 -05:00
advplyr
ec05bd36e4 Merge pull request #4223 from Vito0912/feat/fixCrashEmptyCollection
Fix server crash when a user requests the RSS feed of an empty collection
2025-04-26 13:43:38 -05:00
advplyr
be041f93c2 Merge pull request #4213 from nichwall/chapter_lookup_error_fix
Chapter lookup error interface update
2025-04-26 12:17:28 -05:00
advplyr
a156d3595b Merge pull request #4212 from Nishantsingh11/fix/AIFF-is-supported-but-AIF-isnot
fix(AIFF is supported, but AIF isn't)
2025-04-26 12:05:33 -05:00
Vito0912
a1d549a2b1 prettier 2025-04-26 17:46:19 +02:00
Vito0912
812cb5a160 feat/fixCrashEmptyCollection 2025-04-26 17:35:17 +02:00
Nishantsingh11
e6264540af constants.js in server/utils and client/plugins updated. 2025-04-20 18:34:33 +05:30
Nicholas Wallace
79fe064c4a Add: server localization for chapter lookup 2025-04-19 23:25:17 -07:00
Nicholas Wallace
7e69713683 Change: chapter lookup to be in modal 2025-04-19 23:13:38 -07:00
Nishantsingh11
3bbeb8f27a fix(AIFF is supported, but AIF isn't) 2025-04-20 07:56:44 +05:30
advplyr
04fb8fa61d Merge pull request #3690 from Vito0912/feat/metadataForPlaybackSessions
Improved Metadata Handling and PlaybackSession Metadata Robustness
2025-04-18 17:08:12 -05:00
advplyr
2caa861b8a Update local session mediaMetadata with current item mediaMetadata for undefined values 2025-04-18 17:04:11 -05:00
advplyr
d7f0815fb3 Merge branch 'master' into feat/metadataForPlaybackSessions 2025-04-18 16:34:13 -05:00
Vito0912
e6ab05e177 update so also populates data if mediaMetadata is not null 2025-04-18 07:29:34 +02:00
advplyr
c2ecfd428b Update docker-build workflow to use ubuntu-24.04 2025-04-17 16:28:06 -05:00
advplyr
9f26274ca8 Add pub date sort in episode feed modal #4073 2025-04-16 16:45:49 -05:00
advplyr
7764f1cf75 Merge pull request #4200 from advplyr/socket_item_events
Fix socket events check user permissions for library items #4199
2025-04-12 17:48:22 -05:00
advplyr
bc1b99efd6 Fix socket events check user permissions for library items #4199 2025-04-12 17:39:51 -05:00
advplyr
26309019e7 Merge pull request #4195 from advplyr/fix_podcast_episode_scanner_promise
Fix podcast re-scan promise
2025-04-10 17:54:26 -05:00
advplyr
b47d7b734d Update podcast scanner to remove media progress and episodes from playlist 2025-04-10 17:51:42 -05:00
advplyr
62194b8781 Fix podcast re-scan promise 2025-04-10 17:39:41 -05:00
advplyr
7c114a051a Set podcast episode audio file index to 1 for scanned in episodes 2025-04-09 08:33:00 -05:00
advplyr
26c0c89b94 Update podcast latest page to show latest 50 episodes #3343 2025-04-08 17:39:24 -05:00
advplyr
c81071a7b3 Fix item page text overlap on details #4187 2025-04-07 17:19:48 -05:00
advplyr
31f48edcc3 Update close feed button on rss feeds table to be consistent with other UI 2025-04-06 17:56:17 -05:00
advplyr
f7109a055c Fix rss feeds table overflow with long slugs 2025-04-06 17:50:39 -05:00
advplyr
9d0e7759e0 Merge pull request #4158 from weblate/weblate-audiobookshelf-abs-web-client
Translations update from Hosted Weblate
2025-04-04 17:24:59 -05:00
peter cerny
d15ccbd2fc Translated using Weblate (Slovak)
Currently translated at 50.7% (556 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:31 +02:00
Coxe
cfeb1743df Translated using Weblate (Danish)
Currently translated at 99.8% (1093 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/da/
2025-04-05 00:17:31 +02:00
peter cerny
a7e0330b06 Translated using Weblate (Slovak)
Currently translated at 43.2% (474 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:30 +02:00
biuklija
5f69e83d46 Translated using Weblate (Croatian)
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hr/
2025-04-05 00:17:30 +02:00
peter cerny
fdde62896f Translated using Weblate (Slovak)
Currently translated at 41.9% (459 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:29 +02:00
thehijacker
f1909d0fc7 Translated using Weblate (Slovenian)
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sl/
2025-04-05 00:17:28 +02:00
Mikkel Dupont Olesen
28225618fd Translated using Weblate (Danish)
Currently translated at 99.2% (1087 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/da/
2025-04-05 00:17:27 +02:00
Marc
1a562a5f23 Translated using Weblate (German)
Currently translated at 99.6% (1091 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/de/
2025-04-05 00:17:27 +02:00
peter cerny
bfbbcba160 Translated using Weblate (Slovak)
Currently translated at 29.5% (324 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:26 +02:00
Jan-Eric Myhrgren
21e4d17ef3 Translated using Weblate (Swedish)
Currently translated at 94.8% (1039 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sv/
2025-04-05 00:17:25 +02:00
Augusto Massini Pinto
87faebc7d9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 71.4% (782 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/pt_BR/
2025-04-05 00:17:25 +02:00
Adolfo Jayme Barrientos
5d868d1355 Translated using Weblate (Spanish)
Currently translated at 99.4% (1089 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-04-05 00:17:24 +02:00
Adolfo Jayme Barrientos
ac0fd41740 Translated using Weblate (Catalan)
Currently translated at 94.2% (1032 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-04-05 00:17:24 +02:00
Adolfo Jayme Barrientos
1202e95b66 Translated using Weblate (Spanish)
Currently translated at 99.4% (1089 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-04-05 00:17:23 +02:00
Simple16
c05cf9718b Translated using Weblate (Russian)
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ru/
2025-04-05 00:17:22 +02:00
Adolfo Jayme Barrientos
d8f1e43e85 Translated using Weblate (Spanish)
Currently translated at 99.2% (1087 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/es/
2025-04-05 00:17:22 +02:00
Adolfo Jayme Barrientos
ed7e87b168 Translated using Weblate (Catalan)
Currently translated at 94.1% (1031 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/ca/
2025-04-05 00:17:21 +02:00
Martin Balko
4ca2c9e97f Translated using Weblate (Slovak)
Currently translated at 28.5% (313 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:20 +02:00
Kabika82
01dd1c0615 Translated using Weblate (Hungarian)
Currently translated at 95.9% (1051 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/hu/
2025-04-05 00:17:20 +02:00
Martin Balko
cd387b8fed Translated using Weblate (Slovak)
Currently translated at 27.7% (304 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/sk/
2025-04-05 00:17:19 +02:00
SunSpring
c85cd69152 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/zh_Hans/
2025-04-05 00:17:18 +02:00
Максим Горпиніч
9e9b52a252 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1095 of 1095 strings)

Translation: Audiobookshelf/Abs Web Client
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-web-client/uk/
2025-04-05 00:17:18 +02:00
advplyr
292d5783a9 Update player queue button on item page to be to the right of the read button to keep consistent spacing 2025-04-04 17:17:06 -05:00
advplyr
c7faafd0f3 Fix author order when scanning in multi-author books by setting bookAuthor.createdAt when bulk creating #4177 2025-04-03 17:50:10 -05:00
advplyr
ca7388b14e Fix download podcast update library item size #4180 2025-04-02 17:35:57 -05:00
advplyr
ddf2ca3670 Update item image in audio player when updated on item #4025 2025-04-01 17:32:21 -05:00
advplyr
96825c3c2b Update feedepisode psc customElement 2025-03-31 17:59:16 -05:00
advplyr
6ed66fea16 Update podcast rss feed parser to use psc chapters on episodes 2025-03-31 17:57:39 -05:00
advplyr
ddcda197b4 Fix manage, chapters edit tracks and library stats page not setting the current library properly #4170 2025-03-30 17:27:36 -05:00
advplyr
8bea5d83f5 Merge pull request #4168 from advplyr/new_stats_controller
Create new StatsController and move year in review stats endpoint
2025-03-29 17:44:25 -05:00
advplyr
73c1ea92f3 Add admin middleware for StatsController 2025-03-29 17:37:13 -05:00
advplyr
4fb5330308 Create new StatsController and move year in review stats endpoint 2025-03-29 17:34:17 -05:00
advplyr
f853cff920 Fix LazyBookCard test with new globals getter for placeholder url 2025-03-28 17:42:41 -05:00
Balki
dc3c978f8d Merge branch 'advplyr:master' into patch-1 2025-03-28 04:55:20 +00:00
advplyr
e87825f8df Merge pull request #4151 from mikiher/fix-component-tests
Fix broken component tests
2025-03-27 17:38:22 -05:00
advplyr
718433183b Fix Cover modal showing error image for items with no cover, update placeholder cover url to all come from global store 2025-03-27 17:37:25 -05:00
advplyr
7f3421f78a Merge pull request #4164 from advplyr/count_cache_for_userpermissions
Fix items count for users with item restricting permissions
2025-03-26 17:41:43 -05:00
Balki
13fac2d5bc Support http server listening on unix socket 2025-03-25 19:36:19 -04:00
mikiher
59e099f950 Add GitHub Actions workflow for running component tests 2025-03-24 07:42:26 +02:00
mikiher
b18da959db Fix broken component tests 2025-03-23 20:40:58 +02:00
Jaffar Ashoor
fd0af6b2dd Reduce final docker image size
this adds a third stage to the build, copying the required files only
from the previos stages, this reduces the final image size from 600MB+
down to ~320MB
2025-03-23 02:59:40 +03:00
Vito0912
121805ba39 Merge branch 'master' into feat/metadataForPlaybackSessions 2025-01-07 17:01:01 +01:00
Vito0912
f9bbd71174 added type to be saved. Should support podcasts
It should support everything important from the podcast metadata:
https://api.audiobookshelf.org/#podcast-metadata

And the book metadata:
https://api.audiobookshelf.org/#book-metadata
2024-12-17 15:27:37 +01:00
Vito0912
2fbb31e0ea added null saftey and added displayTitle and displayAuthor 2024-12-07 10:37:00 +01:00
Vito0912
89167543fa added author for podcasts 2024-12-07 10:25:52 +01:00
Vito0912
33e0987d73 Added mediaMetadata to playbackSessions 2024-12-07 10:09:14 +01:00
119 changed files with 4395 additions and 934 deletions

48
.github/workflows/component-tests.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Run Component Tests
on:
workflow_dispatch:
inputs:
ref:
description: 'Branch/Tag/SHA to test'
required: true
pull_request:
paths:
- 'client/**'
- '.github/workflows/component-tests.yml'
push:
paths:
- 'client/**'
- '.github/workflows/component-tests.yml'
jobs:
run-component-tests:
name: Run Component Tests
runs-on: ubuntu-latest
steps:
- name: Checkout (push/pull request)
uses: actions/checkout@v4
if: github.event_name != 'workflow_dispatch'
- name: Checkout (workflow_dispatch)
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
if: github.event_name == 'workflow_dispatch'
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- name: Install dependencies
run: |
cd client
npm ci
- name: Run tests
run: |
cd client
npm test

View File

@@ -23,7 +23,7 @@ on:
jobs:
build:
if: ${{ !contains(github.event.head_commit.message, 'skip ci') && github.repository == 'advplyr/audiobookshelf' }}
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- name: Check out

1
.gitignore vendored
View File

@@ -23,3 +23,4 @@ sw.*
.DS_STORE
.idea/*
tailwind.compiled.css
tailwind.config.js

View File

@@ -1,34 +1,32 @@
ARG NUSQLITE3_DIR="/usr/local/lib/nusqlite3"
ARG NUSQLITE3_PATH="${NUSQLITE3_DIR}/libnusqlite3.so"
### STAGE 0: Build client ###
FROM node:20-alpine AS build
FROM node:20-alpine AS build-client
WORKDIR /client
COPY /client /client
RUN npm ci && npm cache clean --force
RUN npm run generate
### STAGE 1: Build server ###
FROM node:20-alpine
FROM node:20-alpine AS build-server
ARG NUSQLITE3_DIR
ARG TARGETPLATFORM
ENV NODE_ENV=production
RUN apk update && \
apk add --no-cache --update \
RUN apk add --no-cache --update \
curl \
tzdata \
ffmpeg \
make \
python3 \
g++ \
tini \
unzip
COPY --from=build /client/dist /client/dist
COPY index.js package* /
COPY server server
ARG TARGETPLATFORM
ENV NUSQLITE3_DIR="/usr/local/lib/nusqlite3"
ENV NUSQLITE3_PATH="${NUSQLITE3_DIR}/libnusqlite3.so"
WORKDIR /server
COPY index.js package* /server
COPY /server /server/server
RUN case "$TARGETPLATFORM" in \
"linux/amd64") \
@@ -42,14 +40,34 @@ RUN case "$TARGETPLATFORM" in \
RUN npm ci --only=production
RUN apk del make python3 g++
### STAGE 2: Create minimal runtime image ###
FROM node:20-alpine
ARG NUSQLITE3_DIR
ARG NUSQLITE3_PATH
# Install only runtime dependencies
RUN apk add --no-cache --update \
tzdata \
ffmpeg \
tini
WORKDIR /app
# Copy compiled frontend and server from build stages
COPY --from=build-client /client/dist /app/client/dist
COPY --from=build-server /server /app
COPY --from=build-server /usr/local/lib/nusqlite3 /usr/local/lib/nusqlite3
EXPOSE 80
ENV PORT=80
ENV NODE_ENV=production
ENV CONFIG_PATH="/config"
ENV METADATA_PATH="/metadata"
ENV SOURCE="docker"
ENV NUSQLITE3_DIR=${NUSQLITE3_DIR}
ENV NUSQLITE3_PATH=${NUSQLITE3_PATH}
ENTRYPOINT ["tini", "--"]
CMD ["node", "index.js"]

View File

@@ -217,6 +217,16 @@ export default {
})
}
if (this.results.episodes?.length) {
shelves.push({
id: 'episodes',
label: 'Episodes',
labelStringKey: 'LabelEpisodes',
type: 'episode',
entities: this.results.episodes.map((res) => res.libraryItem)
})
}
if (this.results.series?.length) {
shelves.push({
id: 'series',

View File

@@ -274,15 +274,10 @@ export default {
isAuthorsPage() {
return this.page === 'authors'
},
isAlbumsPage() {
return this.page === 'albums'
},
numShowing() {
return this.totalEntities
},
entityName() {
if (this.isAlbumsPage) return 'Albums'
if (this.isPodcastLibrary) return this.$strings.LabelPodcasts
if (!this.page) return this.$strings.LabelBooks
if (this.isSeriesPage) return this.$strings.LabelSeries

View File

@@ -156,7 +156,7 @@ export default {
return this.mediaMetadata.authors || []
},
libraryId() {
return this.streamLibraryItem ? this.streamLibraryItem.libraryId : null
return this.streamLibraryItem?.libraryId || null
},
totalDurationPretty() {
// Adjusted by playback rate

View File

@@ -0,0 +1,60 @@
<template>
<div class="flex items-center h-full px-1 overflow-hidden">
<covers-book-cover :library-item="libraryItem" :width="coverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
<div class="grow px-2 episodeSearchCardContent">
<p class="truncate text-sm">{{ episodeTitle }}</p>
<p class="text-xs text-gray-200 truncate">{{ podcastTitle }}</p>
</div>
</div>
</template>
<script>
export default {
props: {
libraryItem: {
type: Object,
default: () => {}
},
episode: {
type: Object,
default: () => {}
}
},
data() {
return {}
},
computed: {
bookCoverAspectRatio() {
return this.$store.getters['libraries/getBookCoverAspectRatio']
},
coverWidth() {
if (this.bookCoverAspectRatio === 1) return 50 * 1.2
return 50
},
media() {
return this.libraryItem?.media || {}
},
mediaMetadata() {
return this.media.metadata || {}
},
episodeTitle() {
return this.episode.title || 'No Title'
},
podcastTitle() {
return this.mediaMetadata.title || 'No Title'
}
},
methods: {},
mounted() {}
}
</script>
<style>
.episodeSearchCardContent {
width: calc(100% - 80px);
height: 75px;
display: flex;
flex-direction: column;
justify-content: center;
}
</style>

View File

@@ -20,10 +20,10 @@
<div class="w-1/2 px-2">
<div v-if="!isPodcast" class="flex items-end">
<ui-text-input-with-label v-model.trim="itemData.author" :disabled="processing" :label="$strings.LabelAuthor" />
<ui-tooltip :text="$strings.LabelUploaderItemFetchMetadataHelp">
<div class="ml-2 mb-1 w-8 h-8 bg-bg border border-white/10 flex items-center justify-center rounded-full hover:bg-primary cursor-pointer" @click="fetchMetadata">
<ui-tooltip direction="top" :text="$strings.LabelUploaderItemFetchMetadataHelp">
<button type="button" class="ml-2 mb-1 w-8 h-8 bg-bg border border-white/10 flex items-center justify-center rounded-full hover:bg-primary cursor-pointer" @click="fetchMetadata">
<span class="text-base text-white/80 font-mono material-symbols">sync</span>
</div>
</button>
</ui-tooltip>
</div>
<div v-else class="w-full">

View File

@@ -1,142 +0,0 @@
<template>
<div ref="card" :id="`album-card-${index}`" :style="{ width: cardWidth + 'px' }" class="absolute top-0 left-0 rounded-xs z-30 cursor-pointer" @mousedown.prevent @mouseup.prevent @mousemove.prevent @mouseover="mouseover" @mouseleave="mouseleave" @click="clickCard">
<div class="relative" :style="{ height: coverHeight + 'px' }">
<div class="absolute top-0 left-0 w-full box-shadow-book shadow-height" />
<div class="w-full h-full bg-primary relative rounded-sm overflow-hidden">
<covers-preview-cover ref="cover" :src="coverSrc" :width="cardWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
</div>
</div>
<div class="relative w-full">
<div v-if="!isAlternativeBookshelfView" class="categoryPlacard absolute z-30 left-0 right-0 mx-auto -bottom-6e h-6e rounded-md text-center" :style="{ width: Math.min(200, cardWidth) + 'px' }">
<div class="w-full h-full shinyBlack flex items-center justify-center rounded-xs border" :style="{ padding: `0em ${0.5}em` }">
<p class="truncate" :style="{ fontSize: labelFontSize + 'em' }">{{ title }}</p>
</div>
</div>
<div v-else class="absolute z-30 left-0 right-0 mx-auto -bottom-8e h-8e py-1e rounded-md text-center">
<p class="truncate" :style="{ fontSize: labelFontSize + 'em' }">{{ title }}</p>
<p class="truncate text-gray-400" :style="{ fontSize: 0.8 + 'em' }">{{ artist || '&nbsp;' }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
index: Number,
width: Number,
height: {
type: Number,
default: 192
},
bookshelfView: {
type: Number,
default: 0
},
albumMount: {
type: Object,
default: () => null
}
},
data() {
return {
album: null,
isSelectionMode: false,
selected: false,
isHovering: false
}
},
computed: {
bookCoverAspectRatio() {
return this.store.getters['libraries/getBookCoverAspectRatio']
},
cardWidth() {
return this.width || this.coverHeight
},
coverHeight() {
return this.height * this.sizeMultiplier
},
/*
cardHeight() {
return this.coverHeight + this.bottomTextHeight
},
bottomTextHeight() {
if (!this.isAlternativeBookshelfView) return 0
const lineHeight = 1.5
const remSize = 16
const baseHeight = this.sizeMultiplier * lineHeight * remSize
const titleHeight = this.labelFontSize * baseHeight
const paddingHeight = 4 * 2 * this.sizeMultiplier // py-1
return titleHeight + paddingHeight
},
*/
coverSrc() {
const config = this.$config || this.$nuxt.$config
if (!this.album || !this.album.libraryItemId) return `${config.routerBasePath}/book_placeholder.jpg`
return this.store.getters['globals/getLibraryItemCoverSrcById'](this.album.libraryItemId)
},
labelFontSize() {
if (this.width < 160) return 0.75
return 0.9
},
sizeMultiplier() {
return this.store.getters['user/getSizeMultiplier']
},
title() {
return this.album ? this.album.title : ''
},
artist() {
return this.album ? this.album.artist : ''
},
store() {
return this.$store || this.$nuxt.$store
},
currentLibraryId() {
return this.store.state.libraries.currentLibraryId
},
isAlternativeBookshelfView() {
const constants = this.$constants || this.$nuxt.$constants
return this.bookshelfView == constants.BookshelfView.DETAIL
}
},
methods: {
setEntity(album) {
this.album = album
},
setSelectionMode(val) {
this.isSelectionMode = val
},
mouseover() {
this.isHovering = true
},
mouseleave() {
this.isHovering = false
},
clickCard() {
if (!this.album) return
// const router = this.$router || this.$nuxt.$router
// router.push(`/album/${this.$encode(this.title)}`)
},
clickEdit() {
this.$emit('edit', this.album)
},
destroy() {
// destroy the vue listeners, etc
this.$destroy()
// remove the element from the DOM
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el)
} else if (this.$el && this.$el.remove) {
this.$el.remove()
}
}
},
mounted() {
if (this.albumMount) {
this.setEntity(this.albumMount)
}
}
}
</script>

View File

@@ -223,8 +223,7 @@ export default {
return this.mediaMetadata.explicit || false
},
placeholderUrl() {
const config = this.$config || this.$nuxt.$config
return `${config.routerBasePath}/book_placeholder.jpg`
return this.store.getters['globals/getPlaceholderCoverSrc']
},
bookCoverSrc() {
return this.store.getters['globals/getLibraryItemCoverSrc'](this._libraryItem, this.placeholderUrl)

View File

@@ -1,7 +1,7 @@
<template>
<div>
<div v-if="narrators?.length" class="flex py-0.5 mt-4">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelNarrators }}</span>
</div>
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
@@ -12,7 +12,7 @@
</div>
</div>
<div v-if="publishedYear" role="paragraph" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPublishYear }}</span>
</div>
<div>
@@ -20,7 +20,7 @@
</div>
</div>
<div v-if="publisher" role="paragraph" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPublisher }}</span>
</div>
<div>
@@ -28,7 +28,7 @@
</div>
</div>
<div v-if="podcastType" role="paragraph" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelPodcastType }}</span>
</div>
<div class="capitalize">
@@ -36,7 +36,7 @@
</div>
</div>
<div class="flex py-0.5" v-if="genres.length">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelGenres }}</span>
</div>
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
@@ -47,7 +47,7 @@
</div>
</div>
<div class="flex py-0.5" v-if="tags.length">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelTags }}</span>
</div>
<div class="max-w-[calc(100vw-10rem)] overflow-hidden text-ellipsis">
@@ -58,7 +58,7 @@
</div>
</div>
<div v-if="language" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelLanguage }}</span>
</div>
<div>
@@ -66,7 +66,7 @@
</div>
</div>
<div v-if="tracks.length || (isPodcast && totalPodcastDuration)" role="paragraph" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelDuration }}</span>
</div>
<div>
@@ -74,7 +74,7 @@
</div>
</div>
<div role="paragraph" class="flex py-0.5">
<div class="w-24 min-w-24 sm:w-32 sm:min-w-32">
<div class="w-34 min-w-34 sm:w-34 sm:min-w-34 break-words">
<span class="text-white/60 uppercase text-sm">{{ $strings.LabelSize }}</span>
</div>
<div>

View File

@@ -39,6 +39,15 @@
</li>
</template>
<p v-if="episodeResults.length" class="uppercase text-xs text-gray-400 my-1 px-1 font-semibold">{{ $strings.LabelEpisodes }}</p>
<template v-for="item in episodeResults">
<li :key="item.libraryItem.recentEpisode.id" class="text-gray-50 select-none relative cursor-pointer hover:bg-black-400 py-1" role="option" @click="clickOption">
<nuxt-link :to="`/item/${item.libraryItem.id}`">
<cards-episode-search-card :episode="item.libraryItem.recentEpisode" :library-item="item.libraryItem" />
</nuxt-link>
</li>
</template>
<p v-if="authorResults.length" class="uppercase text-xs text-gray-400 mb-1 mt-3 px-1 font-semibold">{{ $strings.LabelAuthors }}</p>
<template v-for="item in authorResults">
<li :key="item.id" class="text-gray-50 select-none relative cursor-pointer hover:bg-black-400 py-1" role="option" @click="clickOption">
@@ -100,6 +109,7 @@ export default {
isFetching: false,
search: null,
podcastResults: [],
episodeResults: [],
bookResults: [],
authorResults: [],
seriesResults: [],
@@ -115,7 +125,7 @@ export default {
return this.$store.state.libraries.currentLibraryId
},
totalResults() {
return this.bookResults.length + this.seriesResults.length + this.authorResults.length + this.tagResults.length + this.genreResults.length + this.podcastResults.length + this.narratorResults.length
return this.bookResults.length + this.seriesResults.length + this.authorResults.length + this.tagResults.length + this.genreResults.length + this.podcastResults.length + this.narratorResults.length + this.episodeResults.length
}
},
methods: {
@@ -132,6 +142,7 @@ export default {
this.search = null
this.lastSearch = null
this.podcastResults = []
this.episodeResults = []
this.bookResults = []
this.authorResults = []
this.seriesResults = []
@@ -175,6 +186,7 @@ export default {
if (!this.isFetching) return
this.podcastResults = searchResults.podcast || []
this.episodeResults = searchResults.episodes || []
this.bookResults = searchResults.book || []
this.authorResults = searchResults.authors || []
this.seriesResults = searchResults.series || []

View File

@@ -276,6 +276,11 @@ export default {
text: this.$strings.ButtonIssues,
value: 'issues',
sublist: false
},
{
text: this.$strings.LabelRSSFeedOpen,
value: 'feed-open',
sublist: false
}
]
},

View File

@@ -96,8 +96,8 @@ export default {
return this.author
},
placeholderUrl() {
const config = this.$config || this.$nuxt.$config
return `${config.routerBasePath}/book_placeholder.jpg`
const store = this.$store || this.$nuxt.$store
return store.getters['globals/getPlaceholderCoverSrc']
},
fullCoverUrl() {
if (!this.libraryItem) return null

View File

@@ -18,7 +18,7 @@
</div>
</div>
<p v-if="!imageFailed && showResolution" class="absolute -bottom-5 left-0 right-0 mx-auto text-xs text-gray-300 text-center">{{ resolution }}</p>
<p v-if="!imageFailed && showResolution && resolution" class="absolute -bottom-5 left-0 right-0 mx-auto text-xs text-gray-300 text-center">{{ resolution }}</p>
</div>
</template>
@@ -65,11 +65,12 @@ export default {
return 0.8 * this.sizeMultiplier
},
resolution() {
if (!this.naturalWidth || !this.naturalHeight) return null
return `${this.naturalWidth}×${this.naturalHeight}px`
},
placeholderUrl() {
const config = this.$config || this.$nuxt.$config
return `${config.routerBasePath}/book_placeholder.jpg`
const store = this.$store || this.$nuxt.$store
return store.getters['globals/getPlaceholderCoverSrc']
}
},
methods: {

View File

@@ -14,6 +14,7 @@
<ui-text-input-with-label ref="sequenceInput" v-model="selectedSeries.sequence" :label="$strings.LabelSequence" />
</div>
</div>
<div v-if="error" class="text-error text-sm mt-2 p-1">{{ error }}</div>
<div class="flex justify-end mt-2 p-1">
<ui-btn type="submit">{{ $strings.ButtonSubmit }}</ui-btn>
</div>
@@ -34,12 +35,17 @@ export default {
existingSeriesNames: {
type: Array,
default: () => []
},
originalSeriesSequence: {
type: String,
default: null
}
},
data() {
return {
el: null,
content: null
content: null,
error: null
}
},
watch: {
@@ -85,10 +91,17 @@ export default {
}
},
submitSeriesForm() {
this.error = null
if (this.$refs.newSeriesSelect) {
this.$refs.newSeriesSelect.blur()
}
if (this.selectedSeries.sequence !== this.originalSeriesSequence && this.selectedSeries.sequence.includes(' ')) {
this.error = this.$strings.MessageSeriesSequenceCannotContainSpaces
return
}
this.$emit('submit')
},
clickClose() {
@@ -100,6 +113,7 @@ export default {
}
},
setShow() {
this.error = null
if (!this.el || !this.content) {
this.init()
}

View File

@@ -2,7 +2,7 @@
<div class="w-full h-full overflow-hidden overflow-y-auto px-2 sm:px-4 py-6 relative">
<div class="flex flex-col sm:flex-row mb-4">
<div class="relative self-center md:self-start">
<covers-preview-cover :src="$store.getters['globals/getLibraryItemCoverSrcById'](libraryItemId, libraryItemUpdatedAt, true)" :width="120" :book-cover-aspect-ratio="bookCoverAspectRatio" />
<covers-preview-cover :src="coverUrl" :width="120" :book-cover-aspect-ratio="bookCoverAspectRatio" />
<!-- book cover overlay -->
<div v-if="media.coverPath" class="absolute top-0 left-0 w-full h-full z-10 opacity-0 hover:opacity-100 transition-opacity duration-100">
@@ -157,6 +157,12 @@ export default {
coverPath() {
return this.media.coverPath
},
coverUrl() {
if (!this.coverPath) {
return this.$store.getters['globals/getPlaceholderCoverSrc']
}
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.libraryItemId, this.libraryItemUpdatedAt, true)
},
mediaMetadata() {
return this.media.metadata || {}
},

View File

@@ -74,19 +74,12 @@ export default {
mediaTracks() {
return this.media.tracks || []
},
isSingleM4b() {
return this.mediaTracks.length === 1 && this.mediaTracks[0].metadata.ext.toLowerCase() === '.m4b'
},
chapters() {
return this.media.chapters || []
},
showM4bDownload() {
if (!this.mediaTracks.length) return false
return !this.isSingleM4b
},
showMp3Split() {
if (!this.mediaTracks.length) return false
return this.isSingleM4b && this.chapters.length
return true
},
queuedEmbedLIds() {
return this.$store.state.tasks.queuedEmbedLIds || []

View File

@@ -55,7 +55,7 @@ export default {
return this.item.coverPath
},
coverUrl() {
if (!this.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg`
if (!this.coverPath) return this.$store.getters['globals/getPlaceholderCoverSrc']
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.libraryItemId)
},
bookCoverAspectRatio() {

View File

@@ -10,6 +10,12 @@
<form @submit.prevent="submit" class="flex grow">
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="grow mr-2 text-sm md:text-base" />
</form>
<ui-btn :padding-x="4" @click="toggleSort">
<span class="pr-4">{{ $strings.LabelSortPubDate }}</span>
<span class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-2">
<span class="material-symbols text-xl" :aria-label="sortDescending ? $strings.LabelSortDescending : $strings.LabelSortAscending">{{ sortDescending ? 'expand_more' : 'expand_less' }}</span>
</span>
</ui-btn>
</div>
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
<div v-for="(episode, index) in episodesList" :key="index" class="relative" :class="episode.isDownloaded || episode.isDownloading ? 'bg-primary/40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success/10' : index % 2 == 0 ? 'cursor-pointer bg-primary/25 hover:bg-primary/40' : 'cursor-pointer bg-primary/5 hover:bg-primary/25'" @click="toggleSelectEpisode(episode)">
@@ -73,7 +79,8 @@ export default {
searchTimeout: null,
searchText: null,
downloadedEpisodeGuidMap: {},
downloadedEpisodeUrlMap: {}
downloadedEpisodeUrlMap: {},
sortDescending: true
}
},
watch: {
@@ -141,6 +148,17 @@ export default {
}
},
methods: {
toggleSort() {
this.sortDescending = !this.sortDescending
this.episodesCleaned = this.episodesCleaned.toSorted((a, b) => {
if (this.sortDescending) {
return a.publishedAt < b.publishedAt ? 1 : -1
}
return a.publishedAt > b.publishedAt ? 1 : -1
})
this.selectedEpisodes = {}
this.selectAll = false
},
getIsEpisodeDownloaded(episode) {
if (episode.guid && !!this.downloadedEpisodeGuidMap[episode.guid]) {
return true
@@ -226,8 +244,8 @@ export default {
const sizeInMb = payloadSize / 1024 / 1024
const sizeInMbPretty = sizeInMb.toFixed(2) + 'MB'
console.log('Request size', sizeInMb)
if (sizeInMb > 4.99) {
return this.$toast.error(`Request is too large (${sizeInMbPretty}) should be < 5Mb`)
if (sizeInMb > 9.99) {
return this.$toast.error(`Request is too large (${sizeInMbPretty}) should be < 10Mb`)
}
this.processing = true

View File

@@ -74,6 +74,9 @@ export default {
currentChapterStart() {
if (!this.currentChapter) return 0
return this.currentChapter.start
},
isMobile() {
return this.$store.state.globals.isMobile
}
},
methods: {
@@ -145,6 +148,9 @@ export default {
})
},
mousemoveTrack(e) {
if (this.isMobile) {
return
}
const offsetX = e.offsetX
const baseTime = this.useChapterTrack ? this.currentChapterStart : 0
@@ -198,6 +204,7 @@ export default {
setTrackWidth() {
if (this.$refs.track) {
this.trackWidth = this.$refs.track.clientWidth
this.trackOffsetLeft = this.$refs.track.getBoundingClientRect().left
} else {
console.error('Track not loaded', this.$refs)
}

View File

@@ -164,14 +164,15 @@ export default {
beforeMount() {
this.yearInReviewYear = new Date().getFullYear()
// When not December show previous year
if (new Date().getMonth() < 11) {
this.availableYears = this.getAvailableYears()
const availableYearValues = this.availableYears.map((y) => y.value)
// When not December show previous year if data is available
if (new Date().getMonth() < 11 && availableYearValues.includes(this.yearInReviewYear - 1)) {
this.yearInReviewYear--
}
},
mounted() {
this.availableYears = this.getAvailableYears()
if (typeof navigator.share !== 'undefined' && navigator.share) {
this.showShareButton = true
} else {

View File

@@ -26,9 +26,9 @@
<span class="material-symbols text-2xl text-error">error_outline</span>
</ui-tooltip>
<button aria-label="Download Backup" class="inline-flex material-symbols text-xl mx-1 mt-1 text-white/70 hover:text-white/100" @click.stop="downloadBackup(backup)">download</button>
<button aria-label="Download backup" class="inline-flex material-symbols text-xl mx-1 mt-1 text-white/70 hover:text-white/100" @click.stop="downloadBackup(backup)">download</button>
<button aria-label="Delete Backup" class="inline-flex material-symbols text-xl mx-1 text-white/70 hover:text-error" @click.stop="deleteBackupClick(backup)">delete</button>
<button aria-label="Delete backup" class="inline-flex material-symbols text-xl mx-1 text-white/70 hover:text-error" @click.stop="deleteBackupClick(backup)">delete</button>
</div>
</td>
</tr>

View File

@@ -1,4 +1,3 @@
<template>
<div id="lazy-episodes-table" class="w-full py-6">
<div class="flex flex-wrap flex-col md:flex-row md:items-center mb-4">
@@ -176,6 +175,13 @@ export default {
return episodeProgress && !episodeProgress.isFinished
})
.sort((a, b) => {
// Swap values if sort descending
if (this.sortDesc) {
const temp = a
a = b
b = temp
}
let aValue
let bValue
@@ -194,10 +200,23 @@ export default {
if (!bValue) bValue = Number.MAX_VALUE
}
if (this.sortDesc) {
return String(bValue).localeCompare(String(aValue), undefined, { numeric: true, sensitivity: 'base' })
const primaryCompare = String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' })
if (primaryCompare !== 0 || this.sortKey === 'publishedAt') return primaryCompare
// When sorting by season, secondary sort is by episode number
if (this.sortKey === 'season') {
const aEpisode = a.episode || ''
const bEpisode = b.episode || ''
const secondaryCompare = String(aEpisode).localeCompare(String(bEpisode), undefined, { numeric: true, sensitivity: 'base' })
if (secondaryCompare !== 0) return secondaryCompare
}
return String(aValue).localeCompare(String(bValue), undefined, { numeric: true, sensitivity: 'base' })
// Final sort by publishedAt
let aPubDate = a.publishedAt || Number.MAX_VALUE
let bPubDate = b.publishedAt || Number.MAX_VALUE
return String(aPubDate).localeCompare(String(bPubDate), undefined, { numeric: true, sensitivity: 'base' })
})
},
episodesList() {

View File

@@ -1,6 +1,6 @@
<template>
<div class="inline-flex toggle-btn-wrapper shadow-md">
<button v-for="item in items" :key="item.value" type="button" class="toggle-btn outline-hidden relative border border-gray-600 px-4 py-1" :class="{ selected: item.value === value }" @click.stop="clickBtn(item.value)">
<button v-for="item in items" :key="item.value" type="button" :disabled="disabled" class="toggle-btn outline-hidden relative border border-gray-600 px-4 py-1" :class="{ selected: item.value === value }" @click.stop="clickBtn(item.value)">
{{ item.text }}
</button>
</div>
@@ -9,13 +9,17 @@
<script>
export default {
props: {
value: String,
value: [String, Number],
/**
* [{ "text", "", "value": "" }]
*/
items: {
type: Array,
default: Object
},
disabled: {
type: Boolean,
default: false
}
},
data() {
@@ -76,10 +80,19 @@ export default {
.toggle-btn.selected {
color: white;
}
.toggle-btn.selected:disabled {
color: white;
}
.toggle-btn.selected::before {
background-color: rgba(255, 255, 255, 0.1);
}
button.toggle-btn.selected:disabled::before {
background-color: rgba(255, 255, 255, 0.05);
}
button.toggle-btn:disabled::before {
background-color: rgba(0, 0, 0, 0.2);
}
button.toggle-btn:disabled {
cursor: not-allowed;
}
</style>

View File

@@ -31,7 +31,7 @@
</div>
</div>
</trix-toolbar>
<trix-editor :toolbar="toolbarId" :contenteditable="!disabledEditor" :class="['trix-content']" ref="trix" :input="computedId" :placeholder="placeholder" @trix-change="handleContentChange" @trix-initialize="handleInitialize" @trix-focus="processTrixFocus" @trix-blur="processTrixBlur" />
<trix-editor :toolbar="toolbarId" :contenteditable="!disabledEditor" :class="['trix-content']" ref="trix" :input="computedId" :placeholder="placeholder" @trix-change="handleContentChange" @trix-initialize="handleInitialize" @trix-focus="processTrixFocus" @trix-blur="processTrixBlur" @trix-attachment-add="handleAttachmentAdd" />
<input type="hidden" :name="inputName" :id="computedId" :value="editorContent" />
</div>
</template>
@@ -316,6 +316,12 @@ export default {
if (this.$refs.trix && this.$refs.trix.blur) {
this.$refs.trix.blur()
}
},
handleAttachmentAdd(event) {
// Prevent pasting in images from the browser
if (!event.attachment.file) {
event.attachment.remove()
}
}
},
mounted() {

View File

@@ -0,0 +1,211 @@
<template>
<div class="w-full py-2">
<div class="flex -mb-px">
<button type="button" :disabled="disabled" class="w-1/2 h-8 rounded-tl-md relative border border-black-200 flex items-center justify-center disabled:cursor-not-allowed" :class="!showAdvancedView ? 'text-white bg-bg hover:bg-bg/60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary/70 hover:bg-primary/60'" @click="showAdvancedView = false">
<p class="text-sm">{{ $strings.HeaderPresets }}</p>
</button>
<button type="button" :disabled="disabled" class="w-1/2 h-8 rounded-tr-md relative border border-black-200 flex items-center justify-center -ml-px disabled:cursor-not-allowed" :class="showAdvancedView ? 'text-white bg-bg hover:bg-bg/60 border-b-bg' : 'text-gray-400 hover:text-gray-300 bg-primary/70 hover:bg-primary/60'" @click="showAdvancedView = true">
<p class="text-sm">{{ $strings.HeaderAdvanced }}</p>
</button>
</div>
<div class="p-4 md:p-8 border border-black-200 rounded-b-md mr-px bg-bg">
<template v-if="!showAdvancedView">
<div class="flex flex-wrap gap-4 sm:gap-8 justify-start sm:justify-center">
<div class="flex flex-col items-start gap-2">
<p class="text-sm w-40">{{ $strings.LabelCodec }}</p>
<ui-toggle-btns v-model="selectedCodec" :items="codecItems" :disabled="disabled" />
<p class="text-xs text-gray-300">
{{ $strings.LabelCurrently }} <span class="text-white">{{ currentCodec }}</span> <span v-if="isCodecsDifferent" class="text-warning">(mixed)</span>
</p>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm w-40">{{ $strings.LabelBitrate }}</p>
<ui-toggle-btns v-model="selectedBitrate" :items="bitrateItems" :disabled="disabled" />
<p class="text-xs text-gray-300">
{{ $strings.LabelCurrently }} <span class="text-white">{{ currentBitrate }} KB/s</span>
</p>
</div>
<div class="flex flex-col items-start gap-2">
<p class="text-sm w-40">{{ $strings.LabelChannels }}</p>
<ui-toggle-btns v-model="selectedChannels" :items="channelsItems" :disabled="disabled" />
<p class="text-xs text-gray-300">
{{ $strings.LabelCurrently }} <span class="text-white">{{ currentChannels }} ({{ currentChanelLayout }})</span>
</p>
</div>
</div>
</template>
<template v-else>
<div>
<div class="flex flex-wrap gap-4 sm:gap-8 justify-start sm:justify-center mb-4">
<div class="w-40">
<ui-text-input-with-label v-model="customCodec" :label="$strings.LabelAudioCodec" :disabled="disabled" @input="customCodecChanged" />
</div>
<div class="w-40">
<ui-text-input-with-label v-model="customBitrate" :label="$strings.LabelAudioBitrate" :disabled="disabled" @input="customBitrateChanged" />
</div>
<div class="w-40">
<ui-text-input-with-label v-model="customChannels" :label="$strings.LabelAudioChannels" type="number" :disabled="disabled" @input="customChannelsChanged" />
</div>
</div>
<p class="text-xs sm:text-sm text-warning sm:text-center">{{ $strings.LabelEncodingWarningAdvancedSettings }}</p>
</div>
</template>
</div>
</div>
</template>
<script>
export default {
props: {
audioTracks: {
type: Array,
default: () => []
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {
showAdvancedView: false,
selectedCodec: 'aac',
selectedBitrate: '128k',
selectedChannels: 2,
customCodec: 'aac',
customBitrate: '128k',
customChannels: 2,
currentCodec: '',
currentBitrate: '',
currentChannels: '',
currentChanelLayout: '',
isCodecsDifferent: false
}
},
computed: {
codecItems() {
return [
{
text: 'Copy',
value: 'copy'
},
{
text: 'AAC',
value: 'aac'
},
{
text: 'OPUS',
value: 'opus'
}
]
},
bitrateItems() {
return [
{
text: '32k',
value: '32k'
},
{
text: '64k',
value: '64k'
},
{
text: '128k',
value: '128k'
},
{
text: '192k',
value: '192k'
}
]
},
channelsItems() {
return [
{
text: '1 (mono)',
value: 1
},
{
text: '2 (stereo)',
value: 2
}
]
}
},
methods: {
customBitrateChanged(val) {
localStorage.setItem('embedMetadataBitrate', val)
},
customChannelsChanged(val) {
localStorage.setItem('embedMetadataChannels', val)
},
customCodecChanged(val) {
localStorage.setItem('embedMetadataCodec', val)
},
getEncodingOptions() {
return {
codec: this.selectedCodec || 'aac',
bitrate: this.selectedBitrate || '128k',
channels: this.selectedChannels || 2
}
},
setPreset() {
// If already AAC and not mixed, set copy
if (this.currentCodec === 'aac' && !this.isCodecsDifferent) {
this.selectedCodec = 'copy'
} else {
this.selectedCodec = 'aac'
}
if (!this.currentBitrate) {
this.selectedBitrate = '128k'
} else {
// Find closest bitrate rounding up
const bitratesToMatch = [32, 64, 128, 192]
const closestBitrate = bitratesToMatch.find((bitrate) => bitrate >= this.currentBitrate) || 192
this.selectedBitrate = closestBitrate + 'k'
}
if (!this.currentChannels || isNaN(this.currentChannels)) {
this.selectedChannels = 2
} else {
// Either 1 or 2
this.selectedChannels = Math.max(Math.min(Number(this.currentChannels), 2), 1)
}
},
setCurrentValues() {
if (this.audioTracks.length === 0) return
this.currentChannels = this.audioTracks[0].channels
this.currentChanelLayout = this.audioTracks[0].channelLayout
this.currentCodec = this.audioTracks[0].codec
let totalBitrate = 0
for (const track of this.audioTracks) {
const trackBitrate = !isNaN(track.bitRate) ? track.bitRate : 0
totalBitrate += trackBitrate
if (track.channels > this.currentChannels) this.currentChannels = track.channels
if (track.codec !== this.currentCodec) {
console.warn('Audio track codec is different from the first track', track.codec)
this.isCodecsDifferent = true
}
}
this.currentBitrate = Math.round(totalBitrate / this.audioTracks.length / 1000)
},
init() {
this.customBitrate = localStorage.getItem('embedMetadataBitrate') || '128k'
this.customChannels = localStorage.getItem('embedMetadataChannels') || 2
this.customCodec = localStorage.getItem('embedMetadataCodec') || 'aac'
this.setCurrentValues()
this.setPreset()
}
},
mounted() {
this.init()
}
}
</script>

View File

@@ -2,7 +2,7 @@
<div>
<ui-multi-select-query-input v-model="seriesItems" text-key="displayName" :label="$strings.LabelSeries" :disabled="disabled" readonly show-edit @edit="editSeriesItem" @add="addNewSeries" />
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" @submit="submitSeriesForm" />
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" :original-series-sequence="originalSeriesSequence" @submit="submitSeriesForm" />
</div>
</template>
@@ -18,6 +18,7 @@ export default {
data() {
return {
selectedSeries: null,
originalSeriesSequence: null,
showSeriesForm: false
}
},
@@ -59,6 +60,7 @@ export default {
..._series
}
this.originalSeriesSequence = _series.sequence
this.showSeriesForm = true
},
addNewSeries() {
@@ -68,6 +70,7 @@ export default {
sequence: ''
}
this.originalSeriesSequence = null
this.showSeriesForm = true
},
submitSeriesForm() {

View File

@@ -19,7 +19,9 @@ describe('AuthorCard', () => {
const mocks = {
$strings: {
LabelBooks: 'Books',
ButtonQuickMatch: 'Quick Match'
ButtonQuickMatch: 'Quick Match',
ToastAuthorUpdateSuccess: 'Author updated',
ToastAuthorUpdateSuccessNoImageFound: 'Author updated (no image found)'
},
$store: {
getters: {
@@ -167,7 +169,7 @@ describe('AuthorCard', () => {
cy.get('&match').click()
cy.get('&spinner').should('be.hidden')
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author John Doe was updated (no image found)')
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author updated (no image found)')
cy.get('@error').should('not.have.been.called')
cy.get('@info').should('not.have.been.called')
})
@@ -189,7 +191,7 @@ describe('AuthorCard', () => {
cy.get('&match').click()
cy.get('&spinner').should('be.hidden')
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author John Doe was updated')
cy.get('@success').should('have.been.calledOnceWithExactly', 'Author updated')
cy.get('@error').should('not.have.been.called')
cy.get('@info').should('not.have.been.called')
})

View File

@@ -49,6 +49,7 @@ function createMountOptions() {
'libraries/getLibraryProvider': () => 'audible.us',
'libraries/getBookCoverAspectRatio': 1,
'globals/getLibraryItemCoverSrc': () => 'https://my.server.com/book_placeholder.jpg',
'globals/getPlaceholderCoverSrc': 'https://my.server.com/book_placeholder.jpg',
getLibraryItemsStreaming: () => null,
getIsMediaQueued: () => false,
getIsStreamingFromDifferentLibrary: () => false
@@ -172,6 +173,7 @@ describe('LazyBookCard', () => {
})
it('shows titleImageNotReady and sets opacity 0 on coverImage when image not ready', () => {
mountOptions.mocks.$store.getters['globals/getLibraryItemCoverSrc'] = () => 'https://my.server.com/notfound.jpg'
cy.mount(LazyBookCard, mountOptions)
cy.get('&titleImageNotReady').should('be.visible')
@@ -257,7 +259,7 @@ describe('LazyBookCard', () => {
cy.get('#book-card-0').trigger('mouseover')
cy.get('&titleImageNotReady').should('be.hidden')
cy.get('&seriesNameOverlay').should('be.visible').and('have.text', 'Middle Earth Chronicles')
cy.get('&seriesNameOverlay').should('be.visible').and('have.text', 'The Lord of the Rings')
})
it('shows the seriesSequenceList when collapsed series has a sequence list', () => {

View File

@@ -30,6 +30,14 @@ describe('LazySeriesCard', () => {
}
const mocks = {
$getString: (id, args) => {
switch (id) {
case 'LabelAddedDate':
return `Added ${args[0]}`
default:
return null
}
},
$store: {
getters: {
'user/getUserCanUpdate': true,

View File

@@ -183,7 +183,7 @@ export default {
this.$store.commit('libraries/updateFilterDataWithItem', libraryItem)
},
libraryItemUpdated(libraryItem) {
if (this.$store.state.selectedLibraryItem && this.$store.state.selectedLibraryItem.id === libraryItem.id) {
if (this.$store.state.selectedLibraryItem?.id === libraryItem.id) {
this.$store.commit('setSelectedLibraryItem', libraryItem)
if (this.$store.state.globals.selectedEpisode && libraryItem.mediaType === 'podcast') {
const episode = libraryItem.media.episodes.find((ep) => ep.id === this.$store.state.globals.selectedEpisode.id)
@@ -192,6 +192,9 @@ export default {
}
}
}
if (this.$store.state.streamLibraryItem?.id === libraryItem.id) {
this.$store.commit('updateStreamLibraryItem', libraryItem)
}
this.$eventBus.$emit(`${libraryItem.id}_updated`, libraryItem)
this.$store.commit('libraries/updateFilterDataWithItem', libraryItem)
},

View File

@@ -3,7 +3,6 @@ import LazyBookCard from '@/components/cards/LazyBookCard'
import LazySeriesCard from '@/components/cards/LazySeriesCard'
import LazyCollectionCard from '@/components/cards/LazyCollectionCard'
import LazyPlaylistCard from '@/components/cards/LazyPlaylistCard'
import LazyAlbumCard from '@/components/cards/LazyAlbumCard'
import AuthorCard from '@/components/cards/AuthorCard'
export default {
@@ -20,7 +19,6 @@ export default {
if (this.entityName === 'series') return Vue.extend(LazySeriesCard)
if (this.entityName === 'collections') return Vue.extend(LazyCollectionCard)
if (this.entityName === 'playlists') return Vue.extend(LazyPlaylistCard)
if (this.entityName === 'albums') return Vue.extend(LazyAlbumCard)
if (this.entityName === 'authors') return Vue.extend(AuthorCard)
return Vue.extend(LazyBookCard)
},
@@ -28,7 +26,6 @@ export default {
if (this.entityName === 'series') return 'cards-lazy-series-card'
if (this.entityName === 'collections') return 'cards-lazy-collection-card'
if (this.entityName === 'playlists') return 'cards-lazy-playlist-card'
if (this.entityName === 'albums') return 'cards-lazy-album-card'
if (this.entityName === 'authors') return 'cards-author-card'
return 'cards-lazy-book-card'
},

View File

@@ -1,12 +1,12 @@
{
"name": "audiobookshelf-client",
"version": "2.20.0",
"version": "2.24.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "audiobookshelf-client",
"version": "2.20.0",
"version": "2.24.0",
"license": "ISC",
"dependencies": {
"@nuxtjs/axios": "^5.13.6",

View File

@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-client",
"version": "2.20.0",
"version": "2.24.0",
"buildNumber": 1,
"description": "Self-hosted audiobook and podcast client",
"main": "index.js",

View File

@@ -1,6 +1,6 @@
<template>
<div id="page-wrapper" class="bg-bg page overflow-y-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
<div class="flex items-center py-4 px-2 md:px-0 max-w-7xl mx-auto">
<div class="flex items-center py-4 px-4 max-w-7xl mx-auto">
<nuxt-link :to="`/item/${libraryItem.id}`" class="hover:underline">
<h1 class="text-lg lg:text-xl">{{ title }}</h1>
</nuxt-link>
@@ -12,7 +12,7 @@
<p class="text-base font-mono ml-4 hidden md:block">{{ $secondsToTimestamp(mediaDurationRounded) }}</p>
</div>
<div class="flex flex-wrap-reverse justify-center py-4 px-2">
<div class="flex flex-wrap-reverse lg:flex-nowrap justify-center py-4 px-4">
<div class="w-full max-w-3xl py-4">
<div class="flex items-center">
<div class="w-12 hidden lg:block" />
@@ -23,8 +23,8 @@
</div>
<div class="flex items-center mb-3 py-1 -mx-1">
<div class="w-12 hidden lg:block" />
<ui-btn v-if="chapters.length" color="bg-primary" small class="mx-1" @click.stop="removeAllChaptersClick">{{ $strings.ButtonRemoveAll }}</ui-btn>
<ui-btn v-if="newChapters.length > 1" :color="showShiftTimes ? 'bg' : 'primary'" class="mx-1" small @click="showShiftTimes = !showShiftTimes">{{ $strings.ButtonShiftTimes }}</ui-btn>
<ui-btn v-if="chapters.length" color="bg-primary" small class="mx-1 whitespace-nowrap" @click.stop="removeAllChaptersClick">{{ $strings.ButtonRemoveAll }}</ui-btn>
<ui-btn v-if="newChapters.length > 1" :color="showShiftTimes ? 'bg-bg' : 'bg-primary'" class="mx-1 whitespace-nowrap" small @click="showShiftTimes = !showShiftTimes">{{ $strings.ButtonShiftTimes }}</ui-btn>
<ui-btn color="bg-primary" small :class="{ 'mx-1': newChapters.length > 1 }" @click="showFindChaptersModal = true">{{ $strings.ButtonLookup }}</ui-btn>
<div class="grow" />
<ui-btn v-if="hasChanges" small class="mx-1" @click.stop="resetChapters">{{ $strings.ButtonReset }}</ui-btn>
@@ -65,7 +65,7 @@
<ui-time-picker v-else class="text-xs" v-model="chapter.start" :show-three-digit-hour="mediaDuration >= 360000" @change="checkChapters" />
</div>
<div class="grow px-1">
<ui-text-input v-model="chapter.title" @change="checkChapters" class="text-xs" />
<ui-text-input v-model="chapter.title" @change="checkChapters" class="text-xs min-w-52" />
</div>
<div class="w-32 min-w-32 px-2 py-1">
<div class="flex items-center">
@@ -141,10 +141,22 @@
</div>
</template>
<div class="w-full h-full max-h-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative">
<div v-if="!chapterData" class="flex p-20">
<ui-text-input-with-label v-model.trim="asinInput" label="ASIN" />
<ui-dropdown v-model="regionInput" :label="$strings.LabelRegion" small :items="audibleRegions" class="w-32 mx-1" />
<ui-btn small color="bg-primary" class="mt-5" @click="findChapters">{{ $strings.ButtonSearch }}</ui-btn>
<div v-if="!chapterData" class="flex flex-col items-center justify-center p-20">
<div class="relative">
<div class="flex items-end space-x-2">
<ui-text-input-with-label v-model.trim="asinInput" label="ASIN" class="flex-grow" />
<ui-dropdown v-model="regionInput" :label="$strings.LabelRegion" small :items="audibleRegions" class="w-20 max-w-20" />
<ui-btn color="bg-primary" @click="findChapters">{{ $strings.ButtonSearch }}</ui-btn>
</div>
<div class="mt-4">
<ui-checkbox v-model="removeBranding" :label="$strings.LabelRemoveAudibleBranding" small checkbox-bg="bg" label-class="pl-2 text-base text-sm" @click="toggleRemoveBranding" />
</div>
<div class="absolute left-0 mt-1.5 text-error text-s h-5">
<p v-if="asinError">{{ asinError }}</p>
<p v-if="asinError">{{ $strings.MessageAsinCheck }}</p>
</div>
<div class="invisible mt-1 text-xs"></div>
</div>
</div>
<div v-else class="w-full p-4">
<div class="flex justify-between mb-4">
@@ -221,6 +233,11 @@ export default {
return redirect('/')
}
// Fetch and set library if this items library does not match the current
if (store.state.libraries.currentLibraryId !== libraryItem.libraryId || !store.state.libraries.filterData) {
await store.dispatch('libraries/fetch', libraryItem.libraryId)
}
var previousRoute = from ? from.fullPath : null
if (from && from.path === '/login') previousRoute = null
return {
@@ -244,6 +261,8 @@ export default {
findingChapters: false,
showFindChaptersModal: false,
chapterData: null,
asinError: null,
removeBranding: false,
showSecondInputs: false,
audibleRegions: ['US', 'CA', 'UK', 'AU', 'FR', 'DE', 'JP', 'IT', 'IN', 'ES'],
hasChanges: false
@@ -305,6 +324,9 @@ export default {
this.checkChapters()
},
toggleRemoveBranding() {
this.removeBranding = !this.removeBranding
},
shiftChapterTimes() {
if (!this.shiftAmount || isNaN(this.shiftAmount) || this.newChapters.length <= 1) {
return
@@ -314,12 +336,12 @@ export default {
const lastChapter = this.newChapters[this.newChapters.length - 1]
if (lastChapter.start + amount > this.mediaDurationRounded) {
this.$toast.error('Invalid shift amount. Last chapter start time would extend beyond the duration of this audiobook.')
this.$toast.error(this.$strings.ToastChaptersInvalidShiftAmountLast)
return
}
if (this.newChapters[0].end + amount <= 0) {
this.$toast.error('Invalid shift amount. First chapter would have zero or negative length.')
if (this.newChapters[1].start + amount <= 0) {
this.$toast.error(this.$strings.ToastChaptersInvalidShiftAmountStart)
return
}
@@ -541,17 +563,17 @@ export default {
this.findingChapters = true
this.chapterData = null
this.asinError = null // used to show warning about audible vs amazon ASIN
this.$axios
.$get(`/api/search/chapters?asin=${this.asinInput}&region=${this.regionInput}`)
.then((data) => {
this.findingChapters = false
if (data.error) {
this.$toast.error(data.error)
this.showFindChaptersModal = false
this.asinError = this.$getString(data.stringKey)
} else {
console.log('Chapter data', data)
this.chapterData = data
this.chapterData = this.removeBranding ? this.removeBrandingFromData(data) : data
}
})
.catch((error) => {
@@ -561,6 +583,37 @@ export default {
this.showFindChaptersModal = false
})
},
removeBrandingFromData(data) {
if (!data) return data
try {
const introDuration = data.brandIntroDurationMs
const outroDuration = data.brandOutroDurationMs
for (let i = 0; i < data.chapters.length; i++) {
const chapter = data.chapters[i]
if (chapter.startOffsetMs < introDuration) {
// This should never happen, as the intro is not longer than the first chapter
// If this happens set to the next second
// Will be 0 for the first chapter anayways
chapter.startOffsetMs = i * 1000
chapter.startOffsetSec = i
} else {
chapter.startOffsetMs -= introDuration
chapter.startOffsetSec = Math.floor(chapter.startOffsetMs / 1000)
}
}
const lastChapter = data.chapters[data.chapters.length - 1]
// If there is an outro that's in the outro duration, remove it
if (lastChapter && lastChapter.lengthMs <= outroDuration) {
data.chapters.pop()
}
return data
} catch {
return data
}
},
resetChapters() {
const payload = {
message: this.$strings.MessageResetChaptersConfirm,

View File

@@ -103,6 +103,12 @@ export default {
console.error('No need to edit library item that is 1 file...')
return redirect('/')
}
// Fetch and set library if this items library does not match the current
if (store.state.libraries.currentLibraryId !== libraryItem.libraryId || !store.state.libraries.filterData) {
await store.dispatch('libraries/fetch', libraryItem.libraryId)
}
return {
libraryItem,
files: libraryItem.media.audioFiles ? libraryItem.media.audioFiles.map((af) => ({ ...af, include: !af.exclude })) : []

View File

@@ -2,7 +2,14 @@
<div id="page-wrapper" class="bg-bg page p-8 overflow-auto relative" :class="streamLibraryItem ? 'streaming' : ''">
<div class="flex items-center justify-center mb-6">
<div class="w-full max-w-2xl">
<p class="text-2xl mb-2">{{ $strings.HeaderAudiobookTools }}</p>
<div class="flex items-center mb-4">
<nuxt-link :to="`/item/${libraryItem.id}`" class="hover:underline">
<h1 class="text-lg lg:text-xl">{{ mediaMetadata.title }}</h1>
</nuxt-link>
<button class="w-7 h-7 flex items-center justify-center mx-4 hover:scale-110 duration-100 transform text-gray-200 hover:text-white" @click="editItem">
<span class="material-symbols text-base">edit</span>
</button>
</div>
</div>
<div class="w-full max-w-2xl">
<div class="flex justify-end">
@@ -13,13 +20,13 @@
<div class="flex justify-center mb-2">
<div class="w-full max-w-2xl">
<p class="text-xl">{{ $strings.HeaderMetadataToEmbed }}</p>
<p class="text-lg">{{ $strings.HeaderMetadataToEmbed }}</p>
</div>
<div class="w-full max-w-2xl"></div>
</div>
<div class="flex justify-center flex-wrap">
<div class="w-full max-w-2xl border border-white/10 bg-bg mx-2">
<div class="flex justify-center flex-wrap lg:flex-nowrap gap-4">
<div class="w-full max-w-2xl border border-white/10 bg-bg">
<div class="flex py-2 px-4">
<div class="w-1/3 text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelMetaTag }}</div>
<div class="w-2/3 text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelValue }}</div>
@@ -35,7 +42,7 @@
</template>
</div>
</div>
<div class="w-full max-w-2xl border border-white/10 bg-bg mx-2">
<div class="w-full max-w-2xl border border-white/10 bg-bg">
<div class="flex py-2 px-4 bg-primary/25">
<div class="grow text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelChapterTitle }}</div>
<div class="w-24 text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelStart }}</div>
@@ -77,10 +84,6 @@
</div>
<!-- m4b embed action buttons -->
<div v-else class="w-full flex items-center mb-4">
<button :disabled="processing" class="text-sm uppercase text-gray-200 flex items-center pt-px pl-1 pr-2 hover:bg-white/5 rounded-md" @click="showEncodeOptions = !showEncodeOptions">
<span class="material-symbols text-xl">{{ showEncodeOptions || usingCustomEncodeOptions ? 'check_box' : 'check_box_outline_blank' }}</span> <span class="pl-1">{{ $strings.LabelUseAdvancedOptions }}</span>
</button>
<div class="grow" />
<ui-btn v-if="!isTaskFinished && processing" color="bg-error" :loading="isCancelingEncode" class="mr-2" @click.stop="cancelEncodeClick">{{ $strings.ButtonCancelEncode }}</ui-btn>
@@ -89,18 +92,16 @@
<p v-else class="text-success text-lg font-semibold">{{ $strings.MessageM4BFinished }}</p>
</div>
<!-- advanced encoding options -->
<div v-if="isM4BTool" class="overflow-hidden">
<transition name="slide">
<div v-if="showEncodeOptions || usingCustomEncodeOptions" class="mb-4 pb-4 border-b border-white/10">
<div class="flex flex-wrap -mx-2">
<ui-text-input-with-label ref="bitrateInput" v-model="encodingOptions.bitrate" :disabled="processing || isTaskFinished" :label="$strings.LabelAudioBitrate" class="m-2 max-w-40" @input="bitrateChanged" />
<ui-text-input-with-label ref="channelsInput" v-model="encodingOptions.channels" :disabled="processing || isTaskFinished" :label="$strings.LabelAudioChannels" class="m-2 max-w-40" @input="channelsChanged" />
<ui-text-input-with-label ref="codecInput" v-model="encodingOptions.codec" :disabled="processing || isTaskFinished" :label="$strings.LabelAudioCodec" class="m-2 max-w-40" @input="codecChanged" />
</div>
<p class="text-sm text-warning">{{ $strings.LabelEncodingWarningAdvancedSettings }}</p>
</div>
</transition>
<!-- show encoding options for running task -->
<div v-if="encodeTaskHasEncodingOptions" class="mb-4 pb-4 border-b border-white/10">
<div class="flex flex-wrap -mx-2">
<ui-text-input-with-label ref="bitrateInput" v-model="encodingOptions.bitrate" readonly :label="$strings.LabelAudioBitrate" class="m-2 max-w-40" @input="bitrateChanged" />
<ui-text-input-with-label ref="channelsInput" v-model="encodingOptions.channels" readonly :label="$strings.LabelAudioChannels" class="m-2 max-w-40" @input="channelsChanged" />
<ui-text-input-with-label ref="codecInput" v-model="encodingOptions.codec" readonly :label="$strings.LabelAudioCodec" class="m-2 max-w-40" @input="codecChanged" />
</div>
</div>
<div v-else-if="isM4BTool" class="mb-4">
<widgets-encoder-options-card ref="encoderOptionsCard" :audio-tracks="audioFiles" :disabled="processing || isTaskFinished" />
</div>
<div class="mb-4">
@@ -146,19 +147,29 @@
<div class="flex py-2 px-4 bg-primary/25">
<div class="w-10 text-xs font-semibold text-gray-200">#</div>
<div class="grow text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelFilename }}</div>
<div class="w-20 text-xs font-semibold uppercase text-gray-200 hidden lg:block">{{ $strings.LabelChannels }}</div>
<div class="w-16 text-xs font-semibold uppercase text-gray-200 hidden md:block">{{ $strings.LabelCodec }}</div>
<div class="w-16 text-xs font-semibold uppercase text-gray-200 hidden md:block">{{ $strings.LabelBitrate }}</div>
<div class="w-16 text-xs font-semibold uppercase text-gray-200">{{ $strings.LabelSize }}</div>
<div class="w-24"></div>
</div>
<template v-for="file in audioFiles">
<div :key="file.index" class="flex py-2 px-4 text-sm" :class="file.index % 2 === 0 ? 'bg-primary/25' : ''">
<div class="w-10">{{ file.index }}</div>
<div :key="file.index" class="flex py-2 px-4 text-xs sm:text-sm" :class="file.index % 2 === 0 ? 'bg-primary/25' : ''">
<div class="w-10 min-w-10">{{ file.index }}</div>
<div class="grow">
{{ file.metadata.filename }}
</div>
<div class="w-16 font-mono text-gray-200">
<div class="w-20 min-w-20 text-gray-200 hidden lg:block">{{ file.channels || 'unknown' }} ({{ file.channelLayout || 'unknown' }})</div>
<div class="w-16 min-w-16 text-gray-200 hidden md:block">
{{ file.codec || 'unknown' }}
</div>
<div class="w-16 min-w-16 text-gray-200 hidden md:block">
{{ $bytesPretty(file.bitRate || 0, 0) }}
</div>
<div class="w-16 min-w-16 text-gray-200">
{{ $bytesPretty(file.metadata.size) }}
</div>
<div class="w-24">
<div class="w-24 min-w-24">
<div class="flex justify-center">
<span v-if="audioFilesFinished[file.ino]" class="material-symbols text-xl text-success leading-none">check_circle</span>
<div v-else-if="audioFilesEncoding[file.ino]">
@@ -195,10 +206,15 @@ export default {
return redirect('/?error=invalid media type')
}
if (!libraryItem.media.audioFiles.length) {
cnosole.error('No audio files')
console.error('No audio files')
return redirect('/?error=no audio files')
}
// Fetch and set library if this items library does not match the current
if (store.state.libraries.currentLibraryId !== libraryItem.libraryId || !store.state.libraries.filterData) {
await store.dispatch('libraries/fetch', libraryItem.libraryId)
}
return {
libraryItem
}
@@ -209,7 +225,6 @@ export default {
metadataObject: null,
selectedTool: 'embed',
isCancelingEncode: false,
showEncodeOptions: false,
shouldBackupAudioFiles: true,
encodingOptions: {
bitrate: '128k',
@@ -258,9 +273,6 @@ export default {
audioFiles() {
return (this.media.audioFiles || []).filter((af) => !af.exclude)
},
isSingleM4b() {
return this.audioFiles.length === 1 && this.audioFiles[0].metadata.ext.toLowerCase() === '.m4b'
},
streamLibraryItem() {
return this.$store.state.streamLibraryItem
},
@@ -268,14 +280,10 @@ export default {
return this.media.chapters || []
},
availableTools() {
if (this.isSingleM4b) {
return [{ value: 'embed', text: this.$strings.LabelToolsEmbedMetadata }]
} else {
return [
{ value: 'embed', text: this.$strings.LabelToolsEmbedMetadata },
{ value: 'm4b', text: this.$strings.LabelToolsM4bEncoder }
]
}
return [
{ value: 'embed', text: this.$strings.LabelToolsEmbedMetadata },
{ value: 'm4b', text: this.$strings.LabelToolsM4bEncoder }
]
},
taskFailed() {
return this.isTaskFinished && this.task.isFailed
@@ -309,8 +317,8 @@ export default {
isMetadataEmbedQueued() {
return this.queuedEmbedLIds.some((lid) => lid === this.libraryItemId)
},
usingCustomEncodeOptions() {
return this.isM4BTool && this.encodeTask && this.encodeTask.data.encodeOptions && Object.keys(this.encodeTask.data.encodeOptions).length > 0
encodeTaskHasEncodingOptions() {
return this.isM4BTool && !!this.encodeTask?.data.encodeOptions && Object.keys(this.encodeTask.data.encodeOptions).length > 0
}
},
methods: {
@@ -346,19 +354,13 @@ export default {
if (this.$refs.channelsInput) this.$refs.channelsInput.blur()
if (this.$refs.codecInput) this.$refs.codecInput.blur()
let queryStr = ''
if (this.showEncodeOptions) {
const options = []
if (this.encodingOptions.bitrate) options.push(`bitrate=${this.encodingOptions.bitrate}`)
if (this.encodingOptions.channels) options.push(`channels=${this.encodingOptions.channels}`)
if (this.encodingOptions.codec) options.push(`codec=${this.encodingOptions.codec}`)
if (options.length) {
queryStr = `?${options.join('&')}`
}
}
const encodeOptions = this.$refs.encoderOptionsCard.getEncodingOptions()
const queryParams = new URLSearchParams(encodeOptions)
this.processing = true
this.$axios
.$post(`/api/tools/item/${this.libraryItemId}/encode-m4b${queryStr}`)
.$post(`/api/tools/item/${this.libraryItemId}/encode-m4b?${queryParams.toString()}`)
.then(() => {
console.log('Ab m4b merge started')
})
@@ -411,14 +413,10 @@ export default {
const shouldBackupAudioFiles = localStorage.getItem('embedMetadataShouldBackup')
this.shouldBackupAudioFiles = shouldBackupAudioFiles != 0
if (this.usingCustomEncodeOptions) {
if (this.encodeTaskHasEncodingOptions) {
if (this.encodeTask.data.encodeOptions.bitrate) this.encodingOptions.bitrate = this.encodeTask.data.encodeOptions.bitrate
if (this.encodeTask.data.encodeOptions.channels) this.encodingOptions.channels = this.encodeTask.data.encodeOptions.channels
if (this.encodeTask.data.encodeOptions.codec) this.encodingOptions.codec = this.encodeTask.data.encodeOptions.codec
} else {
this.encodingOptions.bitrate = localStorage.getItem('embedMetadataBitrate') || '128k'
this.encodingOptions.channels = localStorage.getItem('embedMetadataChannels') || '2'
this.encodingOptions.codec = localStorage.getItem('embedMetadataCodec') || 'aac'
}
},
fetchMetadataEmbedObject() {
@@ -433,10 +431,24 @@ export default {
},
taskUpdated(task) {
this.processing = !task.isFinished
},
editItem() {
this.$store.commit('showEditModal', this.libraryItem)
},
libraryItemUpdated(libraryItem) {
if (libraryItem.id === this.libraryItem.id) {
this.libraryItem = libraryItem
this.fetchMetadataEmbedObject()
}
}
},
mounted() {
this.init()
this.$eventBus.$on(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
},
beforeDestroy() {
this.$eventBus.$off(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
}
}
</script>

View File

@@ -122,7 +122,8 @@
</div>
</transition>
</div>
<div class="w-full flex items-center justify-end p-4">
<div class="w-full flex items-center justify-between p-4">
<p v-if="enableOpenIDAuth" class="text-sm text-warning">{{ $strings.MessageAuthenticationOIDCChangesRestart }}</p>
<ui-btn color="bg-success" :padding-x="8" small class="text-base" :loading="savingSettings" @click="saveSettings">{{ $strings.ButtonSave }}</ui-btn>
</div>
</app-settings-content>

View File

@@ -32,7 +32,7 @@
<p class="truncate">{{ feed.meta.title }}</p>
</td>
<!-- -->
<td class="hidden xl:table-cell">
<td class="hidden xl:table-cell max-w-48">
<p class="truncate">{{ feed.slug }}</p>
</td>
<!-- -->
@@ -57,7 +57,7 @@
</td>
<!-- -->
<td class="text-center">
<ui-icon-btn icon="delete" class="mx-0.5" :size="7" bg-color="bg-error" outlined @click.stop="deleteFeedClick(feed)" />
<ui-icon-btn icon="delete" class="mx-0.5 text-white/70" borderless :size="7" iconFontSize="1.25rem" outlined @click.stop="deleteFeedClick(feed)" />
</td>
</tr>
</table>

View File

@@ -91,15 +91,15 @@
{{ isMissing ? $strings.LabelMissing : $strings.LabelIncomplete }}
</ui-btn>
<ui-tooltip v-if="showQueueBtn" :text="isQueued ? $strings.ButtonQueueRemoveItem : $strings.ButtonQueueAddItem" direction="top">
<ui-icon-btn :icon="isQueued ? 'playlist_add_check' : 'playlist_play'" :bg-color="isQueued ? 'bg-primary' : 'bg-success/60'" class="mx-0.5" :class="isQueued ? 'text-success' : ''" @click="queueBtnClick" />
</ui-tooltip>
<ui-btn v-if="showReadButton" color="bg-info" :padding-x="4" small class="flex items-center h-9 mr-2" @click="openEbook">
<span class="material-symbols text-2xl -ml-2 pr-2 text-white" aria-hidden="true">auto_stories</span>
{{ $strings.ButtonRead }}
</ui-btn>
<ui-tooltip v-if="showQueueBtn" :text="isQueued ? $strings.ButtonQueueRemoveItem : $strings.ButtonQueueAddItem" direction="top">
<ui-icon-btn :icon="isQueued ? 'playlist_add_check' : 'playlist_play'" :bg-color="isQueued ? 'bg-primary' : 'bg-success/60'" class="mx-0.5" :class="isQueued ? 'text-success' : ''" @click="queueBtnClick" />
</ui-tooltip>
<ui-tooltip v-if="userCanUpdate" :text="$strings.LabelEdit" direction="top">
<ui-icon-btn icon="&#xe3c9;" outlined class="mx-0.5" :aria-label="$strings.LabelEdit" @click="editClick" />
</ui-tooltip>
@@ -819,6 +819,17 @@ export default {
-webkit-line-clamp: 4;
max-height: calc(6 * 1lh);
}
/* Safari-specific fix for the description clamping */
@supports (-webkit-touch-callout: none) {
#item-description {
position: relative;
display: block;
overflow: hidden;
max-height: calc(6 * 1lh);
}
}
#item-description.show-full {
-webkit-line-clamp: unset;
max-height: 999rem;

View File

@@ -249,7 +249,7 @@ export default {
},
async loadRecentEpisodes(page = 0) {
this.processing = true
const episodePayload = await this.$axios.$get(`/api/libraries/${this.libraryId}/recent-episodes?limit=25&page=${page}`).catch((error) => {
const episodePayload = await this.$axios.$get(`/api/libraries/${this.libraryId}/recent-episodes?limit=50&page=${page}`).catch((error) => {
console.error('Failed to get recent episodes', error)
this.$toast.error(this.$strings.ToastFailedToLoadData)
return null

View File

@@ -22,6 +22,7 @@ export default {
})
results = {
podcasts: results?.podcast || [],
episodes: results?.episodes || [],
books: results?.book || [],
authors: results?.authors || [],
series: results?.series || [],
@@ -61,6 +62,7 @@ export default {
})
this.results = {
podcasts: results?.podcast || [],
episodes: results?.episodes || [],
books: results?.book || [],
authors: results?.authors || [],
series: results?.series || [],

View File

@@ -89,14 +89,16 @@
<script>
export default {
asyncData({ redirect, store }) {
async asyncData({ redirect, store, params }) {
if (!store.getters['user/getIsAdminOrUp']) {
redirect('/')
return
}
if (!store.state.libraries.currentLibraryId) {
return redirect('/config')
const libraryId = params.library
const library = await store.dispatch('libraries/fetch', libraryId)
if (!library) {
return redirect(`/oops?message=Library "${libraryId}" not found`)
}
return {}
},

View File

@@ -1,5 +1,5 @@
<template>
<div class="w-full h-dvh max-h-dvh overflow-hidden" :style="{ backgroundColor: coverRgb }">
<div class="w-full max-w-full h-dvh max-h-dvh overflow-hidden" :style="{ backgroundColor: coverRgb }">
<div class="w-screen h-screen absolute inset-0 pointer-events-none" style="background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(38, 38, 38, 1) 80%)"></div>
<div class="absolute inset-0 w-screen h-dvh flex items-center justify-center z-10">
<div class="w-full p-2 sm:p-4 md:p-8">
@@ -64,7 +64,7 @@ export default {
return this.mediaItemShare.playbackSession
},
coverUrl() {
if (!this.playbackSession.coverPath) return `${this.$config.routerBasePath}/book_placeholder.jpg`
if (!this.playbackSession.coverPath) return this.$store.getters['globals/getPlaceholderCoverSrc']
return `${this.$config.routerBasePath}/public/share/${this.mediaItemShare.slug}/cover`
},
downloadUrl() {
@@ -335,8 +335,11 @@ export default {
}
},
resize() {
this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight
setTimeout(() => {
this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight
this.$store.commit('globals/updateWindowSize', { width: window.innerWidth, height: window.innerHeight })
}, 100)
},
playerError(error) {
console.error('Player error', error)

View File

@@ -316,9 +316,8 @@ export default {
.$post('/api/upload', form)
.then(() => true)
.catch((error) => {
console.error('Failed', error)
var errorMessage = error.response && error.response.data ? error.response.data : 'Oops, something went wrong...'
this.$toast.error(errorMessage)
console.error('Failed to upload item', error)
this.$toast.error(error.response?.data || 'Oops, something went wrong...')
return false
})
},
@@ -360,15 +359,14 @@ export default {
// Check if path already exists before starting upload
// uploading fails if path already exists
for (const item of items) {
const filepath = Path.join(this.selectedFolder.fullPath, item.directory)
const exists = await this.$axios
.$post(`/api/filesystem/pathexists`, { filepath, directory: item.directory, folderPath: this.selectedFolder.fullPath })
.$post(`/api/filesystem/pathexists`, { directory: item.directory, folderPath: this.selectedFolder.fullPath })
.then((data) => {
if (data.exists) {
if (data.libraryItemTitle) {
this.$toast.error(this.$getString('ToastUploaderItemExistsInSubdirectoryError', [data.libraryItemTitle]))
} else {
this.$toast.error(this.$getString('ToastUploaderFilepathExistsError', [filepath]))
this.$toast.error(this.$getString('ToastUploaderFilepathExistsError', [Path.join(this.selectedFolder.fullPath, item.directory)]))
}
}
return data.exists
@@ -382,13 +380,9 @@ export default {
}
}
let itemsUploaded = 0
let itemsFailed = 0
for (const item of itemsToUpload) {
this.updateItemCardStatus(item.index, 'uploading')
const result = await this.uploadItem(item)
if (result) itemsUploaded++
else itemsFailed++
this.updateItemCardStatus(item.index, result ? 'success' : 'failed')
}
this.processing = false

View File

@@ -1,5 +1,5 @@
export default class AudioTrack {
constructor(track, userToken, routerBasePath) {
constructor(track, sessionId, routerBasePath) {
this.index = track.index || 0
this.startOffset = track.startOffset || 0 // Total time of all previous tracks
this.duration = track.duration || 0
@@ -8,28 +8,29 @@ export default class AudioTrack {
this.mimeType = track.mimeType
this.metadata = track.metadata || {}
this.userToken = userToken
this.sessionId = sessionId
this.routerBasePath = routerBasePath || ''
if (this.contentUrl?.startsWith('/hls')) {
this.sessionTrackUrl = this.contentUrl
} else {
this.sessionTrackUrl = `/public/session/${sessionId}/track/${this.index}`
}
}
/**
* Used for CastPlayer
*/
get fullContentUrl() {
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 `${process.env.serverUrl}${this.sessionTrackUrl}`
}
return `${window.location.origin}${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
return `${window.location.origin}${this.routerBasePath}${this.sessionTrackUrl}`
}
/**
* Used for LocalPlayer
*/
get relativeContentUrl() {
if (!this.contentUrl || this.contentUrl.startsWith('http')) return this.contentUrl
return `${this.routerBasePath}${this.contentUrl}?token=${this.userToken}`
return `${this.routerBasePath}${this.sessionTrackUrl}`
}
}

View File

@@ -37,9 +37,6 @@ export default class PlayerHandler {
get isPlayingLocalItem() {
return this.libraryItem && this.player instanceof LocalAudioPlayer
}
get userToken() {
return this.ctx.$store.getters['user/getToken']
}
get playerPlaying() {
return this.playerState === 'PLAYING'
}
@@ -226,7 +223,7 @@ export default class PlayerHandler {
console.log('[PlayerHandler] Preparing Session', session)
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken, this.ctx.$config.routerBasePath))
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, session.id, this.ctx.$config.routerBasePath))
this.ctx.playerLoading = true
this.isHlsTranscode = true

View File

@@ -1,6 +1,6 @@
const SupportedFileTypes = {
image: ['png', 'jpg', 'jpeg', 'webp'],
audio: ['m4b', 'mp3', 'm4a', 'flac', 'opus', 'ogg', 'oga', 'mp4', 'aac', 'wma', 'aiff', 'wav', 'webm', 'webma', 'mka', 'awb', 'caf', 'mpeg', 'mpg'],
audio: ['m4b', 'mp3', 'm4a', 'flac', 'opus', 'ogg', 'oga', 'mp4', 'aac', 'wma', 'aiff', 'aif','wav', 'webm', 'webma', 'mka', 'awb', 'caf', 'mpeg', 'mpg'],
ebook: ['epub', 'pdf', 'mobi', 'azw3', 'cbr', 'cbz'],
info: ['nfo'],
text: ['txt'],

View File

@@ -5,6 +5,7 @@ import { supplant } from './utils'
const defaultCode = 'en-us'
const languageCodeMap = {
ar: { label: 'عربي', dateFnsLocale: 'ar' },
bg: { label: 'Български', dateFnsLocale: 'bg' },
bn: { label: 'বাংলা', dateFnsLocale: 'bn' },
ca: { label: 'Català', dateFnsLocale: 'ca' },

View File

@@ -87,7 +87,7 @@ export const getters = {
getLibraryItemCoverSrc:
(state, getters, rootState, rootGetters) =>
(libraryItem, placeholder = null, raw = false) => {
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
if (!placeholder) placeholder = getters.getPlaceholderCoverSrc
if (!libraryItem) return placeholder
const media = libraryItem.media
if (!media?.coverPath || media.coverPath === placeholder) return placeholder
@@ -95,7 +95,6 @@ export const getters = {
// Absolute URL covers (should no longer be used)
if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
const userToken = rootGetters['user/getToken']
const lastUpdate = libraryItem.updatedAt || Date.now()
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?ts=${lastUpdate}${raw ? '&raw=1' : ''}`
@@ -103,11 +102,13 @@ export const getters = {
getLibraryItemCoverSrcById:
(state, getters, rootState, rootGetters) =>
(libraryItemId, timestamp = null, raw = false) => {
const placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
if (!libraryItemId) return placeholder
const userToken = rootGetters['user/getToken']
if (!libraryItemId) return getters.getPlaceholderCoverSrc
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?${raw ? '&raw=1' : ''}${timestamp ? `&ts=${timestamp}` : ''}`
},
getPlaceholderCoverSrc: (state, getters, rootState, rootGetters) => {
return `${rootState.routerBasePath}/book_placeholder.jpg`
},
getIsBatchSelectingMediaItems: (state) => {
return state.selectedMediaItems.length
}

View File

@@ -171,6 +171,10 @@ export const mutations = {
state.playerQueueItems = payload.queueItems || []
}
},
updateStreamLibraryItem(state, libraryItem) {
if (!libraryItem) return
state.streamLibraryItem = libraryItem
},
setIsPlaying(state, isPlaying) {
state.streamIsPlaying = isPlaying
},

View File

File diff suppressed because it is too large Load Diff

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Плейлист",
"HeaderPlaylistItems": "Елементи от плейлист",
"HeaderPodcastsToAdd": "Подкасти за Добавяне",
"HeaderPresets": "Настройки по подразбиране",
"HeaderPreviewCover": "Преглед на Корица",
"HeaderRSSFeedGeneral": "RSS подробности",
"HeaderRSSFeedIsOpen": "RSS емисията е отворена",
@@ -219,6 +220,7 @@
"LabelAccountTypeAdmin": "Администратор",
"LabelAccountTypeGuest": "Гост",
"LabelAccountTypeUser": "Потребител",
"LabelActivities": "Дейности",
"LabelActivity": "Дейност",
"LabelAddToCollection": "Добави в Колекция",
"LabelAddToCollectionBatch": "Добави {0} Книги в Колекция",
@@ -253,7 +255,7 @@
"LabelBackupLocation": "Местоположение на Архив",
"LabelBackupsEnableAutomaticBackups": "Включи автоматично архивиране",
"LabelBackupsEnableAutomaticBackupsHelp": "Архиви запазени в /metadata/backups",
"LabelBackupsMaxBackupSize": "Максимален размер на архива (в GB)",
"LabelBackupsMaxBackupSize": "Максимален размер на архива (в GB) (0 за неограничен)",
"LabelBackupsMaxBackupSizeHelp": "За защита срещу грешки в конфигурацията, архивите ще се провалят ако надхвърлят конфигурирания размер.",
"LabelBackupsNumberToKeep": "Брой архиви за запазване",
"LabelBackupsNumberToKeepHelp": "Само 1 архив ще бъде премахнат на веднъж, така че ако вече имате повече архиви от това трябва да ги премахнете ръчно.",
@@ -283,6 +285,7 @@
"LabelContinueSeries": "Продължи серии",
"LabelCover": "Корица",
"LabelCoverImageURL": "URL на Корица",
"LabelCoverProvider": "Източник за обложки",
"LabelCreatedAt": "Създадено на",
"LabelCronExpression": "Cron израз",
"LabelCurrent": "Текущо",
@@ -325,11 +328,20 @@
"LabelEncodingClearItemCache": "Уверете се, че периодично изчиствате кеша на елементите.",
"LabelEncodingFinishedM4B": "Завършеният M4B файл ще бъде поставен в папката на вашите аудиокниги на:",
"LabelEncodingInfoEmbedded": "Метаданните ще бъдат вградени в аудио траковете в папката на вашите аудиокниги.",
"LabelEncodingStartedNavigation": "Когато задачата е стартирана, можете да смените тази страница.",
"LabelEncodingTimeWarning": "Кодирането може да отнеме до 30 минути.",
"LabelEncodingWarningAdvancedSettings": "Внимание: Не променяйте тези настройки, ако не сте запознати с ffmpeg настройките за кодиране.",
"LabelEncodingWatcherDisabled": "Ако сте изключили наблюдението на папки, ще е нужно да сканирате повторно аудио книгата.",
"LabelEnd": "Край",
"LabelEndOfChapter": "Край на глава",
"LabelEpisode": "Епизод",
"LabelEpisodeNotLinkedToRssFeed": "Епизодът не е свързан с RSS канал",
"LabelEpisodeNumber": "Епизод #{0}",
"LabelEpisodeTitle": "Заглавие на Епизод",
"LabelEpisodeType": "Тип на Епизод",
"LabelEpisodeUrlFromRssFeed": "URL адрес на епизод от RSS канал",
"LabelEpisodes": "Епизоди",
"LabelEpisodic": "Епизодичен",
"LabelExample": "Пример",
"LabelExpandSeries": "Покажи сериите",
"LabelExpandSubSeries": "Покажи съб сериите",
@@ -341,7 +353,9 @@
"LabelFetchingMetadata": "Взимане на Метаданни",
"LabelFile": "Файл",
"LabelFileBirthtime": "Дата на създаване на файла",
"LabelFileBornDate": "Роден {0}",
"LabelFileModified": "Дата на модификация на файла",
"LabelFileModifiedDate": "Променен {0}",
"LabelFilename": "Име на файла",
"LabelFilterByUser": "Филтриране по Потребител",
"LabelFindEpisodes": "Намери Епизоди",
@@ -355,14 +369,17 @@
"LabelFontScale": "Мащаб на шрифта",
"LabelFontStrikethrough": "Зачертан",
"LabelFormat": "Формат",
"LabelFull": "Пълен",
"LabelGenre": "Жанр",
"LabelGenres": "Жанрове",
"LabelHardDeleteFile": "Пълно Изтриване на Файл",
"LabelHasEbook": "Има е-книга",
"LabelHasSupplementaryEbook": "Има допълнителна е-книга",
"LabelHideSubtitles": "Скрий субтитри",
"LabelHighestPriority": "Най-висок Приоритет",
"LabelHost": "Хост",
"LabelHour": "Час",
"LabelHours": "Часа",
"LabelIcon": "Икона",
"LabelImageURLFromTheWeb": "URL на Изображение от Интернет",
"LabelInProgress": "В процес на изпълнение",
@@ -377,8 +394,11 @@
"LabelIntervalEvery6Hours": "Всеки 6 часа",
"LabelIntervalEveryDay": "Всеки ден",
"LabelIntervalEveryHour": "Всеки час",
"LabelIntervalEveryMinute": "Всяка минута",
"LabelInvert": "Обърни",
"LabelItem": "Елемент",
"LabelJumpBackwardAmount": "Количество за прескачане назад",
"LabelJumpForwardAmount": "Количество за прескачане напред",
"LabelLanguage": "Език",
"LabelLanguageDefaultServer": "Език по подразбиране на сървъра",
"LabelLanguages": "Езици",
@@ -393,6 +413,7 @@
"LabelLess": "По-малко",
"LabelLibrariesAccessibleToUser": "Библиотеки Достъпни за Потребителя",
"LabelLibrary": "Библиотека",
"LabelLibraryFilterSublistEmpty": "Не {0}",
"LabelLibraryItem": "Елемент на Библиотека",
"LabelLibraryName": "Име на Библиотека",
"LabelLimit": "Лимит",
@@ -405,6 +426,10 @@
"LabelLowestPriority": "Най-нисък Приоритет",
"LabelMatchExistingUsersBy": "Съпостави съществуващи потребители по",
"LabelMatchExistingUsersByDescription": "Използва се за свързване на съществуващи потребители. След свързване потребителите ще бъдат съпоставени по уникален идентификатор от вашия доставчик на SSO",
"LabelMaxEpisodesToDownload": "Максимален брой епизоди за сваляне. Използвай 0 за неограничен.",
"LabelMaxEpisodesToDownloadPerCheck": "Максимален брой нови епизоди за сваляне за проверка",
"LabelMaxEpisodesToKeep": "Максимален брой епизоди за запазване",
"LabelMaxEpisodesToKeepHelp": "Стойност 0 указва без максимален лимит. След като нов епизод е автоматично свален, най-старият епизод ще бъде изтрит, ако имате повече от X епизода. Само по един епизод ще бъде изтриван за всеки нов свален такъв.",
"LabelMediaPlayer": "Медия Плейър",
"LabelMediaType": "Тип медия",
"LabelMetaTag": "Мета Таг",
@@ -412,6 +437,7 @@
"LabelMetadataOrderOfPrecedenceDescription": "По-високите източници на метаданни ще заменят по-ниските",
"LabelMetadataProvider": "Доставчик на Метаданни",
"LabelMinute": "Минута",
"LabelMinutes": "Минути",
"LabelMissing": "Липсващо",
"LabelMissingEbook": "Няма електронна книга",
"LabelMissingSupplementaryEbook": "Няма допълнителна електронна книга",
@@ -449,11 +475,14 @@
"LabelOpenIDGroupClaimDescription": "Име на OpenID твърдението, което съдържа списък с групите на потребителя. Обикновено се нарича <code>groups</code>. <b>Ако е конфигурирано</b>, приложението автоматично ще присвоява роли въз основа на членството на потребителя в групи, при условие че тези групи са наименувани без чувствителност към регистъра като 'admin', 'user' или 'guest' в твърдението. Твърдението трябва да съдържа списък и ако потребителят принадлежи към множество групи, приложението ще присвои ролята, съответстваща на най-високото ниво на достъп. Ако няма съвпадение с група, достъпът ще бъде отказан.",
"LabelOpenRSSFeed": "Отвори RSS Feed",
"LabelOverwrite": "Презапиши",
"LabelPaginationPageXOfY": "Страница {0} от {1}",
"LabelPassword": "Парола",
"LabelPath": "Път",
"LabelPermanent": "Постоянен",
"LabelPermissionsAccessAllLibraries": "Може да достъпи до всички библиотеки",
"LabelPermissionsAccessAllTags": "Може да достъпи всички тагове",
"LabelPermissionsAccessExplicitContent": "Може да достъпи експлицитно съдържание",
"LabelPermissionsCreateEreader": "Може да създава електронен четец",
"LabelPermissionsDelete": "Може да трие",
"LabelPermissionsDownload": "Може да сваля",
"LabelPermissionsUpdate": "Може да обновява",
@@ -461,6 +490,8 @@
"LabelPersonalYearReview": "Преглед на годината Ви ({0})",
"LabelPhotoPathURL": "Път/URL на Снимка",
"LabelPlayMethod": "Метод на Пускане",
"LabelPlaybackRateIncrementDecrement": "Размер на увеличаване/намаляне при скоростта на възпроизвеждане",
"LabelPlayerChapterNumberMarker": "{0} от {1}",
"LabelPlaylists": "Плейлисти",
"LabelPodcast": "Подкаст",
"LabelPodcastSearchRegion": "Регион за Търсене на Подкасти",
@@ -472,9 +503,12 @@
"LabelPrimaryEbook": "Основна Електронна Книга",
"LabelProgress": "Прогрес",
"LabelProvider": "Доставчик",
"LabelProviderAuthorizationValue": "Стойност на Authorization Header",
"LabelPubDate": "Дата на публикуване",
"LabelPublishYear": "Година на публикуване",
"LabelPublishedDate": "Публикувани {0}",
"LabelPublishedDecade": "Десетилетие на публикуване",
"LabelPublishedDecades": "Десетилетия на публикуване",
"LabelPublisher": "Издател",
"LabelPublishers": "Издателство",
"LabelRSSFeedCustomOwnerEmail": "Персонализиран имейл на собственика",
@@ -484,6 +518,7 @@
"LabelRSSFeedSlug": "идентификатор на RSS емисия",
"LabelRSSFeedURL": "URL на RSS емисия",
"LabelRandomly": "Случайно",
"LabelReAddSeriesToContinueListening": "Добави отново в \"Продължете да слушате\"",
"LabelRead": "Прочети",
"LabelReadAgain": "Прочети отново",
"LabelReadEbookWithoutProgress": "Прочети електронната книга без записване прогрес",
@@ -493,29 +528,40 @@
"LabelRedo": "Повтори",
"LabelRegion": "Регион",
"LabelReleaseDate": "Дата на Издаване",
"LabelRemoveAllMetadataAbs": "Премахни всички metadata.abs файлове",
"LabelRemoveAllMetadataJson": "Премахни всички metadata.json файлове",
"LabelRemoveAudibleBranding": "Премахни въведението и заключението на Audible от главите",
"LabelRemoveCover": "Премахни Корица",
"LabelRemoveMetadataFile": "Премахни файловете с метаданни от папката на библиотеката",
"LabelRemoveMetadataFileHelp": "Премахни всички metadata.json и metadata.abs файлове от вашата {0} папка.",
"LabelRowsPerPage": "Редове на Страница",
"LabelSearchTerm": "Търси Термин",
"LabelSearchTitle": "Търси Заглавие",
"LabelSearchTitleOrASIN": "Търси Заглавие или ASIN",
"LabelSeason": "Сезон",
"LabelSeasonNumber": "Сезон #{0}",
"LabelSelectAll": "Избери всичко",
"LabelSelectAllEpisodes": "Избери всички епизоди",
"LabelSelectEpisodesShowing": "Избери {0} епизоди показани",
"LabelSelectUsers": "Избери Потребители",
"LabelSendEbookToDevice": "Изпрати електронна книга до ...",
"LabelSequence": "Последователност",
"LabelSerial": "Сериал",
"LabelSeries": "От сериите",
"LabelSeriesName": "Име на Серия",
"LabelSeriesProgress": "Прогрес на Серия",
"LabelServerLogLevel": "Ниво на сървърен журнал",
"LabelServerYearReview": "Преглед на годината на сървъра ({0})",
"LabelSetEbookAsPrimary": "Направи главен",
"LabelSetEbookAsSupplementary": "Направи второстепенен",
"LabelSettingsAllowIframe": "Разреши вграждане в iframe",
"LabelSettingsAudiobooksOnly": "Само аудиокниги",
"LabelSettingsAudiobooksOnlyHelp": "Активирането на тази настройка ще игнорира файловете на електронни книги, освен ако не са в папка с аудиокниги, в което случай ще бъдат зададени като допълнителни електронни книги",
"LabelSettingsBookshelfViewHelp": "Скеуморфен дизайн с дървени рафтове",
"LabelSettingsChromecastSupport": "Chromecast поддръжка",
"LabelSettingsDateFormat": "Формат на Дата",
"LabelSettingsEnableWatcher": "Автоматично сканиране на библиотеките за промени",
"LabelSettingsEnableWatcherForLibrary": "Автоматично сканиране на библиотеката за промени",
"LabelSettingsEnableWatcherHelp": "Включва автоматичното добавяне/обновяване на елементи, когато се открият промени във файловете. *Изисква рестарт на сървъра",
"LabelSettingsEpubsAllowScriptedContent": "Позволи скриптово съдържание в epub-и",
"LabelSettingsEpubsAllowScriptedContentHelp": "Позволи epub файловете да изпълняват скриптове. Препоръчително е да бъде изключено освен ако не се доверявате на източника на epub файловете.",
@@ -527,10 +573,13 @@
"LabelSettingsHideSingleBookSeriesHelp": "Сериите с една книга ще бъдат скрити от страницата на серията и рафтовете на началната страница.",
"LabelSettingsHomePageBookshelfView": "Начална страница изглед на рафт",
"LabelSettingsLibraryBookshelfView": "Библиотека изглед на рафт",
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Процент завършеност е по-голям от",
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Оставащо време е по-малко от (секунди)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Отбелязване на мултимедиен елемент като завършен когато",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропусни предишни книги в Продължи Поредица",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Рафтът на началната страница 'Продължи поредицата' показва първата книга, която не е започната в поредици, в които има поне една завършена книга и няма книги в процес на четене. Активирането на тази настройка ще продължи поредицата от най-далечната завършена книга вместо от първата незапочната книга.",
"LabelSettingsParseSubtitles": "Извлечи подзаглавия",
"LabelSettingsParseSubtitlesHelp": "Извлича подзаглавия от имената на папките на аудиокнигите.<br>Подзаглавията трябва да бъдат разделени с \" - \"<br>например \"Заглавие на Книга - Тук е Подзаглавито\" има подзаглавие \"Тук е Подзаглавито\"",
"LabelSettingsParseSubtitlesHelp": "Извлича подзаглавия от имената на папките на аудио книгите.<br>Подзаглавията трябва да бъдат разделени с \" - \"<br>например \"Заглавие на Книга - Тук е подзаглавието\" има подзаглавие \"Тук е подзаглавието\"",
"LabelSettingsPreferMatchedMetadata": "Предпочети съвпадащи метаданни",
"LabelSettingsPreferMatchedMetadataHelp": "Съвпадащите данни ще заменят детайлите на елемента при използване на Бързо Съпоставяне. По подразбиране Бързото Съпоставяне ще попълни само липсващите детайли.",
"LabelSettingsSkipMatchingBooksWithASIN": "Пропусни съвпадащи книги, които вече имат ASIN",
@@ -544,11 +593,19 @@
"LabelSettingsStoreMetadataWithItem": "Запази метаданните с елемента",
"LabelSettingsStoreMetadataWithItemHelp": "По подразбиране метаданните се съхраняват в /metadata/items, като активирате тази настройка метаданните ще се съхраняват в папката на елемента на вашата библиотека",
"LabelSettingsTimeFormat": "Формат на Време",
"LabelShare": "Сподели",
"LabelShareDownloadableHelp": "Разреши на потребителите през връзка за споделяне да свалят zip файл с мултимедийния елемент.",
"LabelShareOpen": "Общодостъпно",
"LabelShareURL": "URL за споделяне",
"LabelShowAll": "Покажи всички",
"LabelShowSeconds": "Покажи секунди",
"LabelShowSubtitles": "Показвай подзаглавия",
"LabelSize": "Размер",
"LabelSleepTimer": "Таймер за изключване",
"LabelSlug": "Слъг",
"LabelSortAscending": "Възходящ",
"LabelSortDescending": "Низходящ",
"LabelSortPubDate": "Подреди по дата на публикуване",
"LabelStart": "Старт",
"LabelStartTime": "Начално Време",
"LabelStarted": "Стартирано",
@@ -583,6 +640,11 @@
"LabelThemeDark": "Тъмна",
"LabelThemeLight": "Светла",
"LabelTimeBase": "Времева Основа",
"LabelTimeDurationXHours": "{0} часа",
"LabelTimeDurationXMinutes": "{0} минути",
"LabelTimeDurationXSeconds": "{0} секунди",
"LabelTimeInMinutes": "Време в минути",
"LabelTimeLeft": "остава {0}",
"LabelTimeListened": "Време Слушано",
"LabelTimeListenedToday": "Време Слушано Днес",
"LabelTimeRemaining": "{0} оставащи",
@@ -590,6 +652,7 @@
"LabelTitle": "Заглавие",
"LabelToolsEmbedMetadata": "Вграждане на Метаданни",
"LabelToolsEmbedMetadataDescription": "Вграждане на метаданни в аудио файлове, включително корица и глави.",
"LabelToolsM4bEncoder": "M4B кодировчик",
"LabelToolsMakeM4b": "Направи M4B Аудиокнига Файл",
"LabelToolsMakeM4bDescription": "Генериране на .M4B аудиокнига файл с вградени метаданни, корица и глави.",
"LabelToolsSplitM4b": "Раздели M4B на MP3-ки",
@@ -602,26 +665,32 @@
"LabelTracksMultiTrack": "Многоканален",
"LabelTracksNone": "Няма канали",
"LabelTracksSingleTrack": "Единичен канал",
"LabelTrailer": "Трейлър",
"LabelType": "Тип",
"LabelUnabridged": "Несъкратен",
"LabelUndo": "Отмени",
"LabelUnknown": "Неизвестен",
"LabelUnknownPublishDate": "Неизвестна дата на публикуване",
"LabelUpdateCover": "Обнови Корица",
"LabelUpdateCoverHelp": "Позволи презаписване на съществуващите корици за избраните книги, когато се намери съвпадение",
"LabelUpdateDetails": "Обнови Детайли",
"LabelUpdateDetailsHelp": "Позволи презаписване на съществуващите детайли за избраните книги, когато се намери съвпадение",
"LabelUpdatedAt": "Обновено на",
"LabelUploaderDragAndDrop": "Плъзни и Пусни Файлове или Папки",
"LabelUploaderDragAndDropFilesOnly": "Извлачване на файлове",
"LabelUploaderDropFiles": "Пусни Файлове",
"LabelUploaderItemFetchMetadataHelp": "Автоматично вземи заглавие, автор и серия",
"LabelUseAdvancedOptions": "Използвай разширени опции",
"LabelUseChapterTrack": "Използвай канал за глава",
"LabelUseFullTrack": "Използвай пълен канал",
"LabelUseZeroForUnlimited": "Използвай 0 за неограничен",
"LabelUser": "Потребител",
"LabelUsername": "Потребителско име",
"LabelValue": "Стойност",
"LabelVersion": "Версия",
"LabelViewBookmarks": "Виж Отметки",
"LabelViewChapters": "Виж Глави",
"LabelViewPlayerSettings": "Виж настройки на плеъра",
"LabelViewQueue": "Виж Опашка",
"LabelVolume": "Сила на Звука",
"LabelWeekdaysToRun": "Делници за изпълнение",

View File

@@ -1,33 +1,35 @@
{
"ButtonAdd": "Afegeix",
"ButtonAddChapters": "Afegeix",
"ButtonAddDevice": "Afegeix Dispositiu",
"ButtonAddLibrary": "Crea Biblioteca",
"ButtonAddChapters": "Afegeix capítols",
"ButtonAddDevice": "Afegeix un aparell",
"ButtonAddLibrary": "Afegeix una biblioteca",
"ButtonAddPodcasts": "Afegeix pòdcasts",
"ButtonAddUser": "Crea Usuari",
"ButtonAddYourFirstLibrary": "Crea la teva Primera Biblioteca",
"ButtonAddUser": "Afegeix un usuari",
"ButtonAddYourFirstLibrary": "Afegiu la vostra primera biblioteca",
"ButtonApply": "Aplica",
"ButtonApplyChapters": "Aplica Capítols",
"ButtonApplyChapters": "Aplica capítols",
"ButtonAuthors": "Autors",
"ButtonBack": "Enrere",
"ButtonBrowseForFolder": "Cerca Carpeta",
"ButtonBatchEditPopulateFromExisting": "Omplir des d'existent",
"ButtonBatchEditPopulateMapDetails": "Omple els detalls del mapa",
"ButtonBrowseForFolder": "Cerca una carpeta",
"ButtonCancel": "Cancel·la",
"ButtonCancelEncode": "Cancel·la Codificador",
"ButtonCancelEncode": "Cancel·la la codificació",
"ButtonChangeRootPassword": "Canvia Contrasenya Root",
"ButtonCheckAndDownloadNewEpisodes": "Verifica i Descarrega Nous Episodis",
"ButtonChooseAFolder": "Tria una Carpeta",
"ButtonChooseFiles": "Tria un Fitxer",
"ButtonClearFilter": "Elimina Filtres",
"ButtonCloseFeed": "Tanca Font",
"ButtonChooseAFolder": "Trieu una carpeta",
"ButtonChooseFiles": "Trieu fitxers",
"ButtonClearFilter": "Neteja el filtre",
"ButtonCloseFeed": "Tanca el canal",
"ButtonCloseSession": "Tanca la sessió oberta",
"ButtonCollections": "Col·leccions",
"ButtonConfigureScanner": "Configura Escàner",
"ButtonCreate": "Crea",
"ButtonCreateBackup": "Crea Còpia de Seguretat",
"ButtonDelete": "Elimina",
"ButtonDelete": "Suprimeix",
"ButtonDownloadQueue": "Cua",
"ButtonEdit": "Edita",
"ButtonEditChapters": "Edita Capítol",
"ButtonEditChapters": "Edita capítols",
"ButtonEditPodcast": "Edita el pòdcast",
"ButtonEnable": "Habilita",
"ButtonFireAndFail": "Executat i fallat",
@@ -117,7 +119,7 @@
"HeaderAccount": "Compte",
"HeaderAddCustomMetadataProvider": "Afegeix un proveïdor de metadades personalitzat",
"HeaderAdvanced": "Avançat",
"HeaderAppriseNotificationSettings": "Configuració de Notificacions Apprise",
"HeaderAppriseNotificationSettings": "Paràmetres de notificacions Apprise",
"HeaderAudioTracks": "Pistes d'àudio",
"HeaderAudiobookTools": "Eines de gestió de fitxers de l'audiollibre",
"HeaderAuthentication": "Autenticació",
@@ -133,9 +135,9 @@
"HeaderCustomMetadataProviders": "Proveïdors de metadades personalitzats",
"HeaderDetails": "Detalls",
"HeaderDownloadQueue": "Cua de baixades",
"HeaderEbookFiles": "Fitxers de Llibres Digitals",
"HeaderEbookFiles": "Fitxers de llibres digitals",
"HeaderEmail": "Correu electrònic",
"HeaderEmailSettings": "Configuració de Correu Electrònic",
"HeaderEmailSettings": "Paràmetres de correu electrònic",
"HeaderEpisodes": "Episodis",
"HeaderEreaderDevices": "Dispositius Ereader",
"HeaderEreaderSettings": "Paràmetres del lector",
@@ -171,10 +173,11 @@
"HeaderPasswordAuthentication": "Autenticació per Contrasenya",
"HeaderPermissions": "Permisos",
"HeaderPlayerQueue": "Cua del Reproductor",
"HeaderPlayerSettings": "Configuració del Reproductor",
"HeaderPlayerSettings": "Paràmetres del reproductor",
"HeaderPlaylist": "Llista de Reproducció",
"HeaderPlaylistItems": "Elements de la Llista de Reproducció",
"HeaderPodcastsToAdd": "Pòdcasts a afegir",
"HeaderPresets": "Valors predefinits",
"HeaderPreviewCover": "Previsualització de la Portada",
"HeaderRSSFeedGeneral": "Detalls RSS",
"HeaderRSSFeedIsOpen": "La Font RSS està oberta",
@@ -190,7 +193,7 @@
"HeaderSettings": "Paràmetres",
"HeaderSettingsDisplay": "Interfície",
"HeaderSettingsExperimental": "Funcionalitats experimentals",
"HeaderSettingsGeneral": "General",
"HeaderSettingsGeneral": "Generals",
"HeaderSettingsScanner": "Escàner",
"HeaderSettingsWebClient": "Client web",
"HeaderSleepTimer": "Temporitzador de son",
@@ -219,10 +222,10 @@
"LabelAccountTypeUser": "Usuari",
"LabelActivities": "Activitats",
"LabelActivity": "Activitat",
"LabelAddToCollection": "Afegit a la Col·lecció",
"LabelAddToCollectionBatch": "S'han Afegit {0} Llibres a la Col·lecció",
"LabelAddToPlaylist": "Afegit a la llista de reproducció",
"LabelAddToPlaylistBatch": "S'han Afegit {0} Elements a la Llista de Reproducció",
"LabelAddToCollection": "Afegeix a la col·lecció",
"LabelAddToCollectionBatch": "Afegeix {0} llibres a la col·lecció",
"LabelAddToPlaylist": "Afegeix a la llista de reproducció",
"LabelAddToPlaylistBatch": "Afegeix {0} elements a la llista de reproducció",
"LabelAddedAt": "Afegit",
"LabelAddedDate": "{0} Afegit",
"LabelAdminUsersOnly": "Només usuaris administradors",
@@ -231,7 +234,7 @@
"LabelAllUsers": "Tots els usuaris",
"LabelAllUsersExcludingGuests": "Tots els usuaris excepte convidats",
"LabelAllUsersIncludingGuests": "Tots els usuaris i convidats",
"LabelAlreadyInYourLibrary": "Ja existeix a la Biblioteca",
"LabelAlreadyInYourLibrary": "Ja existeix a la biblioteca",
"LabelApiToken": "Testimoni de l'API",
"LabelAppend": "Adjuntar",
"LabelAudioBitrate": "Taxa de bits d'àudio (per exemple, 128k)",
@@ -288,14 +291,14 @@
"LabelCronExpression": "Expressió de Cron",
"LabelCurrent": "Actual",
"LabelCurrently": "En aquest moment:",
"LabelCustomCronExpression": "Expressió de Cron Personalitzada:",
"LabelDatetime": "Hora i Data",
"LabelCustomCronExpression": "Expressió del Cron personalitzada:",
"LabelDatetime": "Data i hora",
"LabelDays": "Dies",
"LabelDeleteFromFileSystemCheckbox": "Suprimeix del sistema de fitxers (desmarqueu per a eliminar de la base de dades només)",
"LabelDescription": "Descripció",
"LabelDeselectAll": "Desseleccionar Tots",
"LabelDevice": "Dispositiu",
"LabelDeviceInfo": "Informació del Dispositiu",
"LabelDeviceInfo": "Informació de l'aparell",
"LabelDeviceIsAvailableTo": "El dispositiu està disponible per a...",
"LabelDirectory": "Directori",
"LabelDiscFromFilename": "Disc a partir del nom de fitxer",
@@ -333,11 +336,11 @@
"LabelEnd": "Fi",
"LabelEndOfChapter": "Fi del capítol",
"LabelEpisode": "Episodi",
"LabelEpisodeNotLinkedToRssFeed": "Episodi no enllaçat al feed RSS",
"LabelEpisodeNotLinkedToRssFeed": "Episodi no enllaçat al canal RSS",
"LabelEpisodeNumber": "Episodi #{0}",
"LabelEpisodeTitle": "Títol de l'Episodi",
"LabelEpisodeType": "Tipus d'Episodi",
"LabelEpisodeUrlFromRssFeed": "URL de l'episodi del feed RSS",
"LabelEpisodeUrlFromRssFeed": "URL de l'episodi del canal RSS",
"LabelEpisodes": "Episodis",
"LabelEpisodic": "Episodis",
"LabelExample": "Exemple",
@@ -350,7 +353,7 @@
"LabelFeedURL": "Font de URL",
"LabelFetchingMetadata": "Obtenció de metadades",
"LabelFile": "Fitxer",
"LabelFileBirthtime": "Arxiu creat a",
"LabelFileBirthtime": "Fitxer creat a",
"LabelFileBornDate": "Creat {0}",
"LabelFileModified": "Fitxer modificat",
"LabelFileModifiedDate": "Modificat {0}",
@@ -437,7 +440,7 @@
"LabelMinute": "Minut",
"LabelMinutes": "Minuts",
"LabelMissing": "Absent",
"LabelMissingEbook": "No té ebook",
"LabelMissingEbook": "No té llibre electrònic",
"LabelMissingSupplementaryEbook": "No té ebook complementari",
"LabelMobileRedirectURIs": "URI de redirecció mòbil permeses",
"LabelMobileRedirectURIsDescription": "Aquesta és una llista blanca d'URI de redirecció vàlides per a aplicacions mòbils. El predeterminat és <code> audiobookshelf</code>, que pots eliminar o complementar amb URI addicionals per a la integració d'aplicacions de tercers. Usant un asterisc (<code> *</code>) com a única entrada que permet qualsevol URI.",
@@ -471,6 +474,7 @@
"LabelOpenIDAdvancedPermsClaimDescription": "Nom de la notificació de OpenID que conté permisos avançats per accions d'usuari dins l'aplicació que s'aplicaran a rols que no siguin d'administrador (<b>si estan configurats</b>). Si el reclam no apareix en la resposta, es denegarà l'accés a ABS. Si manca una sola opció, es tractarà com a <code>falsa</code>. Assegura't que la notificació del proveïdor d'identitats coincideixi amb l'estructura esperada:",
"LabelOpenIDClaims": "Deixa les següents opcions buides per desactivar l'assignació avançada de grups i permisos, el que assignaria automàticament al grup 'Usuari'.",
"LabelOpenIDGroupClaimDescription": "Nom de la declaració OpenID que conté una llista de grups de l'usuari. Comunament coneguts com <code>grups</code>. <b>Si es configura</b>, l'aplicació assignarà automàticament rols basats en la pertinença a grups de l'usuari, sempre que aquests grups es denominen 'admin', 'user' o 'guest' en la notificació. La sol·licitud ha de contenir una llista, i si un usuari pertany a diversos grups, l'aplicació assignarà el rol corresponent al major nivell d'accés. Si cap grup coincideix, es denegarà l'accés.",
"LabelOpenRSSFeed": "Obre el canal RSS",
"LabelOverwrite": "Sobreescriure",
"LabelPaginationPageXOfY": "Pàgina {0} de {1}",
"LabelPassword": "Contrasenya",
@@ -494,25 +498,25 @@
"LabelPodcastType": "Tipus de pòdcast",
"LabelPodcasts": "Pòdcasts",
"LabelPort": "Port",
"LabelPrefixesToIgnore": "Prefixos per Ignorar (no distingeix entre majúscules i minúscules.)",
"LabelPreventIndexing": "Evita que la teva font sigui indexada pels directoris de podcasts d'iTunes i Google",
"LabelPrimaryEbook": "Ebook Principal",
"LabelPrefixesToIgnore": "Prefixos a ignorar (no distingeix entre majúscules i minúscules)",
"LabelPreventIndexing": "Evita que el vostre canal l'indexin els directoris de pòdcasts de l'iTunes i Google",
"LabelPrimaryEbook": "Llibre electrònic principal",
"LabelProgress": "Progrés",
"LabelProvider": "Proveïdor",
"LabelProviderAuthorizationValue": "Valor de l'encapçalament d'autorització",
"LabelPubDate": "Data de Publicació",
"LabelPublishYear": "Any de Publicació",
"LabelPubDate": "Data de publicació",
"LabelPublishYear": "Any de publicació",
"LabelPublishedDate": "Publicat {0}",
"LabelPublishedDecade": "Dècada de Publicació",
"LabelPublishedDecade": "Dècada de publicació",
"LabelPublishedDecades": "Dècades Publicades",
"LabelPublisher": "Editor",
"LabelPublishers": "Editors",
"LabelRSSFeedCustomOwnerEmail": "Correu Electrònic Personalitzat del Propietari",
"LabelRSSFeedCustomOwnerName": "Nom Personalitzat del Propietari",
"LabelRSSFeedOpen": "Font RSS Oberta",
"LabelRSSFeedPreventIndexing": "Evitar l'indexació",
"LabelRSSFeedSlug": "Font RSS Slug",
"LabelRSSFeedURL": "URL de la Font RSS",
"LabelRSSFeedPreventIndexing": "Evita la indexació",
"LabelRSSFeedSlug": "URL semàntic del canal RSS",
"LabelRSSFeedURL": "URL del canal RSS",
"LabelRandomly": "A l'atzar",
"LabelReAddSeriesToContinueListening": "Reafegir la sèrie per continuar escoltant-la",
"LabelRead": "Llegit",
@@ -521,52 +525,61 @@
"LabelRecentSeries": "Sèries recents",
"LabelRecentlyAdded": "Addicions recents",
"LabelRecommended": "Recomanats",
"LabelRedo": "Refer",
"LabelRedo": "Refés",
"LabelRegion": "Regió",
"LabelReleaseDate": "Data d'Estrena",
"LabelRemoveAllMetadataAbs": "Eliminar tots els fitxers metadata.abs",
"LabelRemoveAllMetadataJson": "Eliminar tots els fitxers metadata.json",
"LabelRemoveCover": "Eliminar Coberta",
"LabelReleaseDate": "Data d'estrena",
"LabelRemoveAllMetadataAbs": "Elimina tots els fitxers metadata.abs",
"LabelRemoveAllMetadataJson": "Elimina tots els fitxers metadata.json",
"LabelRemoveAudibleBranding": "Elimina la introducció i el tancament de l'Audible dels capítols",
"LabelRemoveCover": "Elimina la coberta",
"LabelRemoveMetadataFile": "Eliminar fitxers de metadades en carpetes d'elements de biblioteca",
"LabelRemoveMetadataFileHelp": "Elimina tots els fitxers metadata.json i metadata.abs de les teves carpetes {0}.",
"LabelRowsPerPage": "Files per Pàgina",
"LabelSearchTerm": "Cercar Terme",
"LabelSearchTitle": "Cercar Títol",
"LabelSearchTitleOrASIN": "Cercar Títol o ASIN",
"LabelRemoveMetadataFileHelp": "Elimina tots els fitxers metadata.json i metadata.abs de les vostres carpetes {0}.",
"LabelRowsPerPage": "Files per pàgina",
"LabelSearchTerm": "Cerca terme",
"LabelSearchTitle": "Cerca títol",
"LabelSearchTitleOrASIN": "Cerca títol o ASIN",
"LabelSeason": "Temporada",
"LabelSeasonNumber": "Temporada #{0}",
"LabelSelectAll": "Seleccionar tot",
"LabelSelectAllEpisodes": "Seleccionar tots els episodis",
"LabelSeasonNumber": "{0}a temporada",
"LabelSelectAll": "Selecciona-ho tot",
"LabelSelectAllEpisodes": "Selecciona tots els episodis",
"LabelSelectEpisodesShowing": "Seleccionar els {0} episodis visibles",
"LabelSelectUsers": "Seleccionar usuaris",
"LabelSendEbookToDevice": "Enviar Ebook a...",
"LabelSequence": "Seqüència",
"LabelSerial": "En sèrie",
"LabelSeries": "Sèries",
"LabelSeriesName": "Nom de la Sèrie",
"LabelSeriesProgress": "Progrés de la Sèrie",
"LabelSeries": "Sèrie",
"LabelSeriesName": "Nom de la sèrie",
"LabelSeriesProgress": "Progrés de la sèrie",
"LabelServerLogLevel": "Nivell de registre del servidor",
"LabelServerYearReview": "Resum de l'any del servidor ({0})",
"LabelSetEbookAsPrimary": "Establir com a principal",
"LabelSetEbookAsSupplementary": "Establir com a suplementari",
"LabelSettingsAudiobooksOnly": "Només Audiollibres",
"LabelSettingsAudiobooksOnlyHelp": "Activant aquesta opció s'ignoraran els fitxers d'ebook, excepte si estan dins d'una carpeta d'audiollibre, en aquest cas es marcaran com ebooks suplementaris",
"LabelSettingsAudiobooksOnly": "Només audiollibres",
"LabelSettingsAudiobooksOnlyHelp": "En activar aquesta opció s'ignoraran els fitxers de llibre electrònic, excepte si estan dins d'una carpeta d'audiollibre; en aquest cas es marcaran com a llibres suplementaris",
"LabelSettingsBookshelfViewHelp": "Disseny esqueomorf amb prestatgeries de fusta",
"LabelSettingsChromecastSupport": "Compatibilitat amb Chromecast",
"LabelSettingsDateFormat": "Format de Data",
"LabelSettingsDateFormat": "Format de data",
"LabelSettingsEnableWatcherHelp": "Permet afegir/actualitzar elements automàticament quan es detectin canvis en els fitxers. *Requereix reiniciar el servidor",
"LabelSettingsEpubsAllowScriptedContent": "Permetre scripts en epubs",
"LabelSettingsEpubsAllowScriptedContentHelp": "Permetre que els fitxers epub executin scripts. Es recomana mantenir aquesta opció desactivada tret que confiïs en l'origen dels fitxers epub.",
"LabelSettingsExperimentalFeatures": "Funcions Experimentals",
"LabelSettingsExperimentalFeaturesHelp": "Funcions en desenvolupament que es beneficiarien dels teus comentaris i experiències de prova. Feu clic aquí per obrir una conversa a Github.",
"LabelSettingsFindCovers": "Troba cobertes",
"LabelSettingsHideSingleBookSeries": "Amaga les sèries amb un sol llibre",
"LabelSettingsParseSubtitles": "Analitza els subtítols",
"LabelSettingsSortingIgnorePrefixes": "Ignora els prefixos en ordenar",
"LabelSettingsTimeFormat": "Format d'hora",
"LabelShare": "Comparteix",
"LabelShareDownloadableHelp": "Permet els usuaris amb l'enllaç de compartició de baixar un fitxer ZIP amb l'element de la biblioteca.",
"LabelShareURL": "URL de compartició",
"LabelShowAll": "Mostra-ho tot",
"LabelShowSeconds": "Mostra segons",
"LabelShowSubtitles": "Mostra subtítols",
"LabelSize": "Mida",
"LabelSleepTimer": "Temporitzador de repòs",
"LabelSlug": "Slug",
"LabelSortAscending": "Ascendent",
"LabelSortDescending": "Descendent",
"LabelStart": "Inicia",
"LabelStartTime": "Hora d'inici",
"LabelStarted": "Iniciat",
@@ -654,88 +667,98 @@
"LabelViewPlayerSettings": "Mostra els ajustaments del reproductor",
"LabelViewQueue": "Mostra cua del reproductor",
"LabelVolume": "Volum",
"LabelWebRedirectURLsDescription": "Autoritza aquestes URL al teu proveïdor OAuth per permetre redirecció a l'aplicació web després d'iniciar sessió:",
"LabelWebRedirectURLsDescription": "Autoritzeu aquests URL al vostre proveïdor OAuth per a permetre redirigir a laplicació web després d'iniciar sessió:",
"LabelWebRedirectURLsSubfolder": "Subcarpeta per a URL de redirecció",
"LabelWeekdaysToRun": "Executar en dies de la setmana",
"LabelXBooks": "{0} llibres",
"LabelXItems": "{0} elements",
"LabelYearReviewHide": "Oculta resum de l'any",
"LabelYearReviewShow": "Mostra resum de l'any",
"LabelYourAudiobookDuration": "Duració del teu audiollibre",
"LabelYourAudiobookDuration": "Duració del vostre audiollibre",
"LabelYourBookmarks": "Els vostres marcadors",
"LabelYourPlaylists": "Les teves llistes",
"LabelYourPlaylists": "Les vostres llistes",
"LabelYourProgress": "El vostre progrés",
"MessageAddToPlayerQueue": "Afegeix a la cua del reproductor",
"MessageAppriseDescription": "Per utilitzar aquesta funció, hauràs de tenir l'<a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">API d'Apprise</a> en funcionament o una API que gestioni resultats similars. <br/>La URL de l'API d'Apprise ha de tenir la mateixa ruta d'arxius que on s'envien les notificacions. Per exemple: si la teva API és a <code>http://192.168.1.1:8337</code>, llavors posaries <code>http://192.168.1.1:8337/notify</code>.",
"MessageAuthenticationOIDCChangesRestart": "Reengegueu el servidor després de desar perquè s'hi apliquin els canvis d'OIDC.",
"MessageBackupsDescription": "Les còpies de seguretat inclouen: usuaris, progrés dels usuaris, detalls dels elements de la biblioteca, configuració del servidor i imatges a <code>/metadata/items</code> i <code>/metadata/authors</code>. Les còpies de seguretat <strong>NO</strong> inclouen cap fitxer guardat a la carpeta de la teva biblioteca.",
"MessageBackupsLocationEditNote": "Nota: Actualitzar la ubicació de la còpia de seguretat no mourà ni modificarà les còpies existents",
"MessageBackupsLocationNoEditNote": "Nota: La ubicació de la còpia de seguretat es defineix mitjançant una variable d'entorn i no es pot modificar aquí.",
"MessageBackupsLocationPathEmpty": "La ruta de la còpia de seguretat no pot estar buida",
"MessageBatchQuickMatchDescription": "La funció \"Troba Ràpid\" intentarà afegir portades i metadades que falten als elements seleccionats. Activa l'opció següent perquè \"Troba Ràpid\" pugui sobreescriure portades i/o metadades existents.",
"MessageBookshelfNoCollections": "No tens cap col·lecció",
"MessageBookshelfNoCollections": "Encara no heu fet cap col·lecció",
"MessageBookshelfNoCollectionsHelp": "Les col·leccions són públiques. Tots els usuaris amb accés a la biblioteca les podran veure.",
"MessageBookshelfNoRSSFeeds": "Cap font RSS està oberta",
"MessageBookshelfNoResultsForFilter": "Cap resultat per al filtre \"{0}: {1}\"",
"MessageBookshelfNoResultsForFilter": "Cap resultat per al filtre «{0}: {1}»",
"MessageBookshelfNoResultsForQuery": "Cap resultat per a la consulta",
"MessageBookshelfNoSeries": "No tens cap sèrie",
"MessageBookshelfNoSeries": "No teniu cap sèrie",
"MessageChapterEndIsAfter": "El final del capítol és després del final del teu audiollibre",
"MessageChapterErrorFirstNotZero": "El primer capítol ha de començar a 0",
"MessageChapterErrorStartGteDuration": "El temps d'inici no és vàlid: ha de ser inferior a la durada de l'audiollibre",
"MessageChapterErrorStartLtPrev": "El temps d'inici no és vàlid: ha de ser igual o més gran que el temps d'inici del capítol anterior",
"MessageChapterStartIsAfter": "L'inici del capítol és després del final del teu audiollibre",
"MessageChaptersNotFound": "No s'han trobat els capítols",
"MessageCheckingCron": "Comprovant cron...",
"MessageConfirmCloseFeed": "Estàs segur que vols tancar aquesta font?",
"MessageConfirmDeleteBackup": "Estàs segur que vols eliminar la còpia de seguretat {0}?",
"MessageConfirmDeleteDevice": "Estàs segur que vols eliminar el lector electrònic \"{0}\"?",
"MessageConfirmDeleteFile": "Això eliminarà el fitxer del teu sistema. Estàs segur?",
"MessageConfirmDeleteLibrary": "Estàs segur que vols eliminar permanentment la biblioteca \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "Això eliminarà l'element de la base de dades i del sistema. Estàs segur?",
"MessageConfirmDeleteLibraryItems": "Això eliminarà {0} element(s) de la base de dades i del sistema. Estàs segur?",
"MessageConfirmDeleteMetadataProvider": "Estàs segur que vols eliminar el proveïdor de metadades personalitzat \"{0}\"?",
"MessageConfirmDeleteNotification": "Estàs segur que vols eliminar aquesta notificació?",
"MessageConfirmDeleteSession": "Estàs segur que vols eliminar aquesta sessió?",
"MessageConfirmEmbedMetadataInAudioFiles": "Estàs segur que vols incrustar metadades a {0} fitxer(s) d'àudio?",
"MessageConfirmForceReScan": "Estàs segur que vols forçar un reescaneig?",
"MessageConfirmMarkAllEpisodesFinished": "Estàs segur que vols marcar tots els episodis com a acabats?",
"MessageConfirmMarkAllEpisodesNotFinished": "Estàs segur que vols marcar tots els episodis com a no acabats?",
"MessageConfirmMarkItemFinished": "Estàs segur que vols marcar \"{0}\" com a acabat?",
"MessageConfirmMarkItemNotFinished": "Estàs segur que vols marcar \"{0}\" com a no acabat?",
"MessageConfirmMarkSeriesFinished": "Estàs segur que vols marcar tots els llibres d'aquesta sèrie com a acabats?",
"MessageConfirmMarkSeriesNotFinished": "Estàs segur que vols marcar tots els llibres d'aquesta sèrie com a no acabats?",
"MessageConfirmNotificationTestTrigger": "Vols activar aquesta notificació amb dades de prova?",
"MessageConfirmPurgeCache": "Esborrar la memòria cau eliminarà tot el directori localitzat a <code>/metadata/cache</code>. <br /><br />Estàs segur que vols eliminar-lo?",
"MessageConfirmCloseFeed": "Segur que voleu tancar aquest canal?",
"MessageConfirmDeleteBackup": "Segur que voleu suprimir la còpia de seguretat de {0}?",
"MessageConfirmDeleteDevice": "Segur que voleu suprimir el lector electrònic «{0}»?",
"MessageConfirmDeleteFile": "Això suprimirà el fitxer del vostre sistema de fitxers. N'esteu segur?",
"MessageConfirmDeleteLibrary": "Segur que voleu suprimir permanentment la biblioteca «{0}»?",
"MessageConfirmDeleteLibraryItem": "Això suprimirà lelement de la base de dades i del sistema de fitxers. Nesteu segur?",
"MessageConfirmDeleteLibraryItems": "Això suprimirà {0} element(s) de la base de dades i del sistema de fitxers. N'esteu segur?",
"MessageConfirmDeleteMetadataProvider": "Segur que voleu suprimir el proveïdor de metadades personalitzat «{0}»?",
"MessageConfirmDeleteNotification": "Segur que voleu suprimir aquesta notificació?",
"MessageConfirmDeleteSession": "Segur que voleu suprimir aquesta sessió?",
"MessageConfirmEmbedMetadataInAudioFiles": "Segur que voleu incrustar metadades a {0} fitxer(s) d'àudio?",
"MessageConfirmForceReScan": "Segur que voleu forçar un reescaneig?",
"MessageConfirmMarkAllEpisodesFinished": "Segur que voleu marcar tots els episodis com a acabats?",
"MessageConfirmMarkAllEpisodesNotFinished": "Segur que voleu marcar tots els episodis com a no acabats?",
"MessageConfirmMarkItemFinished": "Segur que voleu marcar «{0}» com a acabat?",
"MessageConfirmMarkItemNotFinished": "Segur que voleu marcar «{0}» com a no acabat?",
"MessageConfirmMarkSeriesFinished": "Segur que voleu marcar tots els llibres d'aquesta sèrie com a acabats?",
"MessageConfirmMarkSeriesNotFinished": "Segur que voleu marcar tots els llibres d'aquesta sèrie com a no acabats?",
"MessageConfirmNotificationTestTrigger": "Voleu activar aquesta notificació amb dades de prova?",
"MessageConfirmPurgeCache": "Purgar la memòria cau suprimirà tot el directori localitzat a <code>/metadata/cache</code>. <br /><br />Segur que voleu eliminar-lo?",
"MessageConfirmPurgeItemsCache": "Esborrar la memòria cau dels elements eliminarà el directori <code>/metadata/cache/items</code>.<br />Estàs segur?",
"MessageConfirmQuickEmbed": "Advertència! La integració ràpida no fa còpies de seguretat dels teus fitxers d'àudio. Assegura't d'haver-ne fet una còpia abans. <br><br>Vols continuar?",
"MessageConfirmQuickEmbed": "Avís: la incrustació ràpida no fa còpies de seguretat dels vostres fitxers d'àudio. Assegureu-vos d'haver-ne fet una còpia abans. <br><br>Voleu continuar?",
"MessageConfirmQuickMatchEpisodes": "El reconeixement ràpid sobreescriurà els detalls si es troba una coincidència. Estàs segur?",
"MessageConfirmReScanLibraryItems": "Estàs segur que vols reescanejar {0} element(s)?",
"MessageConfirmRemoveAllChapters": "Estàs segur que vols eliminar tots els capítols?",
"MessageConfirmRemoveAuthor": "Estàs segur que vols eliminar l'autor \"{0}\"?",
"MessageConfirmRemoveCollection": "Estàs segur que vols eliminar la col·lecció \"{0}\"?",
"MessageConfirmRemoveEpisode": "Estàs segur que vols eliminar l'episodi \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Estàs segur que vols eliminar {0} episodis?",
"MessageConfirmRemoveListeningSessions": "Estàs segur que vols eliminar {0} sessions d'escolta?",
"MessageConfirmRemoveMetadataFiles": "Estàs segur que vols eliminar tots els fitxers de metadades.{0} de les carpetes dels elements de la teva biblioteca?",
"MessageConfirmRemoveNarrator": "Estàs segur que vols eliminar el narrador \"{0}\"?",
"MessageConfirmRemovePlaylist": "Estàs segur que vols eliminar la llista de reproducció \"{0}\"?",
"MessageConfirmRenameGenre": "Estàs segur que vols canviar el gènere \"{0}\" a \"{1}\" per a tots els elements?",
"MessageConfirmReScanLibraryItems": "Segur que voleu reescanejar {0} element(s)?",
"MessageConfirmRemoveAllChapters": "Segur que voleu eliminar tots els capítols?",
"MessageConfirmRemoveAuthor": "Segur que voleu eliminar l'autor «{0}»?",
"MessageConfirmRemoveCollection": "Segur que voleu eliminar la col·lecció «{0}»?",
"MessageConfirmRemoveEpisode": "Segur que voleu eliminar l'episodi «{0}»?",
"MessageConfirmRemoveEpisodes": "Segur que voleu eliminar {0} episodis?",
"MessageConfirmRemoveListeningSessions": "Segur que voleu eliminar {0} sessions d'escolta?",
"MessageConfirmRemoveMetadataFiles": "Segur que voleu eliminar tots els fitxers metadata.{0} de les carpetes dels elements de la vostra biblioteca?",
"MessageConfirmRemoveNarrator": "Segur que voleu eliminar el narrador «{0}»?",
"MessageConfirmRemovePlaylist": "Segur que voleu eliminar la llista de reproducció «{0}»?",
"MessageConfirmRenameGenre": "Segur que voleu canviar el nom del gènere «{0}» a «{1}» per a tots els elements?",
"MessageConfirmRenameGenreMergeNote": "Nota: Aquest gènere ja existeix, i es fusionarà.",
"MessageConfirmRenameGenreWarning": "Advertència! Ja existeix un gènere similar \"{0}\".",
"MessageConfirmRenameTag": "Estàs segur que vols canviar l'etiqueta \"{0}\" a \"{1}\" per a tots els elements?",
"MessageConfirmRenameTag": "Segur que voleu canviar el nom de l'etiqueta «{0}» a «{1}» per a tots els elements?",
"MessageConfirmRenameTagMergeNote": "Nota: Aquesta etiqueta ja existeix, i es fusionarà.",
"MessageConfirmRenameTagWarning": "Advertència! Ja existeix una etiqueta similar \"{0}\".",
"MessageConfirmResetProgress": "Estàs segur que vols reiniciar el teu progrés?",
"MessageConfirmSendEbookToDevice": "Estàs segur que vols enviar {0} ebook(s) \"{1}\" al dispositiu \"{2}\"?",
"MessageConfirmUnlinkOpenId": "Estàs segur que vols desvincular aquest usuari d'OpenID?",
"MessageDownloadingEpisode": "Descarregant capítol",
"MessageConfirmResetProgress": "Segur que voleu reinicialitzar el vostre progrés?",
"MessageConfirmSendEbookToDevice": "Segur que voleu enviar {0} llibre(s) «{1}» al dispositiu «{2}»?",
"MessageConfirmUnlinkOpenId": "Segur que voleu desenllaçar aquest usuari d'OpenID?",
"MessageDaysListenedInTheLastYear": "{0} dies escoltats l'any passat",
"MessageDownloadingEpisode": "S'està baixant l'episodi",
"MessageDragFilesIntoTrackOrder": "Arrossega els fitxers en l'ordre correcte de les pistes",
"MessageEmbedFailed": "Error en incrustar!",
"MessageEmbedFinished": "Incrustació acabada!",
"MessageEmbedQueue": "En cua per incrustar metadades ({0} en cua)",
"MessageFeedURLWillBe": "L'URL del canal serà {0}",
"MessageFetching": "S'està recuperant...",
"MessageImportantNotice": "Avís important",
"MessageInsertChapterBelow": "Insereix un capítol a sota",
"MessageInvalidAsin": "L'ASIN no és vàlid",
"MessageItemsSelected": "{0} elements seleccionats",
"MessageItemsUpdated": "{0} elements actualitzats",
"MessageJoinUsOn": "Uniu-vos a nosaltres a",
"MessageLoading": "S'està carregant...",
"MessageLoadingFolders": "S'estan carregant les carpetes...",
"MessageMarkAllEpisodesFinished": "Marca tots els episodis com a acabats",
"MessageMarkAllEpisodesNotFinished": "Marca tots els episodis com a inacabats",
"MessageMarkAsFinished": "Marcar com acabat",
"MessageMarkAsNotFinished": "Marcar com no acabat",
"MessageMatchBooksDescription": "S'intentarà fer coincidir els llibres de la biblioteca amb un llibre del proveïdor de cerca seleccionat, i s'ompliran els detalls buits i la portada. No sobreescriu els detalls.",
@@ -776,38 +799,40 @@
"MessagePauseChapter": "Pausar la reproducció del capítol",
"MessagePlayChapter": "Escoltar l'inici del capítol",
"MessagePlaylistCreateFromCollection": "Crear una llista de reproducció a partir d'una col·lecció",
"MessagePleaseWait": "Espera si us plau...",
"MessagePodcastHasNoRSSFeedForMatching": "El podcast no té una URL de font RSS que es pugui utilitzar",
"MessagePodcastSearchField": "Introdueix el terme de cerca o la URL de la font RSS",
"MessagePleaseWait": "Espereu...",
"MessagePodcastHasNoRSSFeedForMatching": "El pòdcast no té un URL de canal RSS que es pugui utilitzar",
"MessagePodcastSearchField": "Introduïu el terme de cerca o l'URL del canal RSS",
"MessageQuickEmbedInProgress": "Integració ràpida en procés",
"MessageQuickEmbedQueue": "En cua per a inserció ràpida ({0} en cua)",
"MessageQuickMatchAllEpisodes": "Combina ràpidament tots els episodis",
"MessageQuickMatchDescription": "Omple detalls d'elements buits i portades amb els primers resultats de '{0}'. No sobreescriu els detalls tret que l'opció \"Preferir metadades trobades\" del servidor estigui habilitada.",
"MessageRemoveChapter": "Eliminar capítols",
"MessageRemoveEpisodes": "Eliminar {0} episodi(s)",
"MessageRemoveFromPlayerQueue": "Eliminar de la cua del reproductor",
"MessageRemoveUserWarning": "Estàs segur que vols eliminar l'usuari \"{0}\"?",
"MessageQuickMatchDescription": "Emplena els detalls i la coberta dels elements buits amb el resultat de la primera coincidència de «{0}». No sobreescriu els detalls tret que s'activi el paràmetre del servidor «Prefereix metadades coincidents».",
"MessageRemoveChapter": "Elimina el capítol",
"MessageRemoveEpisodes": "Elimina {0} episodi(s)",
"MessageRemoveFromPlayerQueue": "Elimina de la cua del reproductor",
"MessageRemoveUserWarning": "Segur que voleu suprimir permanentment l'usuari «{0}»?",
"MessageReportBugsAndContribute": "Informa d'errors, sol·licita funcions i contribueix a",
"MessageResetChaptersConfirm": "Estàs segur que vols desfer els canvis i revertir els capítols al seu estat original?",
"MessageRestoreBackupConfirm": "Estàs segur que vols restaurar la còpia de seguretat creada a",
"MessageResetChaptersConfirm": "Segur que voleu desfer els canvis i revertir els capítols al seu estat original?",
"MessageRestoreBackupConfirm": "Segur que voleu restaurar la còpia de seguretat creada a",
"MessageRestoreBackupWarning": "Restaurar sobreescriurà tota la base de dades situada a /config i les imatges de portades a /metadata/items i /metadata/authors.<br /><br />La còpia de seguretat no modifica cap fitxer a les carpetes de la teva biblioteca. Si has activat l'opció del servidor per guardar portades i metadades a les carpetes de la biblioteca, aquests fitxers no es guarden ni sobreescriuen.<br /><br />Tots els clients que utilitzin el teu servidor s'actualitzaran automàticament.",
"MessageScheduleRunEveryWeekdayAtTime": "Executa cada {0} a les {1}",
"MessageSearchResultsFor": "Resultats de la cerca de",
"MessageSelected": "{0} seleccionat(s)",
"MessageSeriesSequenceCannotContainSpaces": "La seqüència de la sèrie no pot contenir espais",
"MessageServerCouldNotBeReached": "No es va poder establir la connexió amb el servidor",
"MessageSetChaptersFromTracksDescription": "Establir capítols utilitzant cada fitxer d'àudio com un capítol i el títol del capítol com el nom del fitxer d'àudio",
"MessageShareExpirationWillBe": "La caducitat serà <strong>{0}</strong>",
"MessageShareExpiresIn": "Caduca en {0}",
"MessageShareURLWillBe": "La URL per compartir serà <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Començar la reproducció per a \"{0}\" a {1}?",
"MessageTaskAudioFileNotWritable": "El fitxer d'àudio \"{0}\" no es pot escriure",
"MessageStartPlaybackAtTime": "Voleu començar la reproducció per a «{0}» a {1}?",
"MessageTaskAudioFileNotWritable": "El fitxer d'àudio «{0}» no es pot escriure",
"MessageTaskCanceledByUser": "Tasca cancel·lada per l'usuari",
"MessageTaskDownloadingEpisodeDescription": "Descarregant l'episodi \"{0}\"",
"MessageTaskDownloadingEpisodeDescription": "S'està baixant l'episodi «{0}»",
"MessageTaskEmbeddingMetadata": "Inserint metadades",
"MessageTaskEmbeddingMetadataDescription": "Inserint metadades en l'audiollibre \"{0}\"",
"MessageTaskEncodingM4b": "Codificant M4B",
"MessageTaskEncodingM4bDescription": "Codificant l'audiollibre \"{0}\" en un únic fitxer M4B",
"MessageTaskEncodingM4bDescription": "S'està codificant l'audiollibre «{0}» en un únic fitxer M4B",
"MessageTaskFailed": "Fallada",
"MessageTaskFailedToBackupAudioFile": "Error en fer una còpia de seguretat del fitxer d'àudio \"{0}\"",
"MessageTaskFailedToBackupAudioFile": "No s'ha pogut fer una còpia de seguretat del fitxer d'àudio «{0}»",
"MessageTaskFailedToCreateCacheDirectory": "Error en crear el directori de la memòria cau",
"MessageTaskFailedToEmbedMetadataInFile": "Error en incrustar metadades en el fitxer \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Error en fusionar fitxers d'àudio",
@@ -816,14 +841,14 @@
"MessageTaskMatchingBooksInLibrary": "Coincidint llibres a la biblioteca \"{0}\"",
"MessageTaskNoFilesToScan": "Sense fitxers per escanejar",
"MessageTaskOpmlImport": "Importar OPML",
"MessageTaskOpmlImportDescription": "Creant podcasts a partir de {0} fonts RSS",
"MessageTaskOpmlImportFeed": "Importació de feed OPML",
"MessageTaskOpmlImportFeedDescription": "Importació del feed RSS \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "No es pot obtenir el podcast",
"MessageTaskOpmlImportFeedPodcastDescription": "Creant el podcast \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "El podcast ja existeix a la ruta",
"MessageTaskOpmlImportFeedPodcastFailed": "Error en crear el podcast",
"MessageTaskOpmlImportFinished": "Afegit {0} podcasts",
"MessageTaskOpmlImportDescription": "S'estan creant pòdcasts a partir de {0} canals RSS",
"MessageTaskOpmlImportFeed": "Importació d'un canal OPML",
"MessageTaskOpmlImportFeedDescription": "S'està important el canal RSS «{0}»",
"MessageTaskOpmlImportFeedFailed": "No s'ha pogut obtenir el canal del pòdcast",
"MessageTaskOpmlImportFeedPodcastDescription": "S'està creant el pòdcast «{0}»",
"MessageTaskOpmlImportFeedPodcastExists": "El pòdcast ja existeix al camí",
"MessageTaskOpmlImportFeedPodcastFailed": "No s'ha pogut crear el pòdcast",
"MessageTaskOpmlImportFinished": "S'han afegit {0} pòdcasts",
"MessageTaskOpmlParseFailed": "No s'ha pogut analitzar el fitxer OPML",
"MessageTaskOpmlParseFastFail": "No s'ha trobat l'etiqueta <opml> o <outline> al fitxer OPML",
"MessageTaskOpmlParseNoneFound": "No s'han trobat fonts al fitxer OPML",
@@ -841,13 +866,13 @@
"MessageValidCronExpression": "Expressió de cron vàlida",
"MessageWatcherIsDisabledGlobally": "El watcher està desactivat globalment a la configuració del servidor",
"MessageXLibraryIsEmpty": "La biblioteca {0} està buida!",
"MessageYourAudiobookDurationIsLonger": "La durada del teu audiollibre és més llarga que la durada trobada",
"MessageYourAudiobookDurationIsShorter": "La durada del teu audiollibre és més curta que la durada trobada",
"MessageYourAudiobookDurationIsLonger": "La durada del vostre audiollibre és major que la durada trobada",
"MessageYourAudiobookDurationIsShorter": "La durada del vostre audiollibre és menor que la durada trobada",
"NoteChangeRootPassword": "L'usuari Root és l'únic usuari que pot no tenir una contrasenya",
"NoteChapterEditorTimes": "Nota: El temps d'inici del primer capítol ha de romandre a 0:00, i el temps d'inici de l'últim capítol no pot superar la durada de l'audiollibre.",
"NoteFolderPicker": "Nota: Les carpetes ja assignades no es mostraran",
"NoteRSSFeedPodcastAppsHttps": "Advertència: La majoria d'aplicacions de podcast requereixen que la URL de la font RSS utilitzi HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Advertència: Un o més dels teus episodis no tenen data de publicació. Algunes aplicacions de podcast ho requereixen.",
"NoteChapterEditorTimes": "Nota: el temps d'inici del primer capítol ha de romandre a 0:00, i el temps d'inici de l'últim capítol no pot superar la durada de l'audiollibre.",
"NoteFolderPicker": "Nota: les carpetes ja assignades no es mostraran",
"NoteRSSFeedPodcastAppsHttps": "Avís: la majoria d'aplicacions de pòdcast requereixen que l'URL del canal RSS utilitzi HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Avís: un o més dels vostres episodis no tenen data de publicació. Algunes aplicacions de pòdcast ho requereixen.",
"NoteUploaderFoldersWithMediaFiles": "Les carpetes amb fitxers multimèdia es gestionaran com a elements separats a la biblioteca.",
"NoteUploaderOnlyAudioFiles": "Si només puges fitxers d'àudio, cada fitxer es gestionarà com un audiollibre separat.",
"NoteUploaderUnsupportedFiles": "Els fitxers no compatibles seran ignorats. Si selecciona o arrossega una carpeta, els fitxers que no estiguin dins d'una subcarpeta seran ignorats.",
@@ -856,7 +881,7 @@
"NotificationOnEpisodeDownloadedDescription": "S'activa quan es descarrega automàticament un episodi d'un podcast",
"NotificationOnTestDescription": "Esdeveniment per provar el sistema de notificacions",
"PlaceholderNewCollection": "Nou nom de la col·lecció",
"PlaceholderNewFolderPath": "Nova ruta de carpeta",
"PlaceholderNewFolderPath": "Camí de carpeta nou",
"PlaceholderNewPlaylist": "Nou nom de la llista de reproducció",
"PlaceholderSearch": "Cerca...",
"PlaceholderSearchEpisode": "Cerca d'episodis...",
@@ -882,7 +907,7 @@
"ToastAppriseUrlRequired": "Cal introduir una URL de Apprise",
"ToastAsinRequired": "ASIN requerit",
"ToastAuthorImageRemoveSuccess": "S'ha eliminat la imatge de l'autor",
"ToastAuthorNotFound": "No s'ha trobat l'autor \"{0}\"",
"ToastAuthorNotFound": "No s'ha trobat l'autor «{0}»",
"ToastAuthorRemoveSuccess": "Autor eliminat",
"ToastAuthorSearchNotFound": "No s'ha trobat l'autor",
"ToastAuthorUpdateMerged": "Autor combinat",
@@ -898,6 +923,7 @@
"ToastBackupRestoreFailed": "Error en restaurar la còpia de seguretat",
"ToastBackupUploadFailed": "Error en carregar la còpia de seguretat",
"ToastBackupUploadSuccess": "Còpia de seguretat carregada",
"ToastBatchApplyDetailsToItemsSuccess": "S'han aplicat els detalls als elements",
"ToastBatchDeleteFailed": "Error en l'eliminació per lots",
"ToastBatchDeleteSuccess": "Eliminació per lots correcte",
"ToastBatchQuickMatchFailed": "Error en la sincronització ràpida per lots!",
@@ -910,6 +936,8 @@
"ToastCachePurgeFailed": "Error en purgar la memòria cau",
"ToastCachePurgeSuccess": "Memòria cau purgada amb èxit",
"ToastChaptersHaveErrors": "Els capítols tenen errors",
"ToastChaptersInvalidShiftAmountLast": "La quantitat de desplaçament no és vàlida. L'hora d'inici de l'últim capítol s'estendria més enllà de la durada d'aquest audiollibre.",
"ToastChaptersInvalidShiftAmountStart": "La quantitat de desplaçament no és vàlida. El primer capítol tindria una durada zero o negativa i el sobreescriuria el segon capítol. Augmenteu la durada inicial del segon capítol.",
"ToastChaptersMustHaveTitles": "Els capítols han de tenir un títol",
"ToastChaptersRemoved": "Capítols eliminats",
"ToastChaptersUpdated": "Capítols actualitzats",
@@ -917,6 +945,7 @@
"ToastCollectionRemoveSuccess": "Col·lecció eliminada",
"ToastCollectionUpdateSuccess": "Col·lecció actualitzada",
"ToastCoverUpdateFailed": "Error en actualitzar la portada",
"ToastDateTimeInvalidOrIncomplete": "La data i hora no és vàlida o està incompleta",
"ToastDeleteFileFailed": "No s'ha pogut suprimir el fitxer",
"ToastDeleteFileSuccess": "Fitxer suprimit",
"ToastDeviceAddFailed": "Error en afegir el dispositiu",
@@ -947,34 +976,35 @@
"ToastItemMarkedAsNotFinishedSuccess": "Element marcat com a no acabat",
"ToastItemUpdateSuccess": "Element actualitzat",
"ToastLibraryCreateFailed": "Error en crear la biblioteca",
"ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada",
"ToastLibraryCreateSuccess": "S'ha creat la biblioteca «{0}»",
"ToastLibraryDeleteFailed": "Error en eliminar la biblioteca",
"ToastLibraryDeleteSuccess": "Biblioteca eliminada",
"ToastLibraryScanFailedToStart": "Error en iniciar l'escaneig",
"ToastLibraryScanStarted": "S'ha iniciat l'escaneig de la biblioteca",
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualitzada",
"ToastLibraryUpdateSuccess": "S'ha actualitzat la biblioteca «{0}»",
"ToastMatchAllAuthorsFailed": "No coincideix amb tots els autors",
"ToastMetadataFilesRemovedError": "Error en eliminar metadades de {0} arxius",
"ToastMetadataFilesRemovedNoneFound": "No s'han trobat metadades en {0} arxius",
"ToastMetadataFilesRemovedNoneRemoved": "Cap metadada eliminada en {0} arxius",
"ToastMetadataFilesRemovedError": "Sha produït un error en eliminar els fitxers metadata.{0}",
"ToastMetadataFilesRemovedNoneFound": "No hi ha cap fitxer metadata.{0} a la biblioteca",
"ToastMetadataFilesRemovedNoneRemoved": "No s'ha eliminat cap fitxer metadata.{0}",
"ToastMetadataFilesRemovedSuccess": "{0} metadades eliminades en {1} arxius",
"ToastMustHaveAtLeastOnePath": "Ha de tenir almenys una ruta",
"ToastNameEmailRequired": "El nom i el correu electrònic són obligatoris",
"ToastNameRequired": "Nom obligatori",
"ToastNewEpisodesFound": "{0} episodi(s) nou(s) trobat(s)",
"ToastNewUserCreatedFailed": "Error en crear el compte: \"{0}\"",
"ToastNewUserCreatedFailed": "No s'ha pogut crear el compte: «{0}»",
"ToastNewUserCreatedSuccess": "Nou compte creat",
"ToastNewUserLibraryError": "Ha de seleccionar almenys una biblioteca",
"ToastNewUserPasswordError": "Necessites una contrasenya, només el root pot estar sense contrasenya",
"ToastNewUserTagError": "Selecciona almenys una etiqueta",
"ToastNewUserUsernameError": "Introdueix un nom d'usuari",
"ToastNewUserLibraryError": "S'ha de seleccionar almenys una biblioteca",
"ToastNewUserPasswordError": "Cal una contrasenya; només l'usuari primari pot estar sense contrasenya",
"ToastNewUserTagError": "S'ha de seleccionar almenys una etiqueta",
"ToastNewUserUsernameError": "Introduïu un nom d'usuari",
"ToastNoNewEpisodesFound": "No s'han trobat nous episodis",
"ToastNoRSSFeed": "El pòdcast no té canal RSS",
"ToastNoUpdatesNecessary": "No cal actualitzar",
"ToastNotificationCreateFailed": "Error en crear la notificació",
"ToastNotificationDeleteFailed": "Error en eliminar la notificació",
"ToastNotificationCreateFailed": "No s'ha pogut crear la notificació",
"ToastNotificationDeleteFailed": "No s'ha pogut suprimir la notificació",
"ToastNotificationFailedMaximum": "El nombre màxim d'intents fallits ha de ser ≥ 0",
"ToastNotificationQueueMaximum": "La cua de notificació màxima ha de ser ≥ 0",
"ToastNotificationSettingsUpdateSuccess": "Configuració de notificació actualitzada",
"ToastNotificationSettingsUpdateSuccess": "S'han actualitzat els paràmetres de notificacions",
"ToastNotificationTestTriggerFailed": "No s'ha pogut activar la notificació de prova",
"ToastNotificationTestTriggerSuccess": "Notificació de prova activada",
"ToastNotificationUpdateSuccess": "Notificació actualitzada",
@@ -984,16 +1014,16 @@
"ToastPlaylistUpdateSuccess": "Llista de reproducció actualitzada",
"ToastPodcastCreateFailed": "No s'ha pogut crear el pòdcast",
"ToastPodcastCreateSuccess": "S'ha creat el pòdcast correctament",
"ToastPodcastGetFeedFailed": "No s'ha pogut obtenir el podcast",
"ToastPodcastNoEpisodesInFeed": "No s'han trobat episodis en el feed RSS",
"ToastPodcastNoRssFeed": "El podcast no té un feed RSS",
"ToastPodcastGetFeedFailed": "No s'ha pogut obtenir el canal del pòdcast",
"ToastPodcastNoEpisodesInFeed": "No s'ha trobat cap episodi al canal RSS",
"ToastPodcastNoRssFeed": "El pòdcast no té un canal RSS",
"ToastProgressIsNotBeingSynced": "El progrés no s'està sincronitzant, reinicia la reproducció",
"ToastProviderCreatedFailed": "Error en afegir el proveïdor",
"ToastProviderCreatedSuccess": "Nou proveïdor afegit",
"ToastProviderNameAndUrlRequired": "Nom i URL obligatoris",
"ToastProviderRemoveSuccess": "Proveïdor eliminat",
"ToastRSSFeedCloseFailed": "Error en tancar el feed RSS",
"ToastRSSFeedCloseSuccess": "Feed RSS tancat",
"ToastRSSFeedCloseFailed": "No s'ha pogut tancar el canal RSS",
"ToastRSSFeedCloseSuccess": "Canal RSS tancat",
"ToastRemoveFailed": "Error en eliminar",
"ToastRemoveItemFromCollectionFailed": "Error en eliminar l'element de la col·lecció",
"ToastRemoveItemFromCollectionSuccess": "Element eliminat de la col·lecció",
@@ -1007,7 +1037,8 @@
"ToastScanFailed": "No s'ha pogut escanejar l'element de la biblioteca",
"ToastSelectAtLeastOneUser": "Selecciona almenys un usuari",
"ToastSendEbookToDeviceFailed": "Error en enviar l'ebook al dispositiu",
"ToastSendEbookToDeviceSuccess": "Ebook enviat al dispositiu \"{0}\"",
"ToastSendEbookToDeviceSuccess": "El llibre electrònic s'ha enviat al dispositiu «{0}»",
"ToastSeriesSubmitFailedSameName": "No és possible afegir dues sèries amb el mateix nom",
"ToastSeriesUpdateFailed": "Error en actualitzar la sèrie",
"ToastSeriesUpdateSuccess": "Sèrie actualitzada",
"ToastServerSettingsUpdateSuccess": "Configuració del servidor actualitzada",
@@ -1026,6 +1057,8 @@
"ToastUnknownError": "Error desconegut",
"ToastUnlinkOpenIdFailed": "Error en desvincular l'usuari d'OpenID",
"ToastUnlinkOpenIdSuccess": "Usuari desvinculat d'OpenID",
"ToastUploaderFilepathExistsError": "El camí del fitxer «{0}» ja existeix al servidor",
"ToastUploaderItemExistsInSubdirectoryError": "L'element «{0}» usa un subdirectori del camí de pujada.",
"ToastUserDeleteFailed": "Error en eliminar l'usuari",
"ToastUserDeleteSuccess": "Usuari eliminat",
"ToastUserPasswordChangeSuccess": "Contrasenya canviada correctament",

View File

@@ -10,6 +10,8 @@
"ButtonApplyChapters": "Aplikovat kapitoly",
"ButtonAuthors": "Autoři",
"ButtonBack": "Zpět",
"ButtonBatchEditPopulateFromExisting": "Vytvořit z existujících",
"ButtonBatchEditPopulateMapDetails": "Předvyplnit podrobnosti mapování",
"ButtonBrowseForFolder": "Vyhledat složku",
"ButtonCancel": "Zrušit",
"ButtonCancelEncode": "Zrušit kódování",
@@ -145,7 +147,7 @@
"HeaderItemFiles": "Soubory položek",
"HeaderItemMetadataUtils": "Nástroje metadat položek",
"HeaderLastListeningSession": "Poslední poslechová relace",
"HeaderLatestEpisodes": "Nejnovější epizody",
"HeaderLatestEpisodes": "Nové epizody",
"HeaderLibraries": "Knihovny",
"HeaderLibraryFiles": "Soubory knihovny",
"HeaderLibraryStats": "Statistiky knihovny",
@@ -227,6 +229,7 @@
"LabelAddedDate": "Přidáno {0}",
"LabelAdminUsersOnly": "Pouze administrátoři",
"LabelAll": "Vše",
"LabelAllEpisodesDownloaded": "Všechny epizody staženy",
"LabelAllUsers": "Všichni uživatelé",
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
@@ -250,7 +253,7 @@
"LabelBackToUser": "Zpět k uživateli",
"LabelBackupAudioFiles": "Zálohovat zvukové soubory",
"LabelBackupLocation": "Umístění zálohy",
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
"LabelBackupsEnableAutomaticBackups": "Automatické zálohování",
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximální velikost zálohy (v GB) (0 bez omezení)",
"LabelBackupsMaxBackupSizeHelp": "Ochrana proti chybné konfiguraci: Zálohování se nezdaří, pokud překročí nastavenou velikost.",
@@ -282,6 +285,7 @@
"LabelContinueSeries": "Pokračovat v sérii",
"LabelCover": "Obálka",
"LabelCoverImageURL": "URL obrázku obálky",
"LabelCoverProvider": "Poskytovatel obálky",
"LabelCreatedAt": "Vytvořeno v",
"LabelCronExpression": "Výraz Cronu",
"LabelCurrent": "Aktuální",
@@ -421,7 +425,7 @@
"LabelLookForNewEpisodesAfterDate": "Hledat nové epizody po tomto datu",
"LabelLowestPriority": "Nejnižší priorita",
"LabelMatchExistingUsersBy": "Přiřadit stávající uživatele podle",
"LabelMatchExistingUsersByDescription": "Slouží k propojení stávajících uživatelů. Po propojení budou uživatelé přiřazeni k jedinečnému ID od poskytovatele SSO.",
"LabelMatchExistingUsersByDescription": "Slouží k propojení stávajících uživatelů. Po propojení budou uživatelé přiřazeni k jedinečnému ID od poskytovatele SSO",
"LabelMaxEpisodesToDownload": "Maximální # epizod pro stažení. Použijte 0 pro bez omezení.",
"LabelMaxEpisodesToDownloadPerCheck": "Maximální počet nových epizod ke stažení při jedné kontrole",
"LabelMaxEpisodesToKeep": "Maximální počet epizod k zachování",
@@ -430,7 +434,7 @@
"LabelMediaType": "Typ média",
"LabelMetaTag": "Metaznačka",
"LabelMetaTags": "Metaznačky",
"LabelMetadataOrderOfPrecedenceDescription": "Zdroje metadat s vyšší prioritou budou mít přednost před zdroji metadat s nižší prioritou.",
"LabelMetadataOrderOfPrecedenceDescription": "Zdroje metadat s vyšší prioritou budou mít přednost před zdroji metadat s nižší prioritou",
"LabelMetadataProvider": "Poskytovatel metadat",
"LabelMinute": "Minuta",
"LabelMinutes": "Minuty",
@@ -555,6 +559,8 @@
"LabelSettingsBookshelfViewHelp": "Skeumorfní design s dřevěnými policemi",
"LabelSettingsChromecastSupport": "Podpora Chromecastu",
"LabelSettingsDateFormat": "Formát data",
"LabelSettingsEnableWatcher": "Automaticky skenovat změny v knihovnách",
"LabelSettingsEnableWatcherForLibrary": "Automaticky skenovat změny v knihovně",
"LabelSettingsEnableWatcherHelp": "Povoluje automatické přidávání/aktualizaci položek, když jsou zjištěny změny souborů. *Vyžaduje restart serveru",
"LabelSettingsEpubsAllowScriptedContent": "Povolení skriptovaného obsahu v epubu",
"LabelSettingsEpubsAllowScriptedContentHelp": "Povolení spouštění skriptů v souborech epub. Doporučujeme toto nastavení vypnout, pokud nedůvěřujete zdroji souborů epub.",
@@ -598,6 +604,7 @@
"LabelSlug": "URL název",
"LabelSortAscending": "Vzestupně",
"LabelSortDescending": "Sestupně",
"LabelSortPubDate": "Seřadit podle datumu publikování",
"LabelStart": "Spustit",
"LabelStartTime": "Čas Spuštění",
"LabelStarted": "Spuštěno",
@@ -698,10 +705,13 @@
"LabelYourProgress": "Váš pokrok",
"MessageAddToPlayerQueue": "Přidat do fronty přehrávače",
"MessageAppriseDescription": "Abyste mohli používat tuto funkci, musíte mít spuštěnou instanci <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nebo API, které bude zpracovávat stejné požadavky. <br />Adresa URL API Apprise by měla být úplná URL cesta pro odeslání oznámení, např. pokud je vaše instance API obsluhována na adrese <code>http://192.168.1.1:8337</code> pak byste měli zadat <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Ujistěte se, že používáte ASIN ze správného regionu Audible a ne z Amazonu.",
"MessageBackupsDescription": "Zálohy zahrnují uživatele, průběh uživatele, podrobnosti o položkách knihovny, nastavení serveru a obrázky uložené v <code>/metadata/items</code> a <code>/metadata/authors</code>. Zálohy <strong>ne</strong> zahrnují všechny soubory uložené ve složkách knihovny.",
"MessageBackupsLocationEditNote": "Poznámka: Změna umístění záloh nepřesune ani nezmění existující zálohy",
"MessageBackupsLocationNoEditNote": "Poznámka: Umístění záloh je nastavené z proměnných prostředí a nelze zde změnit.",
"MessageBackupsLocationPathEmpty": "Umístění záloh nemůže být prázdné",
"MessageBatchEditPopulateMapDetailsAllHelp": "Předvyplnit vybraná pole datami ze všech položek. Pole s více hodnotami budou sloučena",
"MessageBatchEditPopulateMapDetailsItemHelp": "Předvyplnit povolená pole mapování daty z této položky",
"MessageBatchQuickMatchDescription": "Rychlá párování se pokusí přidat chybějící obálky a metadata pro vybrané položky. Povolením níže uvedených možností umožníte funkci Rychlé párování přepsat stávající obálky a/nebo metadata.",
"MessageBookshelfNoCollections": "Ještě jste nevytvořili žádnou sbírku",
"MessageBookshelfNoCollectionsHelp": "Kolekce jsou veřejné. Mohou je zobrazit všichni uživatelé s přístupem do knihovny.",
@@ -714,6 +724,7 @@
"MessageChapterErrorStartGteDuration": "Neplatný čas začátku, musí být kratší než doba trvání audioknihy",
"MessageChapterErrorStartLtPrev": "Neplatný čas začátku, musí být větší nebo roven času začátku předchozí kapitoly",
"MessageChapterStartIsAfter": "Začátek kapitoly přesahuje konec audioknihy",
"MessageChaptersNotFound": "Kapitoly nenalezeny",
"MessageCheckingCron": "Kontrola cronu...",
"MessageConfirmCloseFeed": "Opravdu chcete zavřít tento kanál?",
"MessageConfirmDeleteBackup": "Opravdu chcete smazat zálohu pro {0}?",
@@ -770,6 +781,7 @@
"MessageForceReScanDescription": "znovu prohledá všechny soubory jako při novém skenování. ID3 tagy zvukových souborů OPF soubory a textové soubory budou skenovány jako nové.",
"MessageImportantNotice": "Důležité upozornění!",
"MessageInsertChapterBelow": "Vložit kapitolu níže",
"MessageInvalidAsin": "Neplatný ASIN",
"MessageItemsSelected": "{0} vybraných položek",
"MessageItemsUpdated": "{0} položky byly aktualizovány",
"MessageJoinUsOn": "Přidejte se k nám",
@@ -838,6 +850,7 @@
"MessageRestoreBackupConfirm": "Opravdu chcete obnovit zálohu vytvořenou dne",
"MessageRestoreBackupWarning": "Obnovení zálohy přepíše celou databázi umístěnou v /config a obálku obrázků v /metadata/items & /metadata/authors.<br /><br />Backups nezmění žádné soubory ve složkách knihovny. Pokud jste povolili nastavení serveru pro ukládání obrázků obalu a metadat do složek knihovny, nebudou zálohovány ani přepsány.<br /><br />Všichni klienti používající váš server budou automaticky obnoveni.",
"MessageScheduleLibraryScanNote": "Většině uživatelů se doporučuje ponechat tuto funkci vypnutou a ponechat zapnuté nastavení sledování složek. Sledování složek automaticky zjistí změny ve složkách vaší knihovny. Sledování složek nefunguje pro každý souborový systém (jako je NFS), takže místo toho lze použít plánované skenování knihoven.",
"MessageScheduleRunEveryWeekdayAtTime": "Spusť každý {0} v {1}",
"MessageSearchResultsFor": "Výsledky hledání pro",
"MessageSelected": "{0} vybráno",
"MessageServerCouldNotBeReached": "Server je nedostupný",
@@ -945,6 +958,7 @@
"ToastBackupRestoreFailed": "Nepodařilo se obnovit zálohu",
"ToastBackupUploadFailed": "Nepodařilo se nahrát zálohu",
"ToastBackupUploadSuccess": "Záloha nahrána",
"ToastBatchApplyDetailsToItemsSuccess": "Detaily aplikované na položky",
"ToastBatchDeleteFailed": "Hromadné smazání selhalo",
"ToastBatchDeleteSuccess": "Hromadné smazání proběhlo úspěšně",
"ToastBatchQuickMatchFailed": "Rychlá schoda dávky se nezdařila!",
@@ -1057,6 +1071,7 @@
"ToastSelectAtLeastOneUser": "Vyberte alespoň jednoho uživatele",
"ToastSendEbookToDeviceFailed": "Odeslání e-knihy do zařízení se nezdařilo",
"ToastSendEbookToDeviceSuccess": "E-kniha odeslána do zařízení \"{0}\"",
"ToastSeriesSubmitFailedSameName": "Nelze přidat dvě série se stejným názvem",
"ToastSeriesUpdateFailed": "Aktualizace série se nezdařila",
"ToastSeriesUpdateSuccess": "Aktualizace série byla úspěšná",
"ToastServerSettingsUpdateSuccess": "Nastavení serveru aktualizováno",
@@ -1075,6 +1090,8 @@
"ToastUnknownError": "Neznámý error",
"ToastUnlinkOpenIdFailed": "Chyba při odpárování uživatele z OpenID",
"ToastUnlinkOpenIdSuccess": "Uživatel odpárován z uživatele z OpenID",
"ToastUploaderFilepathExistsError": "Soubor \"{0}\" na serveru již existuje",
"ToastUploaderItemExistsInSubdirectoryError": "Položka \"{0}\" používá podsložku nahrávané cesty.",
"ToastUserDeleteFailed": "Nepodařilo se smazat uživatele",
"ToastUserDeleteSuccess": "Uživatel smazán",
"ToastUserPasswordChangeSuccess": "Heslo bylo změněno úspěšně",

View File

@@ -229,6 +229,7 @@
"LabelAddedDate": "Tilføjet {0}",
"LabelAdminUsersOnly": "Kun Administratorer",
"LabelAll": "Alle",
"LabelAllEpisodesDownloaded": "Alle episoder hentet",
"LabelAllUsers": "Alle Brugere",
"LabelAllUsersExcludingGuests": "Alle bruger eksklusiv gæster",
"LabelAllUsersIncludingGuests": "Alle bruger inklusiv gæster",
@@ -252,7 +253,7 @@
"LabelBackToUser": "Tilbage til Bruger",
"LabelBackupAudioFiles": "Sikkerhedskopier lydfiler",
"LabelBackupLocation": "Backup Placering",
"LabelBackupsEnableAutomaticBackups": "Aktivér automatisk sikkerhedskopiering",
"LabelBackupsEnableAutomaticBackups": "Automatisk sikkerhedskopiering",
"LabelBackupsEnableAutomaticBackupsHelp": "Sikkerhedskopier gemt i /metadata/backups",
"LabelBackupsMaxBackupSize": "Maksimal sikkerhedskopistørrelse (i GB) (0 for ubegrænset)",
"LabelBackupsMaxBackupSizeHelp": "Som en beskyttelse mod fejlkonfiguration fejler sikkerhedskopier, hvis de overstiger den konfigurerede størrelse.",
@@ -558,6 +559,8 @@
"LabelSettingsBookshelfViewHelp": "Skeumorfisk design med træhylder",
"LabelSettingsChromecastSupport": "Chromecast-understøttelse",
"LabelSettingsDateFormat": "Datoformat",
"LabelSettingsEnableWatcher": "Scan automatisk bibliotek for ændringer",
"LabelSettingsEnableWatcherForLibrary": "Scan automatisk bibliotek for ændringer",
"LabelSettingsEnableWatcherHelp": "Aktiverer automatisk tilføjelse/opdatering af elementer, når filændringer registreres. *Kræver servergenstart",
"LabelSettingsEpubsAllowScriptedContent": "Tillad scriptet indhold i epub",
"LabelSettingsEpubsAllowScriptedContentHelp": "Tillad epub filer at køre scripts. Det anbefales at holde denne indstilling deaktiveret med mindre du stoler på kilderne af epub filerne.",
@@ -1063,6 +1066,7 @@
"ToastSelectAtLeastOneUser": "Vælg mindst en bruger",
"ToastSendEbookToDeviceFailed": "Mislykkedes afsendelse af e-bog til enhed",
"ToastSendEbookToDeviceSuccess": "E-bog afsendt til enhed \"{0}\"",
"ToastSeriesSubmitFailedSameName": "Kan ikke tilføje to serier med samme navn",
"ToastSeriesUpdateFailed": "Mislykkedes opdatering af serie",
"ToastSeriesUpdateSuccess": "Serieopdatering lykkedes",
"ToastServerSettingsUpdateSuccess": "Server indstillinger opdateret",
@@ -1081,6 +1085,8 @@
"ToastUnknownError": "Ukendt fejl",
"ToastUnlinkOpenIdFailed": "Fejlede i af afkoble bruger fra OpenID",
"ToastUnlinkOpenIdSuccess": "Bruger afkoblet fra OpenID",
"ToastUploaderFilepathExistsError": "Filsti \"{0}\" findes allerede på serveren",
"ToastUploaderItemExistsInSubdirectoryError": "Genstand \"{0}\" benytter en undermappe af upload stien",
"ToastUserDeleteFailed": "Mislykkedes sletning af bruger",
"ToastUserDeleteSuccess": "Bruger slettet",
"ToastUserPasswordChangeSuccess": "Password ændret",

View File

@@ -88,7 +88,7 @@
"ButtonSave": "Speichern",
"ButtonSaveAndClose": "Speichern & Schließen",
"ButtonSaveTracklist": "Speichere die Titelliste",
"ButtonScan": "Partial-Scan (nur geänderte/neue Medien)",
"ButtonScan": "Scannen",
"ButtonScanLibrary": "Bibliothek scannen",
"ButtonScrollLeft": "Nach Links scrollen",
"ButtonScrollRight": "Nach Rechts scrollen",
@@ -177,6 +177,7 @@
"HeaderPlaylist": "Wiedergabeliste",
"HeaderPlaylistItems": "Einträge in der Wiedergabeliste",
"HeaderPodcastsToAdd": "Podcasts zum Hinzufügen",
"HeaderPresets": "Voreinstellungen",
"HeaderPreviewCover": "Vorschau Titelbild",
"HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS-Feed ist geöffnet",
@@ -229,6 +230,7 @@
"LabelAddedDate": "{0} Hinzugefügt",
"LabelAdminUsersOnly": "Nur Admin Benutzer",
"LabelAll": "Alle",
"LabelAllEpisodesDownloaded": "Alle Episoden heruntergeladen",
"LabelAllUsers": "Alle Benutzer",
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
"LabelAllUsersIncludingGuests": "Alle Benutzer und Gäste",
@@ -397,7 +399,7 @@
"LabelInvert": "Umkehren",
"LabelItem": "Medium",
"LabelJumpBackwardAmount": "Zurückspringen Zeit",
"LabelJumpForwardAmount": "Vorwärtsspringn Zeit",
"LabelJumpForwardAmount": "Vorwärtsspringen Zeit",
"LabelLanguage": "Sprache",
"LabelLanguageDefaultServer": "Standard-Server-Sprache",
"LabelLanguages": "Sprachen",
@@ -529,6 +531,7 @@
"LabelReleaseDate": "Veröffentlichungsdatum",
"LabelRemoveAllMetadataAbs": "Alle metadata.abs Dateien löschen",
"LabelRemoveAllMetadataJson": "Alle metadata.json Dateien löschen",
"LabelRemoveAudibleBranding": "Audible Intro sowie Outro aus Kapiteln entfernen",
"LabelRemoveCover": "Entferne Titelbild",
"LabelRemoveMetadataFile": "Metadaten-Dateien in Bibliotheksordnern löschen",
"LabelRemoveMetadataFileHelp": "Alle metadata.json und metadata.abs Dateien aus den Ordnern {0} löschen.",
@@ -603,6 +606,7 @@
"LabelSlug": "URL Teil",
"LabelSortAscending": "Aufsteigend",
"LabelSortDescending": "Absteigend",
"LabelSortPubDate": "Erscheinungsdatum",
"LabelStart": "Start",
"LabelStartTime": "Startzeit",
"LabelStarted": "Gestartet",
@@ -703,6 +707,8 @@
"LabelYourProgress": "Fortschritt",
"MessageAddToPlayerQueue": "Zur Abspielwarteliste hinzufügen",
"MessageAppriseDescription": "Um diese Funktion nutzen zu können, musst du eine Instanz von <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> laufen haben oder eine API verwenden welche dieselbe Anfragen bearbeiten kann. <br />Die Apprise API Url muss der vollständige URL-Pfad sein, an den die Benachrichtigung gesendet werden soll, z.B. wenn Ihre API-Instanz unter <code>http://192.168.1.1:8337</code> läuft, würdest du <code>http://192.168.1.1:8337/notify</code> eingeben.",
"MessageAsinCheck": "Stellen Sie sicher, dass Sie die ASIN aus der richtigen Audible Region verwenden, nicht Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Nach dem Speichern muß der Server neugestartet werden um die OIDC Änderungen zu übernehmen.",
"MessageBackupsDescription": "In einer Sicherung werden Benutzer, Benutzerfortschritte, Details zu den Bibliotheksobjekten, Servereinstellungen und Bilder welche in <code>/metadata/items</code> & <code>/metadata/authors</code> gespeichert sind gespeichert. Sicherungen enthalten keine Dateien welche in den einzelnen Bibliotheksordnern (Medien-Ordnern) gespeichert sind.",
"MessageBackupsLocationEditNote": "Hinweis: Durch das Aktualisieren des Backup-Speicherorts werden vorhandene Sicherungen nicht verschoben oder geändert",
"MessageBackupsLocationNoEditNote": "Hinweis: Der Sicherungsspeicherort wird über eine Umgebungsvariable festgelegt und kann hier nicht geändert werden.",
@@ -721,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Ungültige Kapitelstartzeit: Kapitelanfang > Mediumlänge (Kapitelanfang liegt zeitlich nach dem Ende des Mediums -> Lösung: Kapitelanfang < Mediumlänge)",
"MessageChapterErrorStartLtPrev": "Ungültige Kapitelstartzeit: Kapitelanfang < Kapitelanfang vorheriges Kapitel (Kapitelanfang liegt zeitlich vor dem Beginn des vorherigen Kapitels -> Lösung: Kapitelanfang >= Startzeit des vorherigen Kapitels)",
"MessageChapterStartIsAfter": "Ungültige Kapitelstartzeit: Kapitelanfang > Mediumende (Kapitelanfang liegt nach dem Ende des Mediums)",
"MessageChaptersNotFound": "Kapitel gefunden nicht",
"MessageCheckingCron": "Überprüfe Cron...",
"MessageConfirmCloseFeed": "Feed wird geschlossen! Bist du dir sicher?",
"MessageConfirmDeleteBackup": "Sicherung für {0} wird gelöscht! Bist du dir sicher?",
@@ -777,6 +784,7 @@
"MessageForceReScanDescription": "Durchsucht alle Dateien erneut, wie bei einem frischen Scan. ID3-Tags von Audiodateien, OPF-Dateien und Textdateien werden neu durchsucht.",
"MessageImportantNotice": "Wichtiger Hinweis!",
"MessageInsertChapterBelow": "Kapitel unten einfügen",
"MessageInvalidAsin": "Ungültige ASIN",
"MessageItemsSelected": "{0} ausgewählte Medien",
"MessageItemsUpdated": "{0} Medien aktualisiert",
"MessageJoinUsOn": "Besuche uns auf",
@@ -848,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Immer {0} um {1} ausführen",
"MessageSearchResultsFor": "Suchergebnisse für",
"MessageSelected": "{0} ausgewählt",
"MessageSeriesSequenceCannotContainSpaces": "Serie Abfolge kann keine Leerzeichen enthalten",
"MessageServerCouldNotBeReached": "Server kann nicht erreicht werden",
"MessageSetChaptersFromTracksDescription": "Kaitelerstellung basiert auf den existierenden einzelnen Audiodateien. Pro existierende Audiodatei wird 1 Kapitel erstellt, wobei deren Kapitelname aus dem Audiodateinamen extrahiert wird",
"MessageShareExpirationWillBe": "Läuft am <strong>{0}</strong> ab",
@@ -953,6 +962,7 @@
"ToastBackupRestoreFailed": "Sicherung konnte nicht wiederhergestellt werden",
"ToastBackupUploadFailed": "Sicherung konnte nicht hochgeladen werden",
"ToastBackupUploadSuccess": "Sicherung hochgeladen",
"ToastBatchApplyDetailsToItemsSuccess": "Details auf Medien anwenden",
"ToastBatchDeleteFailed": "Batch-Löschen fehlgeschlagen",
"ToastBatchDeleteSuccess": "Batch-Löschung erfolgreich",
"ToastBatchQuickMatchFailed": "Batch-Schnellabgleich fehlgeschlagen!",
@@ -965,6 +975,8 @@
"ToastCachePurgeFailed": "Cache leeren fehlgeschlagen",
"ToastCachePurgeSuccess": "Cache geleert",
"ToastChaptersHaveErrors": "Kapitel sind fehlerhaft",
"ToastChaptersInvalidShiftAmountLast": "Die Verschiebung ist nicht möglich, da die Startzeit des letzten Kapitels über die Gesamtdauer dieses Hörbuchs hinausgehen würde.",
"ToastChaptersInvalidShiftAmountStart": "Ungültige Höhe der Verschiebung. Das erste Kapitel hätte eine Länge von Null oder eine negative Länge und würde vom zweiten Kapitel überschrieben werden. Erhöhen Sie die Startdauer des zweiten Kapitels.",
"ToastChaptersMustHaveTitles": "Kapitel benötigen eindeutige Namen",
"ToastChaptersRemoved": "Kapitel entfernt",
"ToastChaptersUpdated": "Kapitel aktualisiert",
@@ -1065,6 +1077,7 @@
"ToastSelectAtLeastOneUser": "Wähle mindestens einen Benutzer aus",
"ToastSendEbookToDeviceFailed": "E-Buch konnte nicht auf Gerät übertragen werden",
"ToastSendEbookToDeviceSuccess": "E-Buch an Gerät „{0}“ gesendet",
"ToastSeriesSubmitFailedSameName": "Serien mit dem selben Namen können nicht hinzugefügt werden",
"ToastSeriesUpdateFailed": "Aktualisierung der Serien fehlgeschlagen",
"ToastSeriesUpdateSuccess": "Serien aktualisiert",
"ToastServerSettingsUpdateSuccess": "Die Server-Einstellungen wurden geupdated",
@@ -1083,6 +1096,8 @@
"ToastUnknownError": "Unbekannter Fehler",
"ToastUnlinkOpenIdFailed": "Fehler beim entkoppeln des Benutzers von OpenID",
"ToastUnlinkOpenIdSuccess": "Benutzer entkoppelt von OpenID",
"ToastUploaderFilepathExistsError": "Dateipfad \"{0}\" ist bereits auf dem Server horhanden",
"ToastUploaderItemExistsInSubdirectoryError": "Element \"{0}\" verwendet ein Unterverzeichnis des Upload-Pfads.",
"ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden",
"ToastUserDeleteSuccess": "Benutzer gelöscht",
"ToastUserPasswordChangeSuccess": "Passwort erfolgreich verändert",

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Playlist",
"HeaderPlaylistItems": "Playlist Items",
"HeaderPodcastsToAdd": "Podcasts to Add",
"HeaderPresets": "Presets",
"HeaderPreviewCover": "Preview Cover",
"HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed is Open",
@@ -530,6 +531,7 @@
"LabelReleaseDate": "Release Date",
"LabelRemoveAllMetadataAbs": "Remove all metadata.abs files",
"LabelRemoveAllMetadataJson": "Remove all metadata.json files",
"LabelRemoveAudibleBranding": "Remove Audible intro and outro from chapters",
"LabelRemoveCover": "Remove cover",
"LabelRemoveMetadataFile": "Remove metadata files in library item folders",
"LabelRemoveMetadataFileHelp": "Remove all metadata.json and metadata.abs files in your {0} folders.",
@@ -604,6 +606,7 @@
"LabelSlug": "Slug",
"LabelSortAscending": "Ascending",
"LabelSortDescending": "Descending",
"LabelSortPubDate": "Sort Pub Date",
"LabelStart": "Start",
"LabelStartTime": "Start Time",
"LabelStarted": "Started",
@@ -704,6 +707,8 @@
"LabelYourProgress": "Your Progress",
"MessageAddToPlayerQueue": "Add to player queue",
"MessageAppriseDescription": "To use this feature you will need to have an instance of <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> running or an api that will handle those same requests. <br />The Apprise API Url should be the full URL path to send the notification, e.g., if your API instance is served at <code>http://192.168.1.1:8337</code> then you would put <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Ensure you are using the ASIN from the correct Audible region, not Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Restart your server after saving to apply OIDC changes.",
"MessageBackupsDescription": "Backups include users, user progress, library item details, server settings, and images stored in <code>/metadata/items</code> & <code>/metadata/authors</code>. Backups <strong>do not</strong> include any files stored in your library folders.",
"MessageBackupsLocationEditNote": "Note: Updating the backup location will not move or modify existing backups",
"MessageBackupsLocationNoEditNote": "Note: The backup location is set through an environment variable and cannot be changed here.",
@@ -722,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Invalid start time must be less than audiobook duration",
"MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time",
"MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook",
"MessageChaptersNotFound": "Chapters not found",
"MessageCheckingCron": "Checking cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?",
@@ -778,6 +784,7 @@
"MessageForceReScanDescription": "will scan all files again like a fresh scan. Audio file ID3 tags, OPF files, and text files will be scanned as new.",
"MessageImportantNotice": "Important Notice!",
"MessageInsertChapterBelow": "Insert chapter below",
"MessageInvalidAsin": "Invalid ASIN",
"MessageItemsSelected": "{0} items selected",
"MessageItemsUpdated": "{0} items updated",
"MessageJoinUsOn": "Join us on",
@@ -849,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Run every {0} at {1}",
"MessageSearchResultsFor": "Search results for",
"MessageSelected": "{0} selected",
"MessageSeriesSequenceCannotContainSpaces": "Series sequence cannot contain spaces",
"MessageServerCouldNotBeReached": "Server could not be reached",
"MessageSetChaptersFromTracksDescription": "Set chapters using each audio file as a chapter and chapter title as the audio file name",
"MessageShareExpirationWillBe": "Expiration will be <strong>{0}</strong>",
@@ -967,6 +975,8 @@
"ToastCachePurgeFailed": "Failed to purge cache",
"ToastCachePurgeSuccess": "Cache purged successfully",
"ToastChaptersHaveErrors": "Chapters have errors",
"ToastChaptersInvalidShiftAmountLast": "Invalid shift amount. The last chapter start time would extend beyond the duration of this audiobook.",
"ToastChaptersInvalidShiftAmountStart": "Invalid shift amount. The first chapter would have zero or negative length and would be overwritten by the second chapter. Increase the start duration of second chapter.",
"ToastChaptersMustHaveTitles": "Chapters must have titles",
"ToastChaptersRemoved": "Chapters removed",
"ToastChaptersUpdated": "Chapters updated",

View File

@@ -10,13 +10,15 @@
"ButtonApplyChapters": "Aplicar capítulos",
"ButtonAuthors": "Autores",
"ButtonBack": "Atrás",
"ButtonBatchEditPopulateFromExisting": "Rellenar desde existentes",
"ButtonBatchEditPopulateMapDetails": "Rellenar detalles de mapa",
"ButtonBrowseForFolder": "Buscar carpeta",
"ButtonCancel": "Cancelar",
"ButtonCancelEncode": "Cancelar Codificador",
"ButtonCancelEncode": "Cancelar codificación",
"ButtonChangeRootPassword": "Cambiar contraseña administrativa",
"ButtonCheckAndDownloadNewEpisodes": "Comprobar y descargar episodios nuevos",
"ButtonChooseAFolder": "Escoger una Carpeta",
"ButtonChooseFiles": "Escoger un Archivo",
"ButtonChooseAFolder": "Elegir una carpeta",
"ButtonChooseFiles": "Elegir archivos",
"ButtonClearFilter": "Quitar filtros",
"ButtonCloseFeed": "Cerrar suministro",
"ButtonCloseSession": "Cerrar la sesión abierta",
@@ -77,9 +79,9 @@
"ButtonRemove": "Quitar",
"ButtonRemoveAll": "Quitar todo",
"ButtonRemoveAllLibraryItems": "Quitar todos los elementos de la biblioteca",
"ButtonRemoveFromContinueListening": "Remover de Continuar Escuchando",
"ButtonRemoveFromContinueReading": "Remover de Continuar Leyendo",
"ButtonRemoveSeriesFromContinueSeries": "Remover Serie de Continuar Series",
"ButtonRemoveFromContinueListening": "Quitar de Continuar escuchando",
"ButtonRemoveFromContinueReading": "Quitar de Continuar leyendo",
"ButtonRemoveSeriesFromContinueSeries": "Quitar serie de Continuar serie",
"ButtonReset": "Restablecer",
"ButtonResetToDefault": "Restaurar valores predeterminados",
"ButtonRestore": "Restaurar",
@@ -87,7 +89,7 @@
"ButtonSaveAndClose": "Guardar y cerrar",
"ButtonSaveTracklist": "Guardar lista de pistas",
"ButtonScan": "Escanear",
"ButtonScanLibrary": "Escanear Biblioteca",
"ButtonScanLibrary": "Escanear biblioteca",
"ButtonScrollLeft": "Desplazarse hacia la izquierda",
"ButtonScrollRight": "Desplazarse hacia la derecha",
"ButtonSearch": "Buscar",
@@ -147,7 +149,7 @@
"HeaderLastListeningSession": "Última sesión de escucha",
"HeaderLatestEpisodes": "Episodios más recientes",
"HeaderLibraries": "Bibliotecas",
"HeaderLibraryFiles": "Archivos de Biblioteca",
"HeaderLibraryFiles": "Archivos de biblioteca",
"HeaderLibraryStats": "Estadísticas de biblioteca",
"HeaderListeningSessions": "Sesión",
"HeaderListeningStats": "Estadísticas de Tiempo Escuchado",
@@ -175,6 +177,7 @@
"HeaderPlaylist": "Lista de reproducción",
"HeaderPlaylistItems": "Elementos de lista de reproducción",
"HeaderPodcastsToAdd": "Pódcast para añadir",
"HeaderPresets": "Preconfiguraciones",
"HeaderPreviewCover": "Previsualizar cubierta",
"HeaderRSSFeedGeneral": "Detalles de RSS",
"HeaderRSSFeedIsOpen": "El suministro RSS está abierto",
@@ -190,7 +193,7 @@
"HeaderSettings": "Configuración",
"HeaderSettingsDisplay": "Interfaz",
"HeaderSettingsExperimental": "Funcionalidades experimentales",
"HeaderSettingsGeneral": "General",
"HeaderSettingsGeneral": "Generales",
"HeaderSettingsScanner": "Escáner",
"HeaderSettingsWebClient": "Cliente web",
"HeaderSleepTimer": "Temporizador de apagado",
@@ -227,6 +230,7 @@
"LabelAddedDate": "{0} Añadido",
"LabelAdminUsersOnly": "Solamente usuarios administradores",
"LabelAll": "Todos",
"LabelAllEpisodesDownloaded": "Todos los episodios descargados",
"LabelAllUsers": "Todos los usuarios",
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
@@ -261,14 +265,14 @@
"LabelBooks": "Libros",
"LabelButtonText": "Texto del botón",
"LabelByAuthor": "por {0}",
"LabelChangePassword": "Cambiar Contraseña",
"LabelChangePassword": "Cambiar contraseña",
"LabelChannels": "Canales",
"LabelChapterCount": "{0} capítulos",
"LabelChapterTitle": "Titulo del Capítulo",
"LabelChapterTitle": "Título del capítulo",
"LabelChapters": "Capítulos",
"LabelChaptersFound": "Capítulo Encontrado",
"LabelClickForMoreInfo": "Click para más información",
"LabelClickToUseCurrentValue": "Haz clic para utilizar el valor actual",
"LabelChaptersFound": "capítulos encontrados",
"LabelClickForMoreInfo": "Pulse para más información",
"LabelClickToUseCurrentValue": "Pulse para utilizar el valor actual",
"LabelClosePlayer": "Cerrar reproductor",
"LabelCodec": "Codec",
"LabelCollapseSeries": "Colapsar serie",
@@ -276,7 +280,7 @@
"LabelCollection": "Colección",
"LabelCollections": "Colecciones",
"LabelComplete": "Completo",
"LabelConfirmPassword": "Confirmar Contraseña",
"LabelConfirmPassword": "Confirmar contraseña",
"LabelContinueListening": "Seguir escuchando",
"LabelContinueReading": "Continuar leyendo",
"LabelContinueSeries": "Continuar series",
@@ -287,8 +291,8 @@
"LabelCronExpression": "Expresión de Cron",
"LabelCurrent": "Actual",
"LabelCurrently": "En este momento:",
"LabelCustomCronExpression": "Expresión de Cron Personalizada:",
"LabelDatetime": "Hora y Fecha",
"LabelCustomCronExpression": "Expresión de Cron personalizada:",
"LabelDatetime": "Hora y fecha",
"LabelDays": "Días",
"LabelDeleteFromFileSystemCheckbox": "Eliminar del sistema de archivos (desmarque para quitar de la base de datos solamente)",
"LabelDescription": "Descripción",
@@ -367,7 +371,7 @@
"LabelFontStrikethrough": "Tachado",
"LabelFormat": "Formato",
"LabelFull": "Completo",
"LabelGenre": "Genero",
"LabelGenre": "Género",
"LabelGenres": "Géneros",
"LabelHardDeleteFile": "Eliminar Definitivamente",
"LabelHasEbook": "Tiene un libro",
@@ -436,8 +440,8 @@
"LabelMinute": "Minuto",
"LabelMinutes": "Minutos",
"LabelMissing": "Falta",
"LabelMissingEbook": "No tiene ebook",
"LabelMissingSupplementaryEbook": "No tiene ebook suplementario",
"LabelMissingEbook": "No tiene libro electrónico",
"LabelMissingSupplementaryEbook": "No tiene libro electrónico suplementario",
"LabelMobileRedirectURIs": "URIs de redirección a móviles permitidos",
"LabelMobileRedirectURIsDescription": "Esta es una lista blanca de URI de redireccionamiento válidos para aplicaciones móviles. El predeterminado es <code> audiobookshelf</code> , que puede eliminar o complementar con URI adicionales para la integración de aplicaciones de terceros. Usando un asterisco (<code> *</code> ) como única entrada que permite cualquier URI.",
"LabelMore": "Más",
@@ -458,17 +462,17 @@
"LabelNotes": "Notas",
"LabelNotificationAppriseURL": "URL(s) de Apprise",
"LabelNotificationAvailableVariables": "Variables disponibles",
"LabelNotificationBodyTemplate": "Plantilla de Cuerpo",
"LabelNotificationEvent": "Evento de Notificación",
"LabelNotificationTitleTemplate": "Plantilla de Titulo",
"LabelNotificationsMaxFailedAttempts": "Máximo de Intentos Fallidos",
"LabelNotificationBodyTemplate": "Plantilla de cuerpo",
"LabelNotificationEvent": "Evento de notificación",
"LabelNotificationTitleTemplate": "Plantilla de tulo",
"LabelNotificationsMaxFailedAttempts": "Máximo de intentos fallidos",
"LabelNotificationsMaxFailedAttemptsHelp": "Las notificaciones se desactivan después de fallar este número de veces",
"LabelNotificationsMaxQueueSize": "Tamaño máximo de la cola de notificaciones",
"LabelNotificationsMaxQueueSizeHelp": "Las notificaciones están limitadas a 1 por segundo. Las notificaciones serán ignoradas si llegan al numero máximo de cola para prevenir spam de eventos.",
"LabelNumberOfBooks": "Número de libros",
"LabelNumberOfEpisodes": "N.º de episodios",
"LabelOpenIDAdvancedPermsClaimDescription": "Nombre de la notificación de OpenID que contiene permisos avanzados para acciones de usuario dentro de la aplicación que se aplicarán a roles que no sean de administrador (<b>si están configurados</b>). Si el reclamo no aparece en la respuesta, se denegará el acceso a ABS. Si falta una sola opción, se tratará como <code>falsa</code>. Asegúrese de que la notificación del proveedor de identidades coincida con la estructura esperada:",
"LabelOpenIDClaims": "Deje las siguientes opciones vacías para deshabilitar la asignación avanzada de grupos y permisos, lo que asignaría de manera automática al grupo 'Usuario'.",
"LabelOpenIDClaims": "Deje las siguientes opciones vacías para desactivar la asignación avanzada de grupos y permisos, lo que asignaría de manera automática al grupo «Usuario».",
"LabelOpenIDGroupClaimDescription": "Nombre de la declaración OpenID que contiene una lista de grupos del usuario. Comúnmente conocidos como <code>grupos</code>. <b>Si se configura</b>, la aplicación asignará automáticamente roles en función de la pertenencia a grupos del usuario, siempre que estos grupos se denominen \"admin\", \"user\" o \"guest\" en la notificación. La solicitud debe contener una lista, y si un usuario pertenece a varios grupos, la aplicación asignará el rol correspondiente al mayor nivel de acceso. Si ningún grupo coincide, se denegará el acceso.",
"LabelOpenRSSFeed": "Abrir suministro RSS",
"LabelOverwrite": "Sobrescribir",
@@ -495,9 +499,9 @@
"LabelPodcastType": "Tipo de pódcast",
"LabelPodcasts": "Pódcast",
"LabelPort": "Puerto",
"LabelPrefixesToIgnore": "Prefijos para Ignorar (no distingue entre mayúsculas y minúsculas.)",
"LabelPrefixesToIgnore": "Prefijos para ignorar (no distingue entre mayúsculas y minúsculas)",
"LabelPreventIndexing": "Evite que los directorios de pódcast de iTunes y Google indicen su suministro",
"LabelPrimaryEbook": "Ebook principal",
"LabelPrimaryEbook": "Libro electrónico principal",
"LabelProgress": "Progreso",
"LabelProvider": "Proveedor",
"LabelProviderAuthorizationValue": "Valor del encabezado de autorización",
@@ -511,7 +515,7 @@
"LabelRSSFeedCustomOwnerEmail": "Correo electrónico de dueño personalizado",
"LabelRSSFeedCustomOwnerName": "Nombre de dueño personalizado",
"LabelRSSFeedOpen": "Suministro RSS abierto",
"LabelRSSFeedPreventIndexing": "Prevenir indexado",
"LabelRSSFeedPreventIndexing": "Evitar indización",
"LabelRSSFeedSlug": "«Slug» de suministro RSS",
"LabelRSSFeedURL": "URL de suministro RSS",
"LabelRandomly": "Aleatorio",
@@ -527,6 +531,7 @@
"LabelReleaseDate": "Fecha de estreno",
"LabelRemoveAllMetadataAbs": "Eliminar todos los archivos metadata.abs",
"LabelRemoveAllMetadataJson": "Eliminar todos los archivos metadata.json",
"LabelRemoveAudibleBranding": "Quitar introducción y cierre de Audible de los capítulos",
"LabelRemoveCover": "Quitar cubierta",
"LabelRemoveMetadataFile": "Eliminar archivos de metadatos en carpetas de elementos de biblioteca",
"LabelRemoveMetadataFileHelp": "Elimine todos los archivos metadata.json y metadata.abs de sus carpetas {0}.",
@@ -535,7 +540,7 @@
"LabelSearchTitle": "Buscar título",
"LabelSearchTitleOrASIN": "Buscar título o ASIN",
"LabelSeason": "Temporada",
"LabelSeasonNumber": "Sesión #{0}",
"LabelSeasonNumber": "{0}.ª temporada",
"LabelSelectAll": "Seleccionar todo",
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
@@ -575,7 +580,7 @@
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Saltar libros anteriores de la serie Continuada",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "El estante de la página de inicio de Continuar Serie muestra el primer libro no iniciado de una serie que tenga por lo menos un libro finalizado y no tenga libros en progreso. Habilitar esta opción le permitirá continuar series desde el último libro que ha completado en vez del primer libro que no ha empezado.",
"LabelSettingsParseSubtitles": "Extraer Subtítulos",
"LabelSettingsParseSubtitlesHelp": "Extraer subtítulos de los nombres de las carpetas de los audiolibros.<br>Los subtítulos deben estar separados por \" - \"<br>Por ejemplo: \"Ejemplo de Título - Subtítulo Aquí\" tiene el subtítulo \"Subtítulo Aquí\"",
"LabelSettingsParseSubtitlesHelp": "Extraer subtítulos de los nombres de las carpetas de los audiolibros.<br>Los subtítulos deben estar separados por « - »<br>Así, «Título de libro - Un subtítulo aquí» tiene el subtítulo «Un subtítulo aquí»",
"LabelSettingsPreferMatchedMetadata": "Preferir metadatos encontrados",
"LabelSettingsPreferMatchedMetadataHelp": "Los datos encontrados sobreescribirán los detalles del elemento cuando se use \"Encontrar Rápido\". Por defecto, \"Encontrar Rápido\" sólo completará los detalles faltantes.",
"LabelSettingsSkipMatchingBooksWithASIN": "Omitir libros coincidentes que ya tengan un ASIN",
@@ -593,7 +598,7 @@
"LabelShareDownloadableHelp": "Permite a quienes posean el enlace de compartición descargar un archivo ZIP del elemento de la biblioteca.",
"LabelShareOpen": "abrir un recurso compartido",
"LabelShareURL": "Compartir la URL",
"LabelShowAll": "Mostrar Todos",
"LabelShowAll": "Mostrar todo",
"LabelShowSeconds": "Mostrar segundos",
"LabelShowSubtitles": "Mostrar subtítulos",
"LabelSize": "Tamaño",
@@ -601,33 +606,34 @@
"LabelSlug": "Slug",
"LabelSortAscending": "Ascendente",
"LabelSortDescending": "Descendente",
"LabelSortPubDate": "Ord. fecha pub.",
"LabelStart": "Iniciar",
"LabelStartTime": "Tiempo de Inicio",
"LabelStarted": "Iniciado",
"LabelStartedAt": "Iniciado En",
"LabelStatsAudioTracks": "Pistas de Audio",
"LabelStatsAuthors": "Autores",
"LabelStatsBestDay": "Mejor Día",
"LabelStatsDailyAverage": "Promedio Diario",
"LabelStatsBestDay": "Mejor día",
"LabelStatsDailyAverage": "Promedio diario",
"LabelStatsDays": "Días",
"LabelStatsDaysListened": "Días Escuchando",
"LabelStatsDaysListened": "Días escuchando",
"LabelStatsHours": "Horas",
"LabelStatsInARow": "seguidos",
"LabelStatsItemsFinished": "Elementos Terminados",
"LabelStatsItemsFinished": "Elementos terminados",
"LabelStatsItemsInLibrary": "Elementos en biblioteca",
"LabelStatsMinutes": "minutos",
"LabelStatsMinutesListening": "Minutos Escuchando",
"LabelStatsOverallDays": "Total de Dias",
"LabelStatsOverallHours": "Total de Horas",
"LabelStatsWeekListening": "Tiempo escuchando en la Semana",
"LabelStatsMinutesListening": "Minutos escuchando",
"LabelStatsOverallDays": "Total de as",
"LabelStatsOverallHours": "Total de horas",
"LabelStatsWeekListening": "Tiempo escuchando en la semana",
"LabelSubtitle": "Subtítulo",
"LabelSupportedFileTypes": "Tipos de archivo admitidos",
"LabelTag": "Etiqueta",
"LabelTags": "Etiquetas",
"LabelTagsAccessibleToUser": "Etiquetas Accessibles al Usuario",
"LabelTagsNotAccessibleToUser": "Etiquetas no Accesibles al Usuario",
"LabelTasks": "Tareas Corriendo",
"LabelTextEditorBulletedList": "Lista con viñetas",
"LabelTagsAccessibleToUser": "Etiquetas accessibles al usuario",
"LabelTagsNotAccessibleToUser": "Etiquetas no accesibles al usuario",
"LabelTasks": "Tareas en ejecución",
"LabelTextEditorBulletedList": "Lista con bolos",
"LabelTextEditorLink": "Enlazar",
"LabelTextEditorNumberedList": "Lista numerada",
"LabelTextEditorUnlink": "Desenlazar",
@@ -680,7 +686,7 @@
"LabelUseFullTrack": "Usar pista completa",
"LabelUseZeroForUnlimited": "Utilice 0 para ilimitado",
"LabelUser": "Usuario",
"LabelUsername": "Nombre de Usuario",
"LabelUsername": "Nombre de usuario",
"LabelValue": "Valor",
"LabelVersion": "Versión",
"LabelViewBookmarks": "Ver Marcadores",
@@ -693,89 +699,95 @@
"LabelWeekdaysToRun": "Correr en Días de la Semana",
"LabelXBooks": "{0} libros",
"LabelXItems": "{0} elementos",
"LabelYearReviewHide": "Ocultar Resumen del año",
"LabelYearReviewShow": "Resumen del año",
"LabelYearReviewHide": "Ocultar resumen del año",
"LabelYearReviewShow": "Ver resumen del año",
"LabelYourAudiobookDuration": "Duración de tu Audiolibro",
"LabelYourBookmarks": "Tus Marcadores",
"LabelYourBookmarks": "Sus marcadores",
"LabelYourPlaylists": "Tus Listas",
"LabelYourProgress": "Su progreso",
"MessageAddToPlayerQueue": "Agregar a fila del Reproductor",
"MessageAppriseDescription": "Para usar esta función deberás tener <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">la API de Apprise</a> corriendo o una API que maneje los mismos resultados. <br/>La URL de la API de Apprise debe tener la misma ruta de archivos que donde se envían las notificaciones. Por ejemplo: si su API esta en <code>http://192.168.1.1:8337</code> entonces pondría <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Cerciórese de usar el ASIN de la región correcta de Audible, no de Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Reinicie el servidor tras el guardado para aplicar los cambios de OIDC.",
"MessageBackupsDescription": "Los respaldos incluyen: usuarios, el progreso del los usuarios, los detalles de los elementos de la biblioteca, la configuración del servidor y las imágenes en <code>/metadata/items</code> y <code>/metadata/authors</code>. Los Respaldos <strong>NO</strong> incluyen ningún archivo guardado en la carpeta de tu biblioteca.",
"MessageBackupsLocationEditNote": "Nota: actualizar la ubicación de la copia de respaldo no moverá ni modificará los respaldos existentes",
"MessageBackupsLocationNoEditNote": "Nota: la ubicación de la copia de respaldo se establece a través de una variable de entorno y no se puede cambiar aquí.",
"MessageBackupsLocationPathEmpty": "La ruta de la copia de seguridad no puede estar vacía",
"MessageBatchEditPopulateMapDetailsAllHelp": "Rellenar campos activados con datos de todos los elementos. Los campos con varios valores se combinarán",
"MessageBatchEditPopulateMapDetailsItemHelp": "Rellenar campos de detalles de mapa con datos de este elemento",
"MessageBatchQuickMatchDescription": "\"Encontrar Rápido\" tratará de agregar portadas y metadatos faltantes de los elementos seleccionados. Habilite la opción de abajo para que \"Encontrar Rápido\" pueda sobrescribir portadas y/o metadatos existentes.",
"MessageBookshelfNoCollections": "Aún no ha hecho ninguna colección",
"MessageBookshelfNoCollectionsHelp": "Las colecciones son públicas. Cualquiera que pueda acceder a la biblioteca las podrá ver.",
"MessageBookshelfNoRSSFeeds": "Ningún suministro RSS está abierto",
"MessageBookshelfNoResultsForFilter": "Ningún Resultado para el filtro \"{0}: {1}\"",
"MessageBookshelfNoResultsForFilter": "El filtro «{0}: {1}» no produjo ningún resultado",
"MessageBookshelfNoResultsForQuery": "No hay resultados para la consulta",
"MessageBookshelfNoSeries": "No tiene ninguna serie",
"MessageChapterEndIsAfter": "El final del capítulo es después del final de tu audiolibro",
"MessageChapterErrorFirstNotZero": "El primer capitulo debe iniciar en 0",
"MessageChapterErrorFirstNotZero": "El primer capítulo debe iniciar en 0",
"MessageChapterErrorStartGteDuration": "El tiempo de inicio no es válido: debe ser inferior a la duración del audiolibro",
"MessageChapterErrorStartLtPrev": "El tiempo de inicio no es válido: debe ser mayor o igual que el tiempo de inicio del capítulo anterior",
"MessageChapterStartIsAfter": "El comienzo del capítulo es después del final de su audiolibro",
"MessageChaptersNotFound": "Capítulos no encontrados",
"MessageCheckingCron": "Revisando cron...",
"MessageConfirmCloseFeed": "¿Confirma que quiere cerrar este suministro?",
"MessageConfirmDeleteBackup": "¿Está seguro de que desea eliminar el respaldo {0}?",
"MessageConfirmDeleteDevice": "¿Estás seguro de que deseas eliminar el lector electrónico \"{0}\"?",
"MessageConfirmDeleteFile": "Esto eliminará el archivo de su sistema de archivos. ¿Está seguro?",
"MessageConfirmDeleteLibrary": "¿Está seguro de que desea eliminar permanentemente la biblioteca \"{0}\"?",
"MessageConfirmDeleteBackup": "¿Confirma que quiere eliminar el respaldo de {0}?",
"MessageConfirmDeleteDevice": "¿Confirma que quiere eliminar el lector electrónico «{0}»?",
"MessageConfirmDeleteFile": "Esto eliminará el archivo del sistema de archivos. ¿Quiere continuar?",
"MessageConfirmDeleteLibrary": "¿Confirma que quiere eliminar permanentemente la biblioteca «{0}»?",
"MessageConfirmDeleteLibraryItem": "Esto eliminará el elemento de la biblioteca de la base de datos y del sistema de archivos. ¿Confirma que quiere hacerlo?",
"MessageConfirmDeleteLibraryItems": "Esto eliminará {0} elementos de la biblioteca de la base de datos y del sistema de archivos. ¿Confirma que quiere hacerlo?",
"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?",
"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?",
"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?",
"MessageConfirmMarkItemFinished": "¿Estás seguro de que deseas marcar \"{0}\" como terminado?",
"MessageConfirmMarkItemNotFinished": "¿Estás seguro de que deseas marcar \"{0}\" como no acabado?",
"MessageConfirmMarkSeriesFinished": "¿Está seguro de que desea marcar todos los libros en esta serie como terminados?",
"MessageConfirmMarkSeriesNotFinished": "¿Está seguro de que desea marcar todos los libros en esta serie como no terminados?",
"MessageConfirmDeleteMetadataProvider": "¿Confirma que quiere eliminar el proveedor de metadatos personalizado «{0}»?",
"MessageConfirmDeleteNotification": "¿Confirma que quiere eliminar esta notificación?",
"MessageConfirmDeleteSession": "¿Confirma que quiere eliminar esta sesión?",
"MessageConfirmEmbedMetadataInAudioFiles": "¿Confirma que quiere incrustar metadatos en {0} archivos de audio?",
"MessageConfirmForceReScan": "¿Confirma que quiere forzar un reescaneo?",
"MessageConfirmMarkAllEpisodesFinished": "¿Confirma que quiere marcar todos los episodios como terminados?",
"MessageConfirmMarkAllEpisodesNotFinished": "¿Confirma que quiere marcar todos los episodios como no terminados?",
"MessageConfirmMarkItemFinished": "¿Confirma que quiere marcar «{0}» como terminado?",
"MessageConfirmMarkItemNotFinished": "¿Confirma que quiere marcar «{0}» como no terminado?",
"MessageConfirmMarkSeriesFinished": "¿Confirma que quiere marcar todos los libros de esta serie como terminados?",
"MessageConfirmMarkSeriesNotFinished": "¿Confirma que quiere marcar todos los libros de esta serie como no terminados?",
"MessageConfirmNotificationTestTrigger": "¿Activar esta notificación con datos de prueba?",
"MessageConfirmPurgeCache": "Purgar el caché eliminará el directorio completo ubicado en <code>/metadata/cache</code>. <br /><br />¿Está seguro que desea eliminar el directorio del caché?",
"MessageConfirmPurgeItemsCache": "Purgar la caché de los elementos eliminará todo el directorio <code>/metadata/cache/items</code>.<br />¿Estás seguro?",
"MessageConfirmQuickEmbed": "¡Advertencia! La integración rápida no realiza copias de seguridad a ninguno de tus archivos de audio. Asegúrate de haber realizado una copia de los mismos previamente. <br><br>¿Deseas continuar?",
"MessageConfirmQuickMatchEpisodes": "El reconocimiento rápido de extensiones sobrescribirá los detalles si se encuentra una coincidencia. Se actualizarán las extensiones no reconocidas. ¿Está seguro?",
"MessageConfirmReScanLibraryItems": "¿Estás seguro de querer re escanear {0} elemento(s)?",
"MessageConfirmRemoveAllChapters": "¿Está seguro de que desea remover todos los capitulos?",
"MessageConfirmRemoveAuthor": "¿Está seguro de que desea remover el autor \"{0}\"?",
"MessageConfirmRemoveCollection": "¿Está seguro de que desea remover la colección \"{0}\"?",
"MessageConfirmRemoveEpisode": "¿Está seguro de que desea remover el episodio \"{0}\"?",
"MessageConfirmRemoveEpisodes": "¿Está seguro de que desea remover {0} episodios?",
"MessageConfirmRemoveListeningSessions": "¿Está seguro que desea remover {0} sesiones de escuchar?",
"MessageConfirmRemoveMetadataFiles": "¿Está seguro de que desea eliminar todos los archivos de metadatos.{0} en las carpetas de elementos de su biblioteca?",
"MessageConfirmRemoveNarrator": "¿Está seguro de que desea remover el narrador \"{0}\"?",
"MessageConfirmRemovePlaylist": "¿Está seguro de que desea remover la lista de reproducción \"{0}\"?",
"MessageConfirmRenameGenre": "¿Está seguro de que desea renombrar el genero \"{0}\" a \"{1}\" de todos los elementos?",
"MessageConfirmPurgeCache": "Purgar la antememoria eliminará el directorio completo ubicado en <code>/metadata/cache</code>. <br /><br />¿Confirma que quiere eliminar el directorio de antememoria?",
"MessageConfirmPurgeItemsCache": "Purgar la antememoria de elementos eliminará el directorio completo ubicado en <code>/metadata/cache/items</code>.<br />¿Lo confirma?",
"MessageConfirmQuickEmbed": "Atención: la incrustación rápida no realiza copias de respaldo a ninguno de sus archivos de audio. Cerciórese de haber realizado una copia de los mismos previamente. <br><br>¿Quiere continuar?",
"MessageConfirmQuickMatchEpisodes": "El reconocimiento rápido de extensiones sobrescribirá los detalles si se encuentra una coincidencia. Se actualizarán las extensiones no reconocidas. ¿Quiere continuar?",
"MessageConfirmReScanLibraryItems": "¿Confirma que quiere volver a analizar {0} elementos?",
"MessageConfirmRemoveAllChapters": "¿Confirma que quiere quitar todos los capítulos?",
"MessageConfirmRemoveAuthor": "¿Confirma que quiere quitar el autor «{0}»?",
"MessageConfirmRemoveCollection": "¿Confirma que quiere quitar la colección «{0}»?",
"MessageConfirmRemoveEpisode": "¿Confirma que quiere quitar el episodio «{0}»?",
"MessageConfirmRemoveEpisodes": "¿Confirma que quiere quitar {0} episodios?",
"MessageConfirmRemoveListeningSessions": "¿Confirma que quiere quitar {0} sesiones de escucha?",
"MessageConfirmRemoveMetadataFiles": "¿Confirma que quiere quitar todos los archivos metadata.{0} en las carpetas de elementos de su biblioteca?",
"MessageConfirmRemoveNarrator": "¿Confirma que quiere quitar el narrador «{0}»?",
"MessageConfirmRemovePlaylist": "¿Confirma que quiere quitar la lista de reproducción «{0}»?",
"MessageConfirmRenameGenre": "¿Confirma que quiere cambiar el nombre del género «{0}» a «{1}» en todos los elementos?",
"MessageConfirmRenameGenreMergeNote": "Nota: Este género ya existe, por lo que se fusionarán.",
"MessageConfirmRenameGenreWarning": "Advertencia! Un genero similar ya existe \"{0}\".",
"MessageConfirmRenameTag": "¿Está seguro de que desea renombrar la etiqueta \"{0}\" a \"{1}\" de todos los elementos?",
"MessageConfirmRenameTagMergeNote": "Nota: Esta etiqueta ya existe, por lo que se fusionarán.",
"MessageConfirmRenameTagWarning": "Advertencia! Una etiqueta similar ya existe \"{0}\".",
"MessageConfirmResetProgress": "¿Estás seguro de que quieres reiniciar tu progreso?",
"MessageConfirmSendEbookToDevice": "¿Está seguro de que enviar {0} ebook(s) \"{1}\" al dispositivo \"{2}\"?",
"MessageConfirmUnlinkOpenId": "¿Estás seguro de que deseas desvincular este usuario de OpenID?",
"MessageDaysListenedInTheLastYear": "{0} dies escoltats en l'últim any",
"MessageDownloadingEpisode": "Descargando Capitulo",
"MessageDragFilesIntoTrackOrder": "Arrastra los archivos al orden correcto de las pistas",
"MessageEmbedFailed": "¡Error al insertar!",
"MessageEmbedFinished": "Incrustación Terminada!",
"MessageConfirmRenameGenreWarning": "¡Atención! Ya existe un género similar con distinta mayusculación, «{0}».",
"MessageConfirmRenameTag": "¿Confirma que quiere cambiar el nombre de la etiqueta «{0}» a «{1}» en todos los elementos?",
"MessageConfirmRenameTagMergeNote": "Nota: esta etiqueta ya existe, por lo que se fusionarán.",
"MessageConfirmRenameTagWarning": "¡Atención! Ya existe una etiqueta similar con distinta mayusculación, «{0}».",
"MessageConfirmResetProgress": "¿Confirma que quiere restablecer su progreso?",
"MessageConfirmSendEbookToDevice": "¿Confirma que quiere enviar el libro electrónico {0} «{1}» al dispositivo «{2}»?",
"MessageConfirmUnlinkOpenId": "¿Confirma que quiere desenlazar este usuario de OpenID?",
"MessageDaysListenedInTheLastYear": "{0} días escuchados el año pasado",
"MessageDownloadingEpisode": "Descargando episodio",
"MessageDragFilesIntoTrackOrder": "Arrastre los archivos al orden correcto de las pistas",
"MessageEmbedFailed": "Falló la incrustación.",
"MessageEmbedFinished": "Finalizó la incrustación.",
"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.",
"MessageFeedURLWillBe": "El URL del suministro será {0}",
"MessageFetching": "Buscando...",
"MessageFetching": "Recuperando...",
"MessageForceReScanDescription": "Escaneará todos los archivos como un nuevo escaneo. Archivos de audio con etiquetas ID3, archivos OPF y archivos de texto serán escaneados como nuevos.",
"MessageImportantNotice": "¡Notificación importante!",
"MessageInsertChapterBelow": "Insertar Capítulo Abajo",
"MessageInsertChapterBelow": "Insertar capítulo debajo",
"MessageInvalidAsin": "ASIN no válido",
"MessageItemsSelected": "{0} elementos seleccionados",
"MessageItemsUpdated": "{0} elementos actualizados",
"MessageJoinUsOn": "Únetenos en",
"MessageJoinUsOn": "Únase a nosotros en",
"MessageLoading": "Cargando...",
"MessageLoadingFolders": "Cargando archivos...",
"MessageLogsDescription": "Logs son almacenados en <code>/metadata/logs</code> en archivos bajo formato JSON. Logs de fallos son almacenados en <code>/metadata/logs/crash_logs.txt</code>.",
@@ -799,19 +811,19 @@
"MessageNoDownloadsInProgress": "No hay descargas actualmente en curso",
"MessageNoDownloadsQueued": "Sin Lista de Descarga",
"MessageNoEpisodeMatchesFound": "No se encontraron episodios que coinciden",
"MessageNoEpisodes": "Sin Episodios",
"MessageNoFoldersAvailable": "No Hay Carpetas Disponibles",
"MessageNoGenres": "Sin Géneros",
"MessageNoIssues": "Sin Problemas",
"MessageNoItems": "Sin elementos",
"MessageNoEpisodes": "Ningún episodio",
"MessageNoFoldersAvailable": "Ninguna carpeta disponible",
"MessageNoGenres": "Ningún género",
"MessageNoIssues": "Ningún número",
"MessageNoItems": "Ningún elemento",
"MessageNoItemsFound": "Ningún elemento encontrado",
"MessageNoListeningSessions": "Ninguna sesión escuchada",
"MessageNoListeningSessions": "Ninguna sesión de escucha",
"MessageNoLogs": "Ningún registro",
"MessageNoMediaProgress": "Multimedia sin Progreso",
"MessageNoNotifications": "Ninguna notificación",
"MessageNoPodcastFeed": "Podcast no válido: Sin feed",
"MessageNoPodcastsFound": "Ningún podcast encontrado",
"MessageNoResults": "Sin Resultados",
"MessageNoPodcastFeed": "Pódcast no válido: no hay suministro",
"MessageNoPodcastsFound": "No se encontró ningún pódcast",
"MessageNoResults": "Ningún resultado",
"MessageNoSearchResultsFor": "La búsqueda «{0}» no produjo ningún resultado",
"MessageNoSeries": "Ninguna serie",
"MessageNoTags": "Ninguna etiqueta",
@@ -819,60 +831,62 @@
"MessageNoUpdatesWereNecessary": "No fue necesario actualizar",
"MessageNoUserPlaylists": "No tiene ninguna lista de reproducción",
"MessageNoUserPlaylistsHelp": "Las listas de reproducción son privadas. Solo quien las cree podrá verlas.",
"MessageNotYetImplemented": "Aun no implementado",
"MessageNotYetImplemented": "Aún no implementado",
"MessageOpmlPreviewNote": "Nota: Esta es una vista previa del archivo OPML analizado. El título real del podcast se obtendrá del canal RSS.",
"MessageOr": "o",
"MessagePauseChapter": "Pausar la reproducción del capítulo",
"MessagePlayChapter": "Escuchar el comienzo del capítulo",
"MessagePlaylistCreateFromCollection": "Crear una lista de reproducción a partir de una colección",
"MessagePleaseWait": "Por favor, espera...",
"MessagePleaseWait": "Espere…",
"MessagePodcastHasNoRSSFeedForMatching": "El pódcast no tiene un URL de suministro RSS que pueda usarse para encontrar correspondencias",
"MessagePodcastSearchField": "Introduzca el término de búsqueda o el URL del suministro RSS",
"MessageQuickEmbedInProgress": "Integración rápida en proceso",
"MessageQuickEmbedQueue": "En cola para inserción rápida ({0} en cola)",
"MessageQuickMatchAllEpisodes": "Combina rápidamente todos los episodios",
"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",
"MessageRemoveEpisodes": "Remover {0} episodio(s)",
"MessageRemoveFromPlayerQueue": "Remover la cola de reproducción",
"MessageRemoveUserWarning": "¿Está seguro de que desea eliminar el usuario \"{0}\"?",
"MessageReportBugsAndContribute": "Reporte erres, solicite funciones y contribuya en",
"MessageResetChaptersConfirm": "¿Está seguro de que desea deshacer los cambios y revertir los capítulos a su estado original?",
"MessageRestoreBackupConfirm": "¿Está seguro de que desea para restaurar del respaldo creado en",
"MessageQuickMatchDescription": "Rellena los detalles y la cubierta de los elementos vacíos con el primer resultado coincidente de «{0}». No sobrescribe los detalles a menos que se active la opción del servidor «Preferir metadatos coincidentes».",
"MessageRemoveChapter": "Quitar capítulo",
"MessageRemoveEpisodes": "Quitar {0} episodio(s)",
"MessageRemoveFromPlayerQueue": "Quitar de la cola de reproducción",
"MessageRemoveUserWarning": "¿Confirma que quiere eliminar permanentemente el usuario «{0}»?",
"MessageReportBugsAndContribute": "Informe de defectos, solicite funciones y contribuya en",
"MessageResetChaptersConfirm": "¿Confirma que quiere deshacer los cambios y restablecer los capítulos a su estado original?",
"MessageRestoreBackupConfirm": "¿Confirma que quiere restaurar el respaldo creado el",
"MessageRestoreBackupWarning": "Restaurar sobrescribirá toda la base de datos localizada en /config y las imágenes de portadas en /metadata/items y /metadata/authors.<br /><br />El respaldo no modifica ningún archivo en las carpetas de su biblioteca. Si ha habilitado la opción del servidor para almacenar portadas y metadata en las carpetas de su biblioteca, esos archivos no se respaldan o sobrescriben.<br /><br />Todos los clientes que usen su servidor se actualizarán automáticamente.",
"MessageScheduleLibraryScanNote": "Para la mayoría de los usuarios, se recomienda dejar esta función desactivada y mantener activada la configuración del observador de carpetas. El observador de carpetas detectará automáticamente los cambios en las carpetas de la biblioteca. El observador de carpetas no funciona para todos los sistemas de archivos (como NFS), por lo que se pueden utilizar exploraciones programadas de la biblioteca en su lugar.",
"MessageScheduleRunEveryWeekdayAtTime": "Ejecutar cada {0} a las {1}",
"MessageSearchResultsFor": "Resultados de la búsqueda de",
"MessageSelected": "{0} seleccionado(s)",
"MessageSeriesSequenceCannotContainSpaces": "La secuencia de la serie no puede contener espacios",
"MessageServerCouldNotBeReached": "No se pudo establecer la conexión con el servidor",
"MessageSetChaptersFromTracksDescription": "Establecer capítulos usando cada archivo de audio como un capítulo y el título del capítulo como el nombre del archivo de audio",
"MessageShareExpirationWillBe": "La caducidad será <strong>{0}</strong>",
"MessageShareExpiresIn": "Caduduca en {0}",
"MessageShareURLWillBe": "La URL para compartir será <strong> {0} </strong>",
"MessageStartPlaybackAtTime": "Iniciar reproducción para \"{0}\" en {1}?",
"MessageTaskAudioFileNotWritable": "El archivo de audio \"{0}\" no se puede grabar",
"MessageStartPlaybackAtTime": "¿Iniciar reproducción para «{0}» en {1}?",
"MessageTaskAudioFileNotWritable": "El archivo de audio «{0}» no se puede grabar",
"MessageTaskCanceledByUser": "Tarea cancelada por el usuario",
"MessageTaskDownloadingEpisodeDescription": "Descargando el episodio \"{0}\"",
"MessageTaskDownloadingEpisodeDescription": "Descargando el episodio «{0}»",
"MessageTaskEmbeddingMetadata": "Inserción de metadatos",
"MessageTaskEmbeddingMetadataDescription": "Inserción de metadatos en el audiolibro \"{0}\"",
"MessageTaskEmbeddingMetadataDescription": "Incrustando metadatos en el audiolibro «{0}»",
"MessageTaskEncodingM4b": "Codificación M4B",
"MessageTaskEncodingM4bDescription": "Codificación del audiolibro \"{0}\" en un único archivo m4b",
"MessageTaskEncodingM4bDescription": "Codificando el audiolibro «{0}» en un único archivo m4b",
"MessageTaskFailed": "Fallida",
"MessageTaskFailedToBackupAudioFile": "Error en la copia de seguridad del archivo de audio \"{0}\"",
"MessageTaskFailedToBackupAudioFile": "No se pudo respaldar el archivo de audio «{0}»",
"MessageTaskFailedToCreateCacheDirectory": "Error al crear el directorio de la caché",
"MessageTaskFailedToEmbedMetadataInFile": "Error al incrustar metadatos en el archivo \"{0}\"",
"MessageTaskFailedToEmbedMetadataInFile": "No se pudieron incrustar metadatos en el archivo «{0}»",
"MessageTaskFailedToMergeAudioFiles": "Error al fusionar archivos de audio",
"MessageTaskFailedToMoveM4bFile": "Error al mover el archivo m4b",
"MessageTaskFailedToWriteMetadataFile": "Error al escribir el archivo de metadatos",
"MessageTaskMatchingBooksInLibrary": "Libros coincidentes en la biblioteca \"{0}\"",
"MessageTaskMatchingBooksInLibrary": "Libros coincidentes en la biblioteca «{0}»",
"MessageTaskNoFilesToScan": "Sin archivos para escanear",
"MessageTaskOpmlImport": "Importar OPML",
"MessageTaskOpmlImportDescription": "Creando pódcast a partir de {0} suministros RSS",
"MessageTaskOpmlImportFeed": "Feed de importación OPML",
"MessageTaskOpmlImportFeedDescription": "Importando el feed RSS \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "No se puede obtener el podcast",
"MessageTaskOpmlImportFeedPodcastDescription": "Creando podcast \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast ya existe en la ruta",
"MessageTaskOpmlImportFeedPodcastFailed": "Error al crear podcast",
"MessageTaskOpmlImportFeedDescription": "Importando el suministro RSS «{0}»",
"MessageTaskOpmlImportFeedFailed": "No se pudo obtener el suministro del pódcast",
"MessageTaskOpmlImportFeedPodcastDescription": "Creando pódcast «{0}»",
"MessageTaskOpmlImportFeedPodcastExists": "El pódcast ya existe en la ruta",
"MessageTaskOpmlImportFeedPodcastFailed": "No se pudo crear el pódcast",
"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>",
@@ -881,8 +895,8 @@
"MessageTaskScanItemsMissing": "Falta {0}",
"MessageTaskScanItemsUpdated": "{0} actualizado",
"MessageTaskScanNoChangesNeeded": "No se necesitan cambios",
"MessageTaskScanningFileChanges": "Escaneando cambios en el archivo en \"{0}\"",
"MessageTaskScanningLibrary": "Escaneando la biblioteca \"{0}\"",
"MessageTaskScanningFileChanges": "Escaneando cambios en archivos en «{0}»",
"MessageTaskScanningLibrary": "Escaneando la biblioteca «{0}»",
"MessageTaskTargetDirectoryNotWritable": "El directorio de destino no se puede escribir",
"MessageThinking": "Pensando...",
"MessageUploaderItemFailed": "Error al Subir",
@@ -932,7 +946,7 @@
"ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise",
"ToastAsinRequired": "Se requiere ASIN",
"ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor",
"ToastAuthorNotFound": "No se encontró el autor \"{0}\"",
"ToastAuthorNotFound": "No se encontró el autor «{0}»",
"ToastAuthorRemoveSuccess": "Autor eliminado",
"ToastAuthorSearchNotFound": "No se encontró al autor",
"ToastAuthorUpdateMerged": "Autor combinado",
@@ -943,32 +957,35 @@
"ToastBackupCreateSuccess": "Respaldo creado",
"ToastBackupDeleteFailed": "Error al eliminar respaldo",
"ToastBackupDeleteSuccess": "Respaldo eliminado",
"ToastBackupInvalidMaxKeep": "Número no válido de copias de seguridad a conservar",
"ToastBackupInvalidMaxSize": "Tamaño máximo de copia de seguridad no válido",
"ToastBackupInvalidMaxKeep": "Número no válido de copias de respaldo para conservar",
"ToastBackupInvalidMaxSize": "Tamaño máximo de copia de respaldo no válido",
"ToastBackupRestoreFailed": "Error al restaurar el respaldo",
"ToastBackupUploadFailed": "Error al subir el respaldo",
"ToastBackupUploadFailed": "Error al cargar la copia de respaldo",
"ToastBackupUploadSuccess": "Respaldo cargado",
"ToastBatchDeleteFailed": "Error al eliminar por lotes",
"ToastBatchDeleteSuccess": "Borrado por lotes correcto",
"ToastBatchApplyDetailsToItemsSuccess": "Detalles aplicados a los elementos",
"ToastBatchDeleteFailed": "Falló la eliminación por lotes",
"ToastBatchDeleteSuccess": "Se eliminó por lotes correctamente",
"ToastBatchQuickMatchFailed": "¡Error en la sincronización rápida por lotes!",
"ToastBatchQuickMatchStarted": "¡Se inició el lote de búsqueda rápida de {0} libros!",
"ToastBatchUpdateFailed": "Subida masiva fallida",
"ToastBatchUpdateSuccess": "Subida masiva exitosa",
"ToastBookmarkCreateFailed": "Error al crear marcador",
"ToastBookmarkCreateSuccess": "Marcador Agregado",
"ToastBatchUpdateFailed": "Falló la actualización por lotes",
"ToastBatchUpdateSuccess": "Se actualizó por lotes correctamente",
"ToastBookmarkCreateFailed": "No se pudo crear el marcador",
"ToastBookmarkCreateSuccess": "Marcador añadido",
"ToastBookmarkRemoveSuccess": "Marcador eliminado",
"ToastCachePurgeFailed": "Error al purgar el caché",
"ToastCachePurgeSuccess": "Caché purgado de manera exitosa",
"ToastCachePurgeFailed": "No se pudo purgar la antememoria",
"ToastCachePurgeSuccess": "Se purgó la antememoria correctamente",
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
"ToastChaptersMustHaveTitles": "Los capítulos tienen que tener un título",
"ToastChaptersInvalidShiftAmountLast": "Cantidad de desplazamiento no válida. La hora de inicio del último capítulo se extendería más allá de la duración de este audiolibro.",
"ToastChaptersInvalidShiftAmountStart": "Cantidad de desplazamiento no válida. El primer capítulo tendría una duración cero o negativa y lo sobrescribiría el segundo capítulo. Aumente la duración inicial del segundo capítulo.",
"ToastChaptersMustHaveTitles": "Los capítulos deben tener título",
"ToastChaptersRemoved": "Capítulos eliminados",
"ToastChaptersUpdated": "Capítulos actualizados",
"ToastCollectionItemsAddFailed": "Artículo(s) añadido(s) a la colección fallido(s)",
"ToastCollectionRemoveSuccess": "Colección removida",
"ToastCollectionRemoveSuccess": "Colección quitada",
"ToastCollectionUpdateSuccess": "Colección actualizada",
"ToastCoverUpdateFailed": "Error al actualizar la cubierta",
"ToastDateTimeInvalidOrIncomplete": "Fecha y hora inválidas o incompletas",
"ToastDeleteFileFailed": "Error el eliminar archivo",
"ToastDateTimeInvalidOrIncomplete": "Fecha y hora no válidas o incompletas",
"ToastDeleteFileFailed": "Falló la eliminación del archivo",
"ToastDeleteFileSuccess": "Archivo eliminado",
"ToastDeviceAddFailed": "Error al añadir dispositivo",
"ToastDeviceNameAlreadyExists": "Un libro electrónico ya existe con ese nombre",
@@ -998,12 +1015,12 @@
"ToastItemMarkedAsNotFinishedSuccess": "Elemento marcado como No Terminado",
"ToastItemUpdateSuccess": "Elemento actualizado",
"ToastLibraryCreateFailed": "Error al crear biblioteca",
"ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada",
"ToastLibraryCreateSuccess": "Se creó la biblioteca «{0}»",
"ToastLibraryDeleteFailed": "Error al eliminar biblioteca",
"ToastLibraryDeleteSuccess": "Biblioteca eliminada",
"ToastLibraryScanFailedToStart": "Error al iniciar el escaneo",
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
"ToastLibraryUpdateSuccess": "Se actualizó la biblioteca «{0}»",
"ToastMatchAllAuthorsFailed": "No se pudo encontrar a todos los autores",
"ToastMetadataFilesRemovedError": "Error al eliminar metadatos de {0} archivo(s)",
"ToastMetadataFilesRemovedNoneFound": "No hay metadatos.{0} archivo(s) encontrado(s) en la biblioteca",
@@ -1013,7 +1030,7 @@
"ToastNameEmailRequired": "Son obligatorios el nombre y el correo electrónico",
"ToastNameRequired": "Nombre obligatorio",
"ToastNewEpisodesFound": "{0} nuevo(s) episodio(s) encontrado(s)",
"ToastNewUserCreatedFailed": "Error al crear la cuenta: \"{0}\"",
"ToastNewUserCreatedFailed": "No se pudo crear la cuenta: «{0}»",
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
"ToastNewUserLibraryError": "Debes seleccionar al menos una biblioteca",
"ToastNewUserPasswordError": "Debes tener una contraseña, solo el usuario root puede estar sin contraseña",
@@ -1034,11 +1051,11 @@
"ToastPlaylistCreateSuccess": "Lista de reproducción creada",
"ToastPlaylistRemoveSuccess": "Lista de reproducción eliminada",
"ToastPlaylistUpdateSuccess": "Lista de reproducción actualizada",
"ToastPodcastCreateFailed": "Error al crear podcast",
"ToastPodcastCreateSuccess": "Podcast creado",
"ToastPodcastCreateFailed": "No se pudo crear el pódcast",
"ToastPodcastCreateSuccess": "Se creó el pódcast correctamente",
"ToastPodcastGetFeedFailed": "No se puede obtener el podcast",
"ToastPodcastNoEpisodesInFeed": "No se han encontrado episodios en el feed del RSS",
"ToastPodcastNoRssFeed": "El podcast no tiene feed RSS",
"ToastPodcastNoRssFeed": "El pódcast no tiene suministro RSS",
"ToastProgressIsNotBeingSynced": "El progreso no se sincroniza, reinicia la reproducción",
"ToastProviderCreatedFailed": "Error al añadir el proveedor",
"ToastProviderCreatedSuccess": "Nuevo proveedor añadido",
@@ -1057,9 +1074,9 @@
"ToastRescanUpToDate": "Reescaneado del artículo completo, estaba actualizado",
"ToastRescanUpdated": "Reescaneado completado, el artículo ha sido actualizado",
"ToastScanFailed": "No se pudo escanear el elemento de la biblioteca",
"ToastSelectAtLeastOneUser": "Selecciona al menos un usuario",
"ToastSendEbookToDeviceFailed": "Error al enviar el ebook al dispositivo",
"ToastSendEbookToDeviceSuccess": "Ebook enviado al dispositivo \"{0}\"",
"ToastSelectAtLeastOneUser": "Seleccione al menos un usuario",
"ToastSendEbookToDeviceFailed": "No se pudo enviar el libro electrónico al dispositivo",
"ToastSendEbookToDeviceSuccess": "Libro electrónico enviado al dispositivo «{0}»",
"ToastSeriesSubmitFailedSameName": "No se puede añadir dos series con el mismo nombre",
"ToastSeriesUpdateFailed": "Error al actualizar la serie",
"ToastSeriesUpdateSuccess": "Serie actualizada",
@@ -1079,10 +1096,12 @@
"ToastUnknownError": "Error desconocido",
"ToastUnlinkOpenIdFailed": "Error al desvincular el usuario de OpenID",
"ToastUnlinkOpenIdSuccess": "Usuario desvinculado de OpenID",
"ToastUploaderFilepathExistsError": "La ruta de archivo «{0}» ya existe en el servidor",
"ToastUploaderItemExistsInSubdirectoryError": "El elemento «{0}» usa un subdirectorio de la ruta de carga.",
"ToastUserDeleteFailed": "Error al eliminar el usuario",
"ToastUserDeleteSuccess": "Usuario eliminado",
"ToastUserPasswordChangeSuccess": "Contraseña modificada correctamente",
"ToastUserPasswordMismatch": "No coinciden las contraseñas",
"ToastUserPasswordMustChange": "La nueva contraseña no puede ser igual que la anterior",
"ToastUserRootRequireName": "Debes introducir un nombre de usuario root"
"ToastUserRootRequireName": "Debe introducir un nombre de usuario administrativo"
}

View File

@@ -69,7 +69,7 @@
"ButtonQueueAddItem": "Lisää jonoon",
"ButtonQueueRemoveItem": "Poista jonosta",
"ButtonQuickEmbed": "Pikaupota",
"ButtonQuickEmbedMetadata": "Upota kuvailutiedot nopeasti",
"ButtonQuickEmbedMetadata": "Upota metatiedot pikaisesti",
"ButtonQuickMatch": "Pikatäsmäys",
"ButtonReScan": "Uudelleenskannaa",
"ButtonRead": "Lue",
@@ -229,6 +229,7 @@
"LabelAddedDate": "Lisätty {0}",
"LabelAdminUsersOnly": "Vain järjestelmänvalvojat",
"LabelAll": "Kaikki",
"LabelAllEpisodesDownloaded": "Kaikki jaksot ladattu",
"LabelAllUsers": "Kaikki käyttäjät",
"LabelAllUsersExcludingGuests": "Kaikki käyttäjät vieraita lukuun ottamatta",
"LabelAllUsersIncludingGuests": "Kaikki käyttäjät mukaan lukien vieraat",
@@ -252,7 +253,7 @@
"LabelBackToUser": "Takaisin käyttäjään",
"LabelBackupAudioFiles": "Varmuuskopioi äänitiedostot",
"LabelBackupLocation": "Varmuuskopiointipaikka",
"LabelBackupsEnableAutomaticBackups": "Ota automaattinen varmuuskopiointi käyttöön",
"LabelBackupsEnableAutomaticBackups": "Automaattiset varmuuskopiot",
"LabelBackupsEnableAutomaticBackupsHelp": "Varmuuskopiot tallennettu kansioon /metadata/backups",
"LabelBackupsMaxBackupSize": "Varmuuskopion enimmäiskoko (Gt) (0 rajaton)",
"LabelBackupsMaxBackupSizeHelp": "Virheellisten asetusten estämiseksi varmuuskopiot epäonnistuvat, jos ne ovat asetettua kokoa suurempia.",
@@ -344,6 +345,9 @@
"LabelExample": "Esimerkki",
"LabelExpandSeries": "Laajenna sarja",
"LabelExpandSubSeries": "Laajenna alisarja",
"LabelExplicit": "Yksiselitteinen",
"LabelExplicitChecked": "Yksiselitteinen (valittu)",
"LabelExplicitUnchecked": "Ei yksiselitteinen (ei valittu)",
"LabelExportOPML": "Vie OPML",
"LabelFeedURL": "Syötteen URL",
"LabelFetchingMetadata": "Noudetaan kuvailutietoja",
@@ -371,8 +375,8 @@
"LabelHardDeleteFile": "Kova tiedostojen poisto",
"LabelHasEbook": "Sillä on s-kirja",
"LabelHasSupplementaryEbook": "Sillä on täydentävän s-kirjan",
"LabelHideSubtitles": "Piilota tekstitykset",
"LabelHighestPriority": "rkein",
"LabelHideSubtitles": "Piilota alaotsikot",
"LabelHighestPriority": "Korkein etusija",
"LabelHost": "Isäntä",
"LabelHour": "Tunti",
"LabelHours": "Tunnit",
@@ -393,6 +397,8 @@
"LabelIntervalEveryMinute": "Joka minuutti",
"LabelInvert": "Saa käänteiseksi",
"LabelItem": "Kohde",
"LabelJumpBackwardAmount": "Taaksepäin-hyppyjen määrä",
"LabelJumpForwardAmount": "Eteenpäin-hyppyjen määrä",
"LabelLanguage": "Kieli",
"LabelLanguageDefaultServer": "Palvelimen oletuskieli",
"LabelLanguages": "Kielet",
@@ -484,6 +490,7 @@
"LabelPersonalYearReview": "Vuotesi katsauksessa ({0})",
"LabelPhotoPathURL": "Valokuvan polku/URL-osoite",
"LabelPlayMethod": "Toistotapa",
"LabelPlaybackRateIncrementDecrement": "Toistonopeuden lisäys-/vähennysmäärä",
"LabelPlayerChapterNumberMarker": "{0}/{1}",
"LabelPlaylists": "Soittolistat",
"LabelPodcast": "Podcast",
@@ -523,9 +530,10 @@
"LabelReleaseDate": "Julkaisupäivä",
"LabelRemoveAllMetadataAbs": "Poista kaikki metadata.abs-tiedostot",
"LabelRemoveAllMetadataJson": "Poista kaikki metadata.json-tiedostot",
"LabelRemoveAudibleBranding": "Poista Audiblen intro ja outro kappaleista",
"LabelRemoveCover": "Poista kansikuva",
"LabelRemoveMetadataFile": "Poista metatietotiedostot kirjaston kohdekansioista",
"LabelRemoveMetadataFileHelp": "Poista kaikki metadata.json- ja metadata.abs-tiedostot {0} kansiostasi.",
"LabelRemoveMetadataFileHelp": "Poista kaikki metadata.json- ja metadata.abs-tiedostot {0} kansioistasi.",
"LabelRowsPerPage": "Rivejä sivulla",
"LabelSearchTerm": "Hakusana",
"LabelSearchTitle": "Etsi otsikko",
@@ -552,6 +560,8 @@
"LabelSettingsBookshelfViewHelp": "Skeuomorfinen muotoilu puisilla hyllyillä",
"LabelSettingsChromecastSupport": "Chromecast-tuki",
"LabelSettingsDateFormat": "Päivämäärän muoto",
"LabelSettingsEnableWatcher": "Skannaa kirjastot automaattisesti muutoksien varalta",
"LabelSettingsEnableWatcherForLibrary": "Skannaa kirjastot automaattisesti muutoksien varalta",
"LabelSettingsEnableWatcherHelp": "Ottaa käyttöön kohteiden automaattisen lisäämisen ja päivityksen kun tiedostomuutoksia havaitaan. *Tarvitsee palvelimen uudelleenkäynnistyksen",
"LabelSettingsEpubsAllowScriptedContent": "Salli komentosarjamuotoinen sisältö epubissa",
"LabelSettingsEpubsAllowScriptedContentHelp": "Salli epub-tiedostojen suorittaa komentosarjoja. On suositeltavaa pitää tämä asetus pois käytöstä, ellet luota epub-tiedostojen lähteeseen.",
@@ -568,8 +578,8 @@
"LabelSettingsLibraryMarkAsFinishedWhen": "Merkitse mediakohde valmiiksi, kun",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Ohita aiemmat kirjat Jatka sarjassa",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Jatka sarja -kotisivun hyllyssä näkyy ensimmäinen kirja, jota ei ole aloitettu sarjoissa, joissa on vähintään yksi kirja valmiina eikä yhtään kirjaa kesken. Tämän asetuksen ottaminen käyttöön jatkaa sarjaa kauimpana valmistuneesta kirjasta ensimmäisen aloittamattoman kirjan sijaan.",
"LabelSettingsParseSubtitles": "Jäsennä tekstitykset",
"LabelSettingsParseSubtitlesHelp": "Pura tekstitykset äänikirjojen kansioiden nimistä.<br>Tekstitys on erotettava toisistaan merkillä \"-\"<br>ts. \"Kirjan otsikko - Tekstitys täällä\" on alaotsikko \"Tekstitys täällä\"",
"LabelSettingsParseSubtitles": "Jäsennä alaotsikot",
"LabelSettingsParseSubtitlesHelp": "Pura alaotsikot äänikirjojen kansioiden nimistä.<br>Tekstitys on erotettava toisistaan merkillä \"-\"<br>ts. \"Kirjan otsikko - Tekstitys täällä\" on alaotsikko \"Tekstitys täällä\"",
"LabelSettingsPreferMatchedMetadata": "Pidä mieluummin täsmäävät metatiedot",
"LabelSettingsPreferMatchedMetadataHelp": "Täsmäävät tiedot ohittavat kohteen tiedot käytettäessä Pikatäsmäystä. Oletuksena Pikatäsmäys täyttää vain puuttuvat tiedot.",
"LabelSettingsSkipMatchingBooksWithASIN": "Ohita täsmäävät kirjat, joilla on jo ASIN",
@@ -589,12 +599,13 @@
"LabelShareURL": "Jaa URL-osoite",
"LabelShowAll": "Näytä kaikki",
"LabelShowSeconds": "Näytä sekunnit",
"LabelShowSubtitles": "Näytä tekstitykset",
"LabelShowSubtitles": "Näytä alaotsikot",
"LabelSize": "Koko",
"LabelSleepTimer": "Uniajastin",
"LabelSlug": "Slug",
"LabelSortAscending": "Nouseva",
"LabelSortDescending": "Laskeva",
"LabelSortPubDate": "Järjestä julkaisupäivän mukaan",
"LabelStart": "Aloita",
"LabelStartTime": "Aloitusaika",
"LabelStarted": "Aloitettu",
@@ -614,7 +625,7 @@
"LabelStatsOverallDays": "Päivät kokonaisuudessaan",
"LabelStatsOverallHours": "Tunnit kokonaisuudessaan",
"LabelStatsWeekListening": "Viikon aikana kuunneltu",
"LabelSubtitle": "Tekstitys",
"LabelSubtitle": "Alaotsikko",
"LabelSupportedFileTypes": "Tuetut tiedostotyypit",
"LabelTag": "Tägi",
"LabelTags": "Tägit",
@@ -713,6 +724,7 @@
"MessageChapterErrorStartGteDuration": "Epäkelvollinen aloitusaika; on oltava lyhyempi kuin äänikirjan kesto",
"MessageChapterErrorStartLtPrev": "Epäkelvollinen aloitusaika; on oltava suurempi tai yhtä suuri kuin edellisen luvun aloitusaika",
"MessageChapterStartIsAfter": "Luku alkaa äänikirjan lopun jälkeen",
"MessageChaptersNotFound": "Kappaleita ei löydy",
"MessageCheckingCron": "Tarkistetaan cronia...",
"MessageConfirmCloseFeed": "Oletko varma, että haluat sulkea tämän syötteen?",
"MessageConfirmDeleteBackup": "Oletko varma, että haluat poistaa varmuuskopion {0}:lle?",
@@ -769,6 +781,7 @@
"MessageForceReScanDescription": "skannaa kaikki tiedostot uudelleen kuten uusi tarkistus. Äänitiedoston ID3-tunnisteet, OPF-tiedostot ja tekstitiedostot skannataan uusina.",
"MessageImportantNotice": "Tärkeä huomautus!",
"MessageInsertChapterBelow": "Syötä luku alle",
"MessageInvalidAsin": "Virheellinen ASIN",
"MessageItemsSelected": "{0} kohdetta valittu",
"MessageItemsUpdated": "{0} kohdetta päivitetty",
"MessageJoinUsOn": "Liity meihin",
@@ -777,70 +790,308 @@
"MessageLogsDescription": "Lokitiedot tallennetaan kansioon <code>/metadata/logs</code> JSON-tiedostoina. Kaatumislokit tallennetaan kansioon <code>/metadata/logs/crash_logs.txt</code>.",
"MessageM4BFailed": "M4B epäonnistui!",
"MessageM4BFinished": "M4B valmis!",
"MessageMapChapterTitles": "Kartoita lukujen otsikot olemassa oleviin äänikirjan lukuihin muuttamatta aikaleimoja",
"MessageMarkAllEpisodesFinished": "Merkitse kaikki jaksot päättyneiksi",
"MessageMarkAllEpisodesNotFinished": "Merkitse kaikki jaksot ei-päättyneiksi",
"MessageMarkAsFinished": "Merkitse valmiiksi",
"MessageMarkAsNotFinished": "Merkitse Ei-päättyneiksi",
"MessageMatchBooksDescription": "yrittää yhdistää kirjaston kirjoja valitun hakupalvelun kirjaan ja täyttää tyhjät tiedot ja kansikuvan. Ei korvaa yksityiskohtia.",
"MessageNoAudioTracks": "Ei ääniraitoja",
"MessageNoAuthors": "Ei tekijöitä",
"MessageNoBackups": "Ei varmuuskopioita",
"MessageNoBookmarks": "Ei kirjanmerkkejä",
"MessageNoChapters": "Ei kappaleita",
"MessageNoCollections": "Ei kokoelmia",
"MessageNoCoversFound": "Kansikuvia ei löydetty",
"MessageNoDescription": "Ei kuvausta",
"MessageNoDevices": "Ei laitteita",
"MessageNoDownloadsInProgress": "Ei latauksia tällä hetkellä meneillään",
"MessageNoDownloadsQueued": "Ei latauksia jonossa",
"MessageNoEpisodeMatchesFound": "Jaksoosumia ei löytynyt",
"MessageNoEpisodes": "Ei jaksoja",
"MessageNoFoldersAvailable": "Ei kansioita saatavilla",
"MessageNoGenres": "Ei lajityyppejä",
"MessageNoIssues": "Ei vikoja",
"MessageNoItems": "Ei kohteita",
"MessageNoItemsFound": "Kohteita ei löytynyt",
"MessageNoListeningSessions": "Ei kuunteluistuntoja",
"MessageNoLogs": "Ei lokeja",
"MessageNoMediaProgress": "Ei median edistymistä",
"MessageNoNotifications": "Ei ilmoituksia",
"MessageNoPodcastFeed": "Epäkelvollinen podcast: Ei syötettä",
"MessageNoPodcastsFound": "Podcasteja ei löytynyt",
"MessageNoResults": "Ei tuloksia",
"MessageNoSearchResultsFor": "Ei hakutuloksia \"{0}\":lle",
"MessageNoSeries": "Ei sarjaa",
"MessageNoTags": "Ei tunnisteita",
"MessageNoTasksRunning": "Ei käynnissä olevia tehtäviä",
"MessageNoUpdatesWereNecessary": "Päivityksiä ei tarvittu",
"MessageNoUserPlaylists": "Sinulla ei ole soittolistoja",
"MessageNoUserPlaylistsHelp": "Soittolistat ovat yksityisiä. Vain ne luonut käyttäjä näkee ne.",
"MessageNotYetImplemented": "Ei vielä toteutettu",
"MessageOpmlPreviewNote": "Huomautus: Tämä on esikatselu jäsennetystä OPML-tiedostosta. Varsinainen podcastin nimi tullaan ottamaan RSS-syötteestä.",
"MessageOr": "tai",
"MessagePauseChapter": "Keskeytä luvun toisto",
"MessagePlayChapter": "Kuuntele luvun alku",
"MessagePlaylistCreateFromCollection": "Luo soittolista kokoelmasta",
"MessagePleaseWait": "Ole hyvä ja odota...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcastilla ei ole RSS-syötteen URL-osoitetta, jota voitaisiin käyttää täsmäämiseen",
"MessagePodcastSearchField": "Syötä hakutermi tai RSS-syötteen URL-osoite",
"MessageQuickEmbedInProgress": "Pikaupottaminen meneillään",
"MessageQuickEmbedQueue": "Jonotettu pikaupotusta varten ({0} jonossa)",
"MessageQuickMatchAllEpisodes": "Pikatäsmää kaikki jaksot",
"MessageQuickMatchDescription": "Täytä tyhjän tuotteen tiedot ja kansi ensimmäisellä täsmäävällä tuloksella {0}:sta. Ei korvaa tietoja, ellei 'Pidä mieluummin täsmäävät metatiedot'-palvelinasetus on otettu käyttöön.",
"MessageRemoveChapter": "Poista luku",
"MessageRemoveEpisodes": "Poista {0} jakso(a)",
"MessageRemoveFromPlayerQueue": "Poista soittimen jonosta",
"MessageRemoveUserWarning": "Oletko varma, että haluat poistaa käyttäjän \"{0}\" pysyvästi?",
"MessageReportBugsAndContribute": "Ilmoita virheistä, toivo ominaisuuksia ja osallistu",
"MessageResetChaptersConfirm": "Oletko varma, että haluat nollata luvut ja kumota tekemäsi muutokset?",
"MessageRestoreBackupConfirm": "Oletko varma, että haluat palauttaa varmuuskopion, joka on luotu",
"MessageRestoreBackupWarning": "Varmuuskopion palauttaminen korvaa koko /config:ssa sijaitsevan tietokannan, ja kansikuvat /metadata/items & /metadata/authors:ssa.<br /><br />Varmuuskopiot eivät muuta kirjastokansioissasi olevia tiedostoja. Jos olet ottanut käyttöön palvelinasetuksissa kansikuvien ja metatietojen tallentamisen kirjaston kansioihin, niitä ei varmuuskopioida tai korvata.<br /><br />Kaikki palvelintasi käyttävät asiakkaat virkistetään automaattisesti.",
"MessageScheduleLibraryScanNote": "Suurimmalle osaa käyttäjistä on suositeltavaa jättää tämä ominaisuus pois päältä ja säilyttää kansiotarkkailu päällä. Kansiotarkkailu havaitsee automaattisesti tiedostomuutokset kirjaston kansioissa. Kansiotarkkailu ei toimi kaikille tiedostojärjestelmille (kuten NFS), jolloin voidaan käyttää ajastettuja kirjastoskannauksia.",
"MessageScheduleRunEveryWeekdayAtTime": "Suorita joka {0} klo {1}",
"MessageSearchResultsFor": "Hakutulokset haulle",
"MessageSelected": "{0} valittuna",
"MessageServerCouldNotBeReached": "Palvelimelle ei saatu yhteyttä",
"MessageSetChaptersFromTracksDescription": "Aseta luvut käyttämällä kutakin äänitiedostoa lukuna ja luvun otsikkoa äänitiedoston nimenä",
"MessageShareExpirationWillBe": "Umpeutuminen on <strong>{0}</strong>",
"MessageShareExpiresIn": "Umpeutuu {0}:n kuluttua",
"MessageShareURLWillBe": "Jaa URL-osoite on <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Aloitetaanko \"{0}\":n toisto klo {1}?",
"MessageTaskAudioFileNotWritable": "Äänitiedosto \"{0}\" ei ole kirjoitettava",
"MessageTaskCanceledByUser": "Tehtävä peruttu käyttäjän toimesta",
"MessageTaskDownloadingEpisodeDescription": "Ladataan jaksoa \"{0}\"",
"MessageTaskEmbeddingMetadata": "Upotetaan metatiedot",
"MessageTaskEmbeddingMetadataDescription": "Upotetaan metatiedot äänikirjaan \"{0}\"",
"MessageTaskEncodingM4b": "Koodaus M4B",
"MessageTaskEncodingM4bDescription": "Koodataan äänikirjaa \"{0}\" yhdeksi m4b-tiedostoksi",
"MessageTaskFailed": "Epäonnistunut",
"MessageTaskFailedToBackupAudioFile": "Äänitiedoston \"{0}\" varmuuskopiointi epäonnistui",
"MessageTaskFailedToCreateCacheDirectory": "Välimuistihakemiston luominen epäonnistui",
"MessageTaskFailedToEmbedMetadataInFile": "Metatietojen upottaminen tiedostoon \"{0}\" epäonnistui",
"MessageTaskFailedToMergeAudioFiles": "Äänitiedostojen yhdistäminen epäonnistui",
"MessageTaskFailedToMoveM4bFile": "m4b-tiedoston siirtäminen epäonnistui",
"MessageTaskFailedToWriteMetadataFile": "Metatietotiedoston kirjoittaminen epäonnistui",
"MessageTaskMatchingBooksInLibrary": "Vastaavat kirjat kirjastossa \"{0}\"",
"MessageTaskNoFilesToScan": "Ei skannattavia tiedostoja",
"MessageTaskOpmlImport": "OPML-tuonti",
"MessageTaskOpmlImportDescription": "Luodaan podcasteja {0} RSS-syötteistä",
"MessageTaskOpmlImportFeed": "OPML-tuontisyöte",
"MessageTaskOpmlImportFeedDescription": "Tuodaan RSS-syötettä \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Podcast-syötteen saaminen epäonnistui",
"MessageTaskOpmlImportFeedPodcastDescription": "Luodaan podcastia \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast on jo olemassa polulla",
"MessageTaskOpmlImportFeedPodcastFailed": "Podcastin luominen epäonnistui",
"MessageTaskOpmlImportFinished": "Lisätty {0} podcastia",
"MessageTaskOpmlParseFailed": "OPML-tiedoston jäsentäminen epäonnistui",
"MessageTaskOpmlParseFastFail": "Epäkelvollinen OPML-tiedoston <opml>-tunnistetta ei löytynyt tai <outline>-tunnistetta ei löytynyt",
"MessageTaskOpmlParseNoneFound": "Syötteitä ei löytynyt OPML-tiedostosta",
"MessageTaskScanItemsAdded": "{0} lisätty",
"MessageTaskScanItemsMissing": "{0} puuttuu",
"MessageTaskScanItemsUpdated": "{0} päivitetty",
"MessageTaskScanNoChangesNeeded": "Muutoksia ei tarvita",
"MessageTaskScanningFileChanges": "Tarkastetaan tiedoston muutoksia \"{0}\":sta",
"MessageTaskScanningLibrary": "Tarkastetaan kirjastoa \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "Kohdehakemisto ei ole kirjoitettava",
"MessageThinking": "Ajattellaan...",
"MessageUploaderItemFailed": "Lataaminen ulospäin epäonnistui",
"MessageUploaderItemSuccess": "Onnistuneesti ladattu! ulospäin!",
"MessageUploading": "Ladataan! ulospäin...",
"MessageValidCronExpression": "Kelvollinen cron-lauseke",
"MessageWatcherIsDisabledGlobally": "Kansiotarkkailu on poistettu käytöstä kaikkialla palvelimen asetuksissa",
"MessageXLibraryIsEmpty": "{0} Kirjasto on tyhjä!",
"MessageYourAudiobookDurationIsLonger": "Äänikirjasi kesto on pidempi kuin löydetty kesto",
"MessageYourAudiobookDurationIsShorter": "Äänikirjasi kesto on lyhyempi kuin löydetty kesto",
"NoteChangeRootPassword": "Käyttäjä root on ainoa käyttäjä, jolla voi olla tyhjä salasana",
"NoteChapterEditorTimes": "Huomautus: Ensimmäisen luvun aloitusajan on oltava 0:00 ja viimeisen luvun aloitusaika ei saa ylittää tätä äänikirjan kestoa.",
"NoteFolderPicker": "Huomautus: jo kartoitettuja kansioita ei näytetä",
"NoteRSSFeedPodcastAppsHttps": "Varoitus: Useimmat podcast-sovellukset edellyttävät, että RSS-syötteen URL-osoite käyttää HTTPS:a",
"NoteRSSFeedPodcastAppsPubDate": "Varoitus: yhdellä tai useammalla jaksollasi ei ole julkaisupäivämäärää. Jotkut podcast-sovellukset vaativat tämän.",
"NoteUploaderFoldersWithMediaFiles": "Mediatiedostoja sisältävät kansiot käsitellään erillisinä kirjastokohteina.",
"NoteUploaderOnlyAudioFiles": "Jos ladataan luospäin vain äänitiedostoja, silloin jokainen äänitiedosto käsitellään erillisenä äänikirjana.",
"NoteUploaderUnsupportedFiles": "Ei-tuetut tiedostot ohitetaan. Kansiota valittaessa tai pudottaessa, muut tiedostot, jotka eivät ole kohdekansiossa, ohitetaan.",
"NotificationOnBackupCompletedDescription": "Laukaistu, kun varmuuskopiointi on valmis",
"NotificationOnBackupFailedDescription": "Laukaistu, kun varmuuskopiointi epäonnistuu",
"NotificationOnEpisodeDownloadedDescription": "Laukaistu, kun podcast-jakso ladataan automaattisesti",
"NotificationOnTestDescription": "Tapahtuma ilmoitusjärjestelmän testaamista varten",
"PlaceholderNewCollection": "Uusi kokoelman nimi",
"PlaceholderNewFolderPath": "Uusi kansion polku",
"PlaceholderNewPlaylist": "Uusi soittolistan nimi",
"PlaceholderSearch": "Haku...",
"PlaceholderSearchEpisode": "Haku jaksosta..",
"StatsAuthorsAdded": "tekijät lisätty",
"StatsBooksAdded": "kirjat lisätty",
"StatsBooksAdditional": "Jotkut lisäykset sisältävät…",
"StatsBooksFinished": "kirjat päättyneet",
"StatsBooksFinishedThisYear": "Jotkut kirjat päättyneet tänä vuonna…",
"StatsBooksListenedTo": "kuunnellut kirjat",
"StatsCollectionGrewTo": "Kirjakokoelmasi kasvoi asti…",
"StatsSessions": "istunnot",
"StatsSpentListening": "kuunteluun käytetty",
"StatsTopAuthor": "HUIPPUTEKIJÄ",
"StatsTopAuthors": "HUIPPUTEKIJÄT",
"StatsTopGenre": "HUIPPUTYYLILAJI",
"StatsTopGenres": "HUIPPUTYYLILAJIT",
"StatsTopMonth": "HUIPPUKUUKAUSI",
"StatsTopNarrator": "HUIPPUKERTOJA",
"StatsTopNarrators": "HUIPPUKERTOJAT",
"StatsTotalDuration": "Kokonaiskestolla…",
"StatsYearInReview": "VUOSI KATSAUKSESSA",
"ToastAccountUpdateSuccess": "Tili päivitetty",
"ToastAppriseUrlRequired": "Arvon tulee olla Apprise URL",
"ToastAsinRequired": "ASIN vaaditaan",
"ToastAuthorImageRemoveSuccess": "Tekijän kuva poistettu",
"ToastAuthorNotFound": "Tekijää \"{0}\" ei löydy",
"ToastAuthorRemoveSuccess": "Tekijä poistettu",
"ToastAuthorSearchNotFound": "Tekijää ei löydy",
"ToastAuthorUpdateMerged": "Tekijä yhdistetty",
"ToastAuthorUpdateSuccess": "Tekijä päivitetty",
"ToastAuthorUpdateSuccessNoImageFound": "Tekijä päivitetty (kuvaa ei löytynyt)",
"ToastBackupAppliedSuccess": "Varmuuskopiointi sovellettu",
"ToastBackupCreateFailed": "Varmuuskopion luominen epäonnistui",
"ToastBackupCreateSuccess": "Varmuuskopio luotu",
"ToastBackupDeleteFailed": "Varmuuskopion poistaminen epäonnistui",
"ToastBackupDeleteSuccess": "Varmuuskopio poistettu",
"ToastBackupInvalidMaxKeep": "Epäkelvollinen määrä säilytettäviä varmuuskopioita",
"ToastBackupInvalidMaxSize": "Epäkelvollinen varmuuskopion enimmäiskoko",
"ToastBackupRestoreFailed": "Varmuuskopion palauttaminen epäonnistui",
"ToastBackupUploadFailed": "Varmuuskopion lataaminen ulospäin epäonnistui",
"ToastBackupUploadSuccess": "Varmuuskopio ladattu ulospäin",
"ToastBatchApplyDetailsToItemsSuccess": "Kohteisiin sovelletut yksityiskohdat",
"ToastBatchDeleteFailed": "Eräpoisto epäonnistui",
"ToastBatchDeleteSuccess": "Eräpoisto onnistui",
"ToastBatchQuickMatchFailed": "Erän pikatäsmäys epäonnistui!",
"ToastBatchQuickMatchStarted": "{0} kirjan erän pikatäsmäys aloitettu!",
"ToastBatchUpdateFailed": "Eräpäivitys epäonnistui",
"ToastBatchUpdateSuccess": "Eräpäivitys onnistui",
"ToastBookmarkCreateFailed": "Kirjanmerkin luominen epäonnistui",
"ToastBookmarkCreateSuccess": "Kirjanmerkki lisätty",
"ToastBookmarkRemoveSuccess": "Kirjanmerkki poistettu",
"ToastCachePurgeFailed": "Välimuistin tyhjentäminen epäonnistui",
"ToastCachePurgeSuccess": "Välimuisti tyhjennetty onnistuneesti",
"ToastChaptersHaveErrors": "Luvuissa on virheitä",
"ToastChaptersMustHaveTitles": "Lukuilla on oltava otsikot",
"ToastChaptersRemoved": "Luvut poistettu",
"ToastChaptersUpdated": "Luvut päivitetty",
"ToastCollectionItemsAddFailed": "Kohteen/kohteiden lisääminen kokoelmaan epäonnistui",
"ToastCollectionRemoveSuccess": "Kokoelma poistettu",
"ToastCollectionUpdateSuccess": "Kokoelma päivitetty",
"ToastCoverUpdateFailed": "Kansikuvan päivitys epäonnistui",
"ToastDateTimeInvalidOrIncomplete": "Päivämäärä ja aika ovat epäkelvolliset tai puutteelliset",
"ToastDeleteFileFailed": "Tiedoston poistaminen epäonnistui",
"ToastDeleteFileSuccess": "Tiedosto poistettu",
"ToastDeviceAddFailed": "Laitteen lisääminen epäonnistui",
"ToastDeviceNameAlreadyExists": "Tämän niminen sähköinen lukulaite on jo olemassa",
"ToastDeviceTestEmailFailed": "Testisähköpostin lähettäminen epäonnistui",
"ToastDeviceTestEmailSuccess": "Testisähköposti lähetetty",
"ToastEmailSettingsUpdateSuccess": "Sähköpostiasetukset päivitetty",
"ToastEncodeCancelFailed": "Koodauksen peruuttaminen epäonnistui",
"ToastEncodeCancelSucces": "Koodaaminen peruutettu",
"ToastEpisodeDownloadQueueClearFailed": "Jonon tyhjentäminen epäonnistui",
"ToastEpisodeDownloadQueueClearSuccess": "Jakson latausjono tyhjennetty",
"ToastEpisodeUpdateSuccess": "{0} jaksoa päivitetty",
"ToastErrorCannotShare": "Ei voi jakaa alkuperäisesti tällä laitteella",
"ToastFailedToLoadData": "Tietojen lataaminen epäonnistui",
"ToastFailedToMatch": "Vastaaminen epäonnistui",
"ToastFailedToShare": "Jakaminen epäonnistui",
"ToastFailedToUpdate": "Päivittäminen epäonnistui",
"ToastInvalidImageUrl": "Epäkelvollinen kuvan URL-osoite",
"ToastInvalidMaxEpisodesToDownload": "Ladattavien jaksojen enimmäismäärä on epäkelvollinen",
"ToastInvalidUrl": "Epäkelvollinen URL-osoite",
"ToastItemCoverUpdateSuccess": "Kohteen kansikuva päivitetty",
"ToastItemDeletedFailed": "Kohteen poistaminen epäonnistui",
"ToastItemDeletedSuccess": "Poistettu kohde",
"ToastItemDetailsUpdateSuccess": "Tuotteen yksityiskohdat päivitetty",
"ToastItemMarkedAsFinishedFailed": "Valmiiksi merkitseminen epäonnistui",
"ToastItemMarkedAsFinishedSuccess": "Kohde merkitty Päättyneeksi",
"ToastItemMarkedAsNotFinishedFailed": "Valmiiksi merkitsemisen poisto epäonnistui",
"ToastItemMarkedAsNotFinishedSuccess": "Kohde merkitty Ei-päättyneeksi",
"ToastItemUpdateSuccess": "Kohde päivitetty",
"ToastLibraryCreateFailed": "Kirjaston luominen epäonnistui",
"ToastLibraryCreateSuccess": "Kirjasto \"{0}\" luotu",
"ToastLibraryDeleteFailed": "Kirjaston poistaminen epäonnistui",
"ToastLibraryDeleteSuccess": "Kirjasto poistettu",
"ToastLibraryScanFailedToStart": "Skannauksen käynnistäminen epäonnistui",
"ToastLibraryScanStarted": "Kirjaston skannaus käynnistetty",
"ToastLibraryUpdateSuccess": "Kirjasto \"{0}\" päivitetty",
"ToastMatchAllAuthorsFailed": "Kaikkia tekijöitä ei voitu vaastattaa",
"ToastMetadataFilesRemovedError": "Virhe poistettaessa metadata.{0}-tiedostot",
"ToastMetadataFilesRemovedNoneFound": "metadata.{0}-tiedostoja ei löytynyt kirjastosta",
"ToastMetadataFilesRemovedNoneRemoved": "Ei metadata.{0}-tiedostoja poistettu",
"ToastMetadataFilesRemovedSuccess": "{0} metadata.{1}-tiedostoa poistettu",
"ToastMustHaveAtLeastOnePath": "On oltava vähintään yksi polku",
"ToastNameEmailRequired": "Nimi ja sähköpostiosoite vaaditaan",
"ToastNameRequired": "Nimi vaaditaan",
"ToastNewEpisodesFound": "{0} uutta jaksoa löydetty",
"ToastNewUserCreatedFailed": "Tilin \"{0}\" luominen epäonnistui",
"ToastNewUserCreatedSuccess": "Uusi tili luotu",
"ToastNewUserLibraryError": "On valittava vähintään yksi kirjasto",
"ToastNewUserPasswordError": "On oltava salasana; vain käyttäjällä root voi olla tyhjä salasana",
"ToastNewUserTagError": "On valittava vähintään yksi tunniste",
"ToastNewUserUsernameError": "Syötä käyttäjänimi",
"ToastNoNewEpisodesFound": "Uusia jaksoja ei löytynyt",
"ToastNoRSSFeed": "Podcastilla ei ole RSS-syötettä",
"ToastNoUpdatesNecessary": "Päivityksiä ei tarvita",
"ToastNotificationCreateFailed": "Ilmoituksen luominen epäonnistui",
"ToastNotificationDeleteFailed": "Ilmoituksen poistaminen epäonnistui",
"ToastNotificationFailedMaximum": "Epäonnistuneiden yritysten enimmäismäärän on oltava >= 0",
"ToastNotificationQueueMaximum": "Ilmoitusjonon enimmäismäärä on oltava >= 0",
"ToastNotificationSettingsUpdateSuccess": "Ilmoitusasetukset päivitetty",
"ToastNotificationTestTriggerFailed": "Testiilmoituksen laukaiseminen epäonnistui",
"ToastNotificationTestTriggerSuccess": "Laukaistiin testiilmoitus",
"ToastNotificationUpdateSuccess": "Ilmoitus päivitetty",
"ToastPlaylistCreateFailed": "Soittolistan luominen epäonnistui",
"ToastPlaylistCreateSuccess": "Soittolista luotu",
"ToastPlaylistRemoveSuccess": "Soittolista poistettu",
"ToastPlaylistUpdateSuccess": "Soittolista päivitetty",
"ToastPodcastCreateFailed": "Podcastin luominen epäonnistui",
"ToastPodcastCreateSuccess": "Podcastin luominen onnistui",
"ToastPodcastGetFeedFailed": "Podcast-syötteen saaminen epäonnistui",
"ToastPodcastNoEpisodesInFeed": "RSS-syötteestä ei löytynyt jaksoja",
"ToastPodcastNoRssFeed": "Podcastilla ei ole RSS-syötettä",
"ToastProgressIsNotBeingSynced": "Edistystä ei synkronoida, aloita toisto uudelleen",
"ToastProviderCreatedFailed": "Palveluntarjoajan lisääminen epäonnistui",
"ToastProviderCreatedSuccess": "Uusi palveluntarjoaja lisätty",
"ToastProviderNameAndUrlRequired": "Nimi ja URL-osoite vaaditaan",
"ToastProviderRemoveSuccess": "Palveluntarjoaja poistettu",
"ToastRSSFeedCloseFailed": "RSS syötteen sulkeminen epäonnistui",
"ToastRSSFeedCloseSuccess": "RSS syöte suljettu",
"ToastRemoveFailed": "Poistaminen epäonnistui",
"ToastRemoveItemFromCollectionFailed": "Kohteen poistaminen kokoelmasta epäonnistui",
"ToastRemoveItemFromCollectionSuccess": "Kohde poistettu kokoelmasta",
"ToastRemoveItemsWithIssuesFailed": "Vikoja sisältävien kirjastokohteiden poistaminen epäonnistui",
"ToastRemoveItemsWithIssuesSuccess": "Vikoja sisältäviä kirjastokohteita poistettu",
"ToastRenameFailed": "Uudelleennimeäminen epäonnistui",
"ToastRescanFailed": "Uudelleenskannaus {0}n kohdalla epäonnistui",
"ToastRescanRemoved": "Uudelleenskannauksen täydellinen kohde poistettiin",
"ToastRescanUpToDate": "Uudelleenskannauksen täydellinen kohde oli ajan tasalla",
"ToastRescanUpdated": "Uudelleenskannauksen täydellinen kohde päivitettiin",
"ToastScanFailed": "Kirjastokohteen skannaaminen epäonnistui",
"ToastSelectAtLeastOneUser": "Valitse ainakin yksi käyttäjä",
"ToastSendEbookToDeviceFailed": "S-kirjan lähettäminen laitteeseen epäonnistui",
"ToastSendEbookToDeviceSuccess": "S-kirja lähetetty laitteeseen \"{0}\"",
"ToastSeriesSubmitFailedSameName": "Ei voi lisätä kahta samannimistä sarjaa",
"ToastSeriesUpdateFailed": "Sarjan päivittäminen epäonnistui",
"ToastSeriesUpdateSuccess": "Sarjan päivittäminen onnistui",
"ToastServerSettingsUpdateSuccess": "Palvelimen asetukset päivitetty",
"ToastSessionCloseFailed": "Istunnon sulkeminen epäonnistui",
"ToastSessionDeleteFailed": "Istunnon poistaminen epäonnistui",
"ToastSessionDeleteSuccess": "Istunto poistettu",
"ToastSleepTimerDone": "Uniajastin tehty... zZzzZz",
"ToastSlugMustChange": "Slug sisältää epäkelvollisia merkkejä",
"ToastSlugRequired": "Slug vaaditaan",
"ToastSocketConnected": "Yhteys saatu",
"ToastSocketDisconnected": "Yhteys katkaistu",
"ToastSocketFailedToConnect": "Yhteyden muodostus epäonnistui",
"ToastSortingPrefixesEmptyError": "On oltava vähintään yksi lajitteluetuliite",
"ToastSortingPrefixesUpdateSuccess": "Lajitteluetuliitteet päivitetty ({0} kohdetta)",
"ToastTitleRequired": "Otsikko on pakollinen",
"ToastUnknownError": "Tuntematon virhe",
"ToastUnlinkOpenIdFailed": "Käyttäjän linkityksen poistaminen OpenID:sta epäonnistui",
"ToastUnlinkOpenIdSuccess": "Käyttäjän linkitys poistettu OpenID:sta",
"ToastUploaderFilepathExistsError": "Tiedostopolku \"{0}\" on jo olemassa palvelimella",
"ToastUploaderItemExistsInSubdirectoryError": "Kohde {0} käyttää ulospäinlatauspolun alihakemistoa.",
"ToastUserDeleteFailed": "Käyttäjän poisto epäonnistui",
"ToastUserDeleteSuccess": "Käyttäjä poistettu",
"ToastUserPasswordChangeSuccess": "Salasana vaihdettu onnistuneesti",

View File

@@ -229,6 +229,7 @@
"LabelAddedDate": "Ajouté le {0}",
"LabelAdminUsersOnly": "Administrateurs uniquement",
"LabelAll": "Tout",
"LabelAllEpisodesDownloaded": "Tous les épisodes ont été téléchargés",
"LabelAllUsers": "Tous les utilisateurs",
"LabelAllUsersExcludingGuests": "Tous les utilisateurs à lexception des invités",
"LabelAllUsersIncludingGuests": "Tous les utilisateurs, y compris les invités",
@@ -252,7 +253,7 @@
"LabelBackToUser": "Retour à lutilisateur",
"LabelBackupAudioFiles": "Sauvegarder les fichiers audio",
"LabelBackupLocation": "Emplacement de la sauvegarde",
"LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques",
"LabelBackupsEnableAutomaticBackups": "Sauvegardes automatiques",
"LabelBackupsEnableAutomaticBackupsHelp": "Sauvegardes enregistrées dans /metadata/backups",
"LabelBackupsMaxBackupSize": "Taille maximale de la sauvegarde (en Go) (0 pour illimité)",
"LabelBackupsMaxBackupSizeHelp": "Afin de prévenir les mauvaises configuration, la sauvegarde échouera si elle excède la taille limite.",
@@ -279,7 +280,7 @@
"LabelCollections": "Collections",
"LabelComplete": "Complet",
"LabelConfirmPassword": "Confirmer le mot de passe",
"LabelContinueListening": "Continuer la lecture",
"LabelContinueListening": "Continuer l'écoute",
"LabelContinueReading": "Continuer la lecture",
"LabelContinueSeries": "Continuer les séries",
"LabelCover": "Couverture",
@@ -302,7 +303,7 @@
"LabelDiscFromFilename": "Depuis le fichier",
"LabelDiscFromMetadata": "Depuis les métadonnées",
"LabelDiscover": "Découvrir",
"LabelDownload": "Téléchargement",
"LabelDownload": "Télécharger",
"LabelDownloadNEpisodes": "Télécharger {0} épisode(s)",
"LabelDownloadable": "Téléchargeable",
"LabelDuration": "Durée",
@@ -529,6 +530,7 @@
"LabelReleaseDate": "Date de parution",
"LabelRemoveAllMetadataAbs": "Supprimer tous les fichiers metadata.abs",
"LabelRemoveAllMetadataJson": "Supprimer tous les fichiers metadata.json",
"LabelRemoveAudibleBranding": "Supprimer lintro et la fin Audible des chapitres",
"LabelRemoveCover": "Supprimer la couverture",
"LabelRemoveMetadataFile": "Supprimer les fichiers de métadonnées dans les dossiers des éléments de la bibliothèque",
"LabelRemoveMetadataFileHelp": "Supprimer tous les fichiers metadata.json et metadata.abs de vos dossiers {0}.",
@@ -558,6 +560,8 @@
"LabelSettingsBookshelfViewHelp": "Interface skeumorphique avec étagères en bois",
"LabelSettingsChromecastSupport": "Support du Chromecast",
"LabelSettingsDateFormat": "Format de date",
"LabelSettingsEnableWatcher": "Analyser automatiquement les bibliothèques pour détecter les modifications",
"LabelSettingsEnableWatcherForLibrary": "Analyser automatiquement la bibliothèque pour détecter les modifications",
"LabelSettingsEnableWatcherHelp": "Active la mise à jour automatique d'éléments lorsque des modifications de fichiers sont détectées. * Nécessite le redémarrage du serveur",
"LabelSettingsEpubsAllowScriptedContent": "Autoriser le contenu scénarisé pour les fichiers EPUB",
"LabelSettingsEpubsAllowScriptedContentHelp": "Autoriser les fichiers EPUB à exécuter des scripts. Il est recommandé de laisser ce paramètre désactivé, sauf si vous faites confiance à la source des fichiers EPUB.",
@@ -575,7 +579,7 @@
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Sauter les livres précédents dans « Continuer la série »",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Létagère de la page daccueil « Continuer la série » affiche le premier livre non commencé dans les séries dont au moins un livre est terminé et aucun livre nest en cours. Lactivation de ce paramètre permet de poursuivre la série à partir du dernier livre terminé au lieu du premier livre non commencé.",
"LabelSettingsParseSubtitles": "Analyser les sous-titres",
"LabelSettingsParseSubtitlesHelp": "Extrait les sous-titres depuis le dossier du livre audio.<br>Les sous-titres doivent être séparés par des « - »<br>cest-à-dire : « Titre du livre - Ceci est un sous-titre » aura le sous-titre « Ceci est un sous-titre »",
"LabelSettingsParseSubtitlesHelp": "Extraire les sous-titres des noms de dossiers de livres audio.<br>Les sous-titres doivent être séparés par « - »<br>Par exemple, « Titre du livre - Un sous-titre » a pour sous-titre « Un sous-titre »",
"LabelSettingsPreferMatchedMetadata": "Préférer les métadonnées par correspondance",
"LabelSettingsPreferMatchedMetadataHelp": "Les métadonnées mises en correspondance remplaceront les détails de lélément lors de lutilisation de la correspondance rapide. Par défaut, la correspondance rapide ne remplira que les détails manquants.",
"LabelSettingsSkipMatchingBooksWithASIN": "Ignorer la recherche par correspondance pour les livres ayant déjà un ASIN",
@@ -601,6 +605,7 @@
"LabelSlug": "Identifiant dURL",
"LabelSortAscending": "Croissant",
"LabelSortDescending": "Décroissant",
"LabelSortPubDate": "Trier par date de publication",
"LabelStart": "Démarrer",
"LabelStartTime": "Heure de démarrage",
"LabelStarted": "Démarré",
@@ -701,11 +706,14 @@
"LabelYourProgress": "Votre progression",
"MessageAddToPlayerQueue": "Ajouter en file dattente",
"MessageAppriseDescription": "Nécessite une instance d<a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">API Apprise</a> pour utiliser cette fonctionnalité ou une api qui prend en charge les mêmes requêtes.<br />LURL de lAPI Apprise doit comprendre le chemin complet pour envoyer la notification. Par exemple, si votre instance écoute sur <code>http://192.168.1.1:8337</code> alors vous devez mettre <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Assurez-vous dutiliser lASIN de la bonne région Audible, et non dAmazon.",
"MessageAuthenticationOIDCChangesRestart": "Redémarrez votre serveur après avoir enregistré pour appliquer les modifications OIDC.",
"MessageBackupsDescription": "Les sauvegardes incluent les utilisateurs, la progression des utilisateurs, les détails des éléments de la bibliothèque, les paramètres du serveur et les images stockées dans <code>/metadata/items</code> & <code>/metadata/authors</code>. Les sauvegardes <strong>nincluent pas</strong> les fichiers stockés dans les dossiers de votre bibliothèque.",
"MessageBackupsLocationEditNote": "Remarque: Mettre à jour l'emplacement de sauvegarde ne déplacera pas ou ne modifiera pas les sauvegardes existantes",
"MessageBackupsLocationNoEditNote": "Remarque: lemplacement de sauvegarde est défini via une variable denvironnement et ne peut pas être modifié ici.",
"MessageBackupsLocationPathEmpty": "L'emplacement de secours ne peut pas être vide",
"MessageBatchEditPopulateMapDetailsAllHelp": "Remplir les champs disponibles avec les données de tous les éléments. Les champs avec des valeurs multiples seront fusionnés.",
"MessageBatchEditPopulateMapDetailsItemHelp": "Renseigner les champs de la carte active avec les informations de cet élément",
"MessageBatchQuickMatchDescription": "La recherche par correspondance rapide tentera dajouter les couvertures et métadonnées manquantes pour les éléments sélectionnés. Activez les options ci-dessous pour permettre la Recherche par correspondance décraser les couvertures et/ou métadonnées existantes.",
"MessageBookshelfNoCollections": "Vous navez pas encore de collections",
"MessageBookshelfNoCollectionsHelp": "Les collections sont publiques. Tous les utilisateurs ayant accès à la bibliothèque pourront les voir.",
@@ -718,6 +726,7 @@
"MessageChapterErrorStartGteDuration": "Horodatage invalide car il doit débuter avant la fin du livre",
"MessageChapterErrorStartLtPrev": "Horodatage invalide car il doit débuter au moins après le précédent chapitre",
"MessageChapterStartIsAfter": "Le premier chapitre est situé au début de votre livre audio",
"MessageChaptersNotFound": "Chapitres non trouvés",
"MessageCheckingCron": "Vérification du cron…",
"MessageConfirmCloseFeed": "Êtes-vous sûr·e de vouloir fermer ce flux?",
"MessageConfirmDeleteBackup": "Êtes-vous sûr·e de vouloir supprimer la sauvegarde de « {0} » ?",
@@ -774,6 +783,7 @@
"MessageForceReScanDescription": "analysera de nouveau tous les fichiers. Les étiquettes ID3 des fichiers audio, les fichiers OPF et les fichiers texte seront analysés comme sils étaient nouveaux.",
"MessageImportantNotice": "Information importante !",
"MessageInsertChapterBelow": "Insérer le chapitre ci-dessous",
"MessageInvalidAsin": "ASIN invalide",
"MessageItemsSelected": "{0} éléments sélectionnés",
"MessageItemsUpdated": "{0} éléments mis à jour",
"MessageJoinUsOn": "Rejoignez-nous sur",
@@ -819,7 +829,7 @@
"MessageNoTasksRunning": "Aucune tâche en cours",
"MessageNoUpdatesWereNecessary": "Aucune mise à jour nétait nécessaire",
"MessageNoUserPlaylists": "Vous navez aucune liste de lecture",
"MessageNoUserPlaylistsHelp": "Les playlists sont privées. Seul l'utilisateur qui les a créées peut les voir.",
"MessageNoUserPlaylistsHelp": "Les playlists sont privées. Seul lutilisateur qui les crée peut les voir.",
"MessageNotYetImplemented": "Non implémenté",
"MessageOpmlPreviewNote": "Remarque: Il sagit dun aperçu du fichier OPML analysé. Le titre réel du podcast provient du flux RSS.",
"MessageOr": "ou",
@@ -845,6 +855,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Exécuté tous les {0} à {1}",
"MessageSearchResultsFor": "Résultats de recherche pour",
"MessageSelected": "{0} sélectionnés",
"MessageSeriesSequenceCannotContainSpaces": "La séquence de séries ne peut pas contenir despaces",
"MessageServerCouldNotBeReached": "Serveur inaccessible",
"MessageSetChaptersFromTracksDescription": "Positionne un chapitre par fichier audio, avec le titre du fichier comme titre de chapitre",
"MessageShareExpirationWillBe": "Expire le <strong>{0}</strong>",
@@ -950,6 +961,7 @@
"ToastBackupRestoreFailed": "Échec de la restauration de sauvegarde",
"ToastBackupUploadFailed": "Échec du téléversement de sauvegarde",
"ToastBackupUploadSuccess": "Sauvegarde téléversée",
"ToastBatchApplyDetailsToItemsSuccess": "Détails appliqués aux articles",
"ToastBatchDeleteFailed": "Échec de la suppression par lot",
"ToastBatchDeleteSuccess": "Suppression par lot réussie",
"ToastBatchQuickMatchFailed": "Échec de la correspondance rapide par lot!",
@@ -962,6 +974,8 @@
"ToastCachePurgeFailed": "Échec de la purge du cache",
"ToastCachePurgeSuccess": "Cache purgé avec succès",
"ToastChaptersHaveErrors": "Les chapitres contiennent des erreurs",
"ToastChaptersInvalidShiftAmountLast": "Durée de décalage non valide. Lheure de début du dernier chapitre pourrait dépasser la durée de ce livre audio.",
"ToastChaptersInvalidShiftAmountStart": "Durée de décalage non valide. Le premier chapitre aurait une longueur nulle ou négative et serait écrasé par le second. Augmentez la durée de début du second chapitre.",
"ToastChaptersMustHaveTitles": "Les chapitre doivent avoir un titre",
"ToastChaptersRemoved": "Chapitres supprimés",
"ToastChaptersUpdated": "Chapitres mis à jour",
@@ -1062,6 +1076,7 @@
"ToastSelectAtLeastOneUser": "Sélectionnez au moins un utilisateur",
"ToastSendEbookToDeviceFailed": "Échec de lenvoi du livre numérique à lappareil",
"ToastSendEbookToDeviceSuccess": "Livre numérique envoyé à lappareil : {0}",
"ToastSeriesSubmitFailedSameName": "Impossible dajouter deux séries ayant le même nom",
"ToastSeriesUpdateFailed": "Échec de la mise à jour de la série",
"ToastSeriesUpdateSuccess": "Mise à jour de la série réussie",
"ToastServerSettingsUpdateSuccess": "Mise à jour des paramètres du serveur",
@@ -1080,6 +1095,8 @@
"ToastUnknownError": "Erreur inconnue",
"ToastUnlinkOpenIdFailed": "Échec de la dissociation de lutilisateur lOpenID",
"ToastUnlinkOpenIdSuccess": "Utilisateur dissocié de OpenID",
"ToastUploaderFilepathExistsError": "Le chemin de fichier « {0} » existe déjà sur le serveur",
"ToastUploaderItemExistsInSubdirectoryError": "Lélément « {0} » utilise un sous-répertoire du chemin de téléchargement.",
"ToastUserDeleteFailed": "Échec de la suppression de lutilisateur",
"ToastUserDeleteSuccess": "Utilisateur supprimé",
"ToastUserPasswordChangeSuccess": "Mot de passe modifié avec succès",

View File

@@ -10,6 +10,8 @@
"ButtonApplyChapters": "החל פרקים",
"ButtonAuthors": "סופרים",
"ButtonBack": "חזור",
"ButtonBatchEditPopulateFromExisting": "מלא משדות קיימים",
"ButtonBatchEditPopulateMapDetails": "מלא פרטי מפה",
"ButtonBrowseForFolder": "עיין בתיקייה",
"ButtonCancel": "ביטול",
"ButtonCancelEncode": "בטל קידוד",
@@ -29,7 +31,9 @@
"ButtonEdit": "ערוך",
"ButtonEditChapters": "ערוך פרקים",
"ButtonEditPodcast": "ערוך פודקאסט",
"ButtonEnable": "הפעל",
"ButtonEnable": "אפשר",
"ButtonFireAndFail": "שלח בכישלון",
"ButtonFireOnTest": "שלח באירוע בדיקה",
"ButtonForceReScan": "סרוק מחדש בכוח",
"ButtonFullPath": "נתיב מלא",
"ButtonHide": "הסתר",
@@ -37,7 +41,7 @@
"ButtonIssues": "תקלות",
"ButtonJumpBackward": "דלג אחורה",
"ButtonJumpForward": "דלג קדימה",
"ButtonLatest": "חדש ביותר",
"ButtonLatest": "אחרון",
"ButtonLibrary": "ספרייה",
"ButtonLogout": "התנתק",
"ButtonLookup": "חפש",
@@ -70,7 +74,7 @@
"ButtonReScan": "סרוק מחדש",
"ButtonRead": "קרא",
"ButtonReadLess": "קרא פחות",
"ButtonReadMore": "קרא יותר",
"ButtonReadMore": "קרא עוד",
"ButtonRefresh": "רענן",
"ButtonRemove": "הסר",
"ButtonRemoveAll": "הסר הכל",
@@ -86,7 +90,9 @@
"ButtonSaveTracklist": "שמור רשימת רצועות",
"ButtonScan": "סרוק",
"ButtonScanLibrary": "סרוק ספרייה",
"ButtonSearch": "חפש",
"ButtonScrollLeft": "גלול שמאלה",
"ButtonScrollRight": "גלול ימינה",
"ButtonSearch": "חיפוש",
"ButtonSelectFolderPath": "בחר נתיב לתיקייה",
"ButtonSeries": "סדרה",
"ButtonSetChaptersFromTracks": "קבע פרקים לפי הרצועות",
@@ -96,7 +102,7 @@
"ButtonStartM4BEncode": "התחל קידוד M4B",
"ButtonStartMetadataEmbed": "התחל הטמעת מטא-נתונים",
"ButtonStats": "סטטיסטיקות",
"ButtonSubmit": "שלח",
"ButtonSubmit": "שליחה",
"ButtonTest": "בדיקה",
"ButtonUnlinkOpenId": "נתק OpenID",
"ButtonUpload": "העלה",
@@ -122,26 +128,26 @@
"HeaderChapters": "פרקים",
"HeaderChooseAFolder": "בחר תיקייה",
"HeaderCollection": "אוסף",
"HeaderCollectionItems": "פריטי אוסף",
"HeaderCollectionItems": "פרטי אוסף",
"HeaderCover": "כריכה",
"HeaderCurrentDownloads": "הורדות נוכחיות",
"HeaderCustomMessageOnLogin": "הודעה מותאמת אישית בהתחברות",
"HeaderCustomMetadataProviders": "ספקי מטא-נתונים מותאמים אישית",
"HeaderDetails": "פרטים",
"HeaderDownloadQueue": "תור הורדה",
"HeaderEbookFiles": "קבצי ספר אלקטרוני",
"HeaderEbookFiles": "קבצי Ebook",
"HeaderEmail": "אימייל",
"HeaderEmailSettings": "הגדרות אימייל",
"HeaderEpisodes": "פרקים",
"HeaderEreaderDevices": "התקני קריאה דיגיטליים",
"HeaderEreaderSettings": "הגדרות התקני קריאה דיגיטליים",
"HeaderEreaderSettings": "הגדרות קורא אלקטרוני",
"HeaderFiles": "קבצים",
"HeaderFindChapters": "מצא פרקים",
"HeaderIgnoredFiles": "קבצים שנתעלמו",
"HeaderItemFiles": "קבצי פריט",
"HeaderItemMetadataUtils": "כלי מטא-נתונים",
"HeaderLastListeningSession": "הפעלת האזנה אחרונה",
"HeaderLatestEpisodes": "הפרקים העדכניים ביותר",
"HeaderLatestEpisodes": "פרקים אחרונים",
"HeaderLibraries": "ספריות",
"HeaderLibraryFiles": "קבצי ספרייה",
"HeaderLibraryStats": "סטטיסטיקות ספרייה",
@@ -171,8 +177,9 @@
"HeaderPlaylist": "רשימת השמעה",
"HeaderPlaylistItems": "פריטי רשימת השמעה",
"HeaderPodcastsToAdd": "פודקאסטים להוספה",
"HeaderPresets": "קביעות מוגדרות מראש",
"HeaderPreviewCover": "תצוגה מקדימה של כריכה",
"HeaderRSSFeedGeneral": "פרטי ערוץ RSS",
"HeaderRSSFeedGeneral": "פרטי RSS",
"HeaderRSSFeedIsOpen": "ערוץ RSS פתוח",
"HeaderRSSFeeds": "ערוצי RSS",
"HeaderRemoveEpisode": "הסר פרק",
@@ -188,14 +195,15 @@
"HeaderSettingsExperimental": "תכונות ניסיוניות",
"HeaderSettingsGeneral": "כללי",
"HeaderSettingsScanner": "סורק",
"HeaderSettingsWebClient": "מערך",
"HeaderSleepTimer": "טיימר שינה",
"HeaderStatsLargestItems": "הפריטים הגדולים ביותר",
"HeaderStatsLongestItems": "הפריטים הארוכים ביותר (בשעות)",
"HeaderStatsMinutesListeningChart": "דקות האזנה (בימים האחרונים)",
"HeaderStatsRecentSessions": פעלות אחרונות",
"HeaderStatsMinutesListeningChart": "דקות האזנה (7 ימים אחרונים)",
"HeaderStatsRecentSessions": אזנות אחרונות",
"HeaderStatsTop10Authors": "10 היוצרים המובילים",
"HeaderStatsTop5Genres": "הז'אנרים המובילים 5",
"HeaderTableOfContents": "תוכן העניינים",
"HeaderTableOfContents": "תוכן עניינים",
"HeaderTools": "כלים",
"HeaderUpdateAccount": "עדכן חשבון",
"HeaderUpdateAuthor": "עדכן יוצר",
@@ -212,15 +220,17 @@
"LabelAccountTypeAdmin": "מנהל",
"LabelAccountTypeGuest": "אורח",
"LabelAccountTypeUser": "משתמש",
"LabelActivities": "פעילויות",
"LabelActivity": "פעילות",
"LabelAddToCollection": "הוסף לאוסף",
"LabelAddToCollectionBatch": "הוסף {0} ספרים לאוסף",
"LabelAddToPlaylist": "הוסף לרשימת השמעה",
"LabelAddToPlaylistBatch": "הוסף {0} פריטים לרשימת השמעה",
"LabelAddedAt": "נוסף בתאריך",
"LabelAddedAt": "נוסף ב-",
"LabelAddedDate": "נוסף ב-{0}",
"LabelAdminUsersOnly": "רק מנהלים",
"LabelAll": "הכל",
"LabelAllEpisodesDownloaded": "כל הפרקים הורדו",
"LabelAllUsers": "כל המשתמשים",
"LabelAllUsersExcludingGuests": "כל המשתמשים, ללא אורחים",
"LabelAllUsersIncludingGuests": "כל המשתמשים כולל אורחים",
@@ -230,10 +240,10 @@
"LabelAudioBitrate": "קצב סיביות (לדוגמא 128k)",
"LabelAudioChannels": "ערוצי קול (1 או 2)",
"LabelAudioCodec": "קידוד קול",
"LabelAuthor": "יוצר",
"LabelAuthorFirstLast": "יוצר (שם פרטי שם משפחה)",
"LabelAuthorLastFirst": "יוצר (שם משפחה, שם פרטי)",
"LabelAuthors": "יוצרים",
"LabelAuthor": "סופר",
"LabelAuthorFirstLast": "סופר (שם, משפחה)",
"LabelAuthorLastFirst": "סופר (משפחה, שם)",
"LabelAuthors": "סופרים",
"LabelAutoDownloadEpisodes": "הורד פרקים באופן אוטומטי",
"LabelAutoFetchMetadata": "חפש והורד מטא-נתונים באופן אוטומטי",
"LabelAutoFetchMetadataHelp": "מחפש ומוריד מטא-נתונים לשדות כותרת, יוצר וסדרה כדי לשפר את תהליך ההעלאה. ייתכן שיהיה צורך להתאים מטא-נתונים נוסף לאחר ההעלאה.",
@@ -242,36 +252,48 @@
"LabelAutoRegister": "הרשמה אוטומטית",
"LabelAutoRegisterDescription": "יצירת משתמשים חדשים אוטומטית לאחר התחברות",
"LabelBackToUser": "חזרה למשתמש",
"LabelBackupAudioFiles": "גיבוי קבצי שמע",
"LabelBackupLocation": "מיקום גיבוי",
"LabelBackupsEnableAutomaticBackups": "הפעל גיבויים אוטומטיים",
"LabelBackupsEnableAutomaticBackups": "גיבויים אוטומטיים",
"LabelBackupsEnableAutomaticBackupsHelp": "גיבויים שמורים ב /metadata/backups",
"LabelBackupsMaxBackupSize": "גודל הגיבוי המרבי (בג'יגה-בייט)",
"LabelBackupsMaxBackupSize": "גודל הגיבוי המרבי (בג'יגה-בייט) (0 - ללא הגבלה)",
"LabelBackupsMaxBackupSizeHelp": "כהגנה על עצמך מפני תצורה שגויה, הגיבויים ייכשלו אם הם יעברו את הגודל שהוגדר.",
"LabelBackupsNumberToKeep": "מספר הגיבויים לשמירה",
"LabelBackupsNumberToKeepHelp": "רק גיבוי אחד יוסר בכל פעם, לכן אם יש לך כבר יותר מגיבוי אחד יש להסיר אותם באופן ידני.",
"LabelBitrate": "קצב סיביות",
"LabelBonus": "בונוס",
"LabelBooks": "ספרים",
"LabelButtonText": "טקסט לחצן",
"LabelByAuthor": "על ידי {0}",
"LabelChangePassword": "שינוי סיסמה",
"LabelChannels": "ערוצים",
"LabelChapterCount": "{0} פרקים",
"LabelChapterTitle": "כותרת הפרק",
"LabelChapters": "פרקים",
"LabelChaptersFound": "פרקים שנמצאו",
"LabelClickForMoreInfo": "לחץ למידע נוסף",
"LabelClickToUseCurrentValue": "לחץ לשימוש בערך הנוכחי",
"LabelClosePlayer": "סגור נגן",
"LabelCollapseSeries": "צמצום סדרה",
"LabelCodec": "Coded",
"LabelCollapseSeries": "הסתר סדרה",
"LabelCollapseSubSeries": "הסתר תת סדרה",
"LabelCollection": "אוסף",
"LabelCollections": "אוספים",
"LabelComplete": "מלא",
"LabelComplete": "הושלם",
"LabelConfirmPassword": "אישור סיסמה",
"LabelContinueListening": "המשך האזנה",
"LabelContinueReading": "המשך קריאה",
"LabelContinueSeries": "המשך סדרה",
"LabelCover": "כריכה",
"LabelCoverImageURL": "כתובת התמונה ברשת",
"LabelCoverProvider": "ספק כריכה",
"LabelCreatedAt": "נוצר בתאריך",
"LabelCronExpression": "ביטוי cron",
"LabelCurrent": "נוכחי",
"LabelCurrently": "כעת:",
"LabelCustomCronExpression": "ביטוי cron מותאם אישית:",
"LabelDatetime": "Datetime",
"LabelDays": "ימים",
"LabelDeleteFromFileSystemCheckbox": "מחיקה מהמערכת הקבצים (הסר סימון למחיקה רק ממסד הנתונים)",
"LabelDescription": "תיאור",
"LabelDeselectAll": "הסר בחירת כל הפריטים",
@@ -282,51 +304,83 @@
"LabelDiscFromFilename": "דיסק משם הקובץ",
"LabelDiscFromMetadata": "דיסק מהמטא-נתונים",
"LabelDiscover": "גלה",
"LabelDownload": "הורד",
"LabelDownload": "הורדה",
"LabelDownloadNEpisodes": "הורד {0} פרקים",
"LabelDownloadable": "ניתן להורדה",
"LabelDuration": "משך",
"LabelDurationComparisonExactMatch": "(התאמה מדוייקת)",
"LabelDurationComparisonLonger": "({0} ארוך יותר)",
"LabelDurationComparisonShorter": "({0} קצר יותר)",
"LabelDurationFound": "משך נמצא:",
"LabelEbook": "ספר אלקטרוני",
"LabelEbooks": "ספרים אלקטרוניים",
"LabelEdit": "עריכה",
"LabelEmail": "דואר אלקטרוני",
"LabelEmailSettingsFromAddress": "מאת",
"LabelEmailSettingsRejectUnauthorized": "דחה תעודות לא מאושרות",
"LabelEmailSettingsRejectUnauthorizedHelp": "השבתת אימות תעודת SSL עלולה לחשוף את החיבור שלך לסיכוני אבטחה, כגון התקפות \"אדם באמצע\". השבת אפשרות זו רק אם אתה מבין את ההשלכות ובוטח בשרת הדואר שאליו אתה מתחבר.",
"LabelEmailSettingsSecure": "מאובטח",
"LabelEmailSettingsSecureHelp": "אם מופעל, החיבור ישתמש ב-TLS בעת ההתחברות לשרת. אם לא, אז TLS יהיה בשימוש אם השרת תומך בהרחבת STARTTLS. ברוב המקרים מומלץ להפעיל את הגדרה זו אם אתה מתחבר לפורט 465. לפורט 587 או 25, השאר כבוי. (from nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "כתובת לבדיקה",
"LabelEmbeddedCover": "כריכה מוטמעת",
"LabelEnable": "הפעל",
"LabelEnd": "סיום",
"LabelEnable": "אפשר",
"LabelEncodingBackupLocation": "גיבוי של קבצי אודיו מקוריים יישמר ב:",
"LabelEncodingChaptersNotEmbedded": "פרקים אינם מוטבעים בספרי אודיו מרובי רצועות.",
"LabelEncodingClearItemCache": "הקפד לנקות מטמון פריטים מעת לעת.",
"LabelEncodingFinishedM4B": "קובץ M4B סופי יישמר בתיקייה ה-audiobook ב:",
"LabelEncodingInfoEmbedded": "מטה דאטה יוטמע ברצועות השמע בתוך תיקיית ה-audiobook.",
"LabelEncodingStartedNavigation": "לאחר שהמשימה תתחיל אפשר לנווט לדף אחר.",
"LabelEncodingTimeWarning": "קידוד יכול להימשך עד 30 דקות.",
"LabelEncodingWarningAdvancedSettings": "אזהרה: אל תעדכן את ההגדרות האלה אלא אם כן אתה מכיר את אפשרויות קידוד ffmpeg.",
"LabelEncodingWatcherDisabled": "אם ה-watcher כבוי, יש לסרוק את הספר מחדש לאחר מכן.",
"LabelEnd": "סוף",
"LabelEndOfChapter": "סוף הפרק",
"LabelEpisode": "פרק",
"LabelEpisodeNotLinkedToRssFeed": "פרק לא מקושר לערוץ RSS",
"LabelEpisodeNumber": "פרק #{0}",
"LabelEpisodeTitle": "כותרת הפרק",
"LabelEpisodeType": "סוג הפרק",
"LabelEpisodeUrlFromRssFeed": "קישור פרק מערוץ RSS",
"LabelEpisodes": "פרקים",
"LabelEpisodic": "ארעי",
"LabelExample": "דוגמה",
"LabelExpandSeries": "הרחב סדרה",
"LabelExpandSubSeries": "הרחב תת סדרה",
"LabelExplicit": "בוטה",
"LabelExplicitChecked": "בוטה (מסומן)",
"LabelExplicitUnchecked": "לא בוטה (לא מסומן)",
"LabelExportOPML": "ייצוא OPML",
"LabelFeedURL": "כתובת ערוץ",
"LabelFetchingMetadata": "מושך מטא-נתונים",
"LabelFile": "קובץ",
"LabelFileBirthtime": "זמן יצירת הקובץ",
"LabelFileModified": "הקובץ שונה",
"LabelFilename": "שם הקובץ",
"LabelFileBornDate": "נוצר {0}",
"LabelFileModified": "קובץ נערך",
"LabelFileModifiedDate": "שונה {0}",
"LabelFilename": "שם קובץ",
"LabelFilterByUser": "סינון לפי משתמש",
"LabelFindEpisodes": "מצא פרקים",
"LabelFinished": "הושלם",
"LabelFolder": "תיקייה",
"LabelFolders": "תיקיות",
"LabelFontBold": "מודגש",
"LabelFontBoldness": "עובי פונט",
"LabelFontFamily": "משפחת הפונטים",
"LabelFontItalic": "נטוי",
"LabelFontScale": "קנה מידה של הפונט",
"LabelFontScale": "גודל פונט",
"LabelFontStrikethrough": "קו חוצה",
"LabelFormat": "תבנית",
"LabelGenre": "ז'אנר",
"LabelGenres": "ז'אנרים",
"LabelFull": "מלא",
"LabelGenre": "סגנון",
"LabelGenres": "סגנונות",
"LabelHardDeleteFile": "מחיקה חזקה של הקובץ",
"LabelHasEbook": "ספר אלקטרוני קיים",
"LabelHasSupplementaryEbook": "קיים ספר אלקטרוני נלווה",
"LabelHasEbook": "קיים ספר אלקטרוני",
"LabelHasSupplementaryEbook": "קיים ספר אלקטרוני משלים",
"LabelHideSubtitles": "הסתר תת כותרות",
"LabelHighestPriority": "העדיפות הגבוהה ביותר",
"LabelHost": "מארח",
"LabelHour": "שעה",
"LabelHours": "שעות",
"LabelIcon": "סמל",
"LabelImageURLFromTheWeb": "כתובת התמונה מהרשת",
"LabelInProgress": "בתהליך",
@@ -341,25 +395,30 @@
"LabelIntervalEvery6Hours": "כל 6 שעות",
"LabelIntervalEveryDay": "כל יום",
"LabelIntervalEveryHour": "כל שעה",
"LabelIntervalEveryMinute": "כל דקה",
"LabelInvert": "הפוך",
"LabelItem": "פריט",
"LabelJumpBackwardAmount": "כמות הרצה לאחור",
"LabelJumpForwardAmount": "כמות הרצה קדימה",
"LabelLanguage": "שפה",
"LabelLanguageDefaultServer": "שפת ברירת המחדל של השרת",
"LabelLanguages": "שפות",
"LabelLastBookAdded": "הספר האחרון שנוסף",
"LabelLastBookUpdated": "הספר האחרון שעודכן",
"LabelLastSeen": "נראה לאחרונה",
"LabelLastTime": "הזמן האחרון",
"LabelLastUpdate": "עדכון אחרון",
"LabelLayout": "פריסה",
"LabelLayoutSinglePage": "דף בודד",
"LabelLayout": "Layout",
"LabelLayoutSinglePage": "עמוד יחיד",
"LabelLayoutSplitPage": "פיצול הדף",
"LabelLess": "פחות",
"LabelLibrariesAccessibleToUser": "ספריות נגישות למשתמש",
"LabelLibrary": "ספרייה",
"LabelLibraryFilterSublistEmpty": "לא {0}",
"LabelLibraryItem": "פריט ספרייה",
"LabelLibraryName": "שם הספרייה",
"LabelLimit": "מגבלה",
"LabelLineSpacing": יווח שורות",
"LabelLineSpacing": "מרווח שורה",
"LabelListenAgain": "האזן שוב",
"LabelLogLevelDebug": "דיבוג",
"LabelLogLevelInfo": "מידע",
@@ -368,6 +427,10 @@
"LabelLowestPriority": "העדיפות הנמוכה ביותר",
"LabelMatchExistingUsersBy": "התאם משתמשים קיימים לפי",
"LabelMatchExistingUsersByDescription": "משמש לחיבור משתמשים קיימים. לאחר החיבור, המשתמשים יותאמו לפי זיהוי ייחודי מספק ה-SSO שלך",
"LabelMaxEpisodesToDownload": "מספר פרקים מקסימלי להורדה. 0 - ללא הגבלה.",
"LabelMaxEpisodesToDownloadPerCheck": "מספר פרקים חדשים מקסימלי להורדה בכל בדיקה",
"LabelMaxEpisodesToKeep": "מספר פרקים מקסימלי לשמור",
"LabelMaxEpisodesToKeepHelp": "ערך של 0 קובע ללא מגבלה. לאחר הורדה אוטומטית של פרק חדש יימחק את הפרק הישן ביותר אם יש לך יותר מ-X פרקים. פעולה זו תמחק רק פרק אחד לכל הורדה חדשה.",
"LabelMediaPlayer": "נגן מדיה",
"LabelMediaType": "סוג מדיה",
"LabelMetaTag": "תג מטא",
@@ -375,6 +438,7 @@
"LabelMetadataOrderOfPrecedenceDescription": "מקורות המטא-נתונים עם עדיפות גבוהה יחליפו מקורות עם עדיפות נמוכה יותר",
"LabelMetadataProvider": "ספק מטא-נתונים",
"LabelMinute": "דקה",
"LabelMinutes": "דקות",
"LabelMissing": "חסר",
"LabelMissingEbook": "אין ספר אלקטרוני",
"LabelMissingSupplementaryEbook": "אין ספר אלקטרוני נלווה",
@@ -387,10 +451,11 @@
"LabelNarrators": "מספרים",
"LabelNew": "חדש",
"LabelNewPassword": "סיסמה חדשה",
"LabelNewestAuthors": "הסופרים החדשים ביותר",
"LabelNewestAuthors": "הסופרים האחרונים",
"LabelNewestEpisodes": "הפרקים החדשים ביותר",
"LabelNextBackupDate": "תאריך הגיבוי הבא",
"LabelNextScheduledRun": "הרצה מתוזמנת הבאה",
"LabelNoCustomMetadataProviders": "אין ספקי מטא-נתונים מותאמים אישית",
"LabelNoEpisodesSelected": "לא נבחרו פרקים",
"LabelNotFinished": "לא הושלם",
"LabelNotStarted": "לא התחיל",
@@ -405,7 +470,9 @@
"LabelNotificationsMaxQueueSize": "גודל התור המרבי לאירועי התראה",
"LabelNotificationsMaxQueueSizeHelp": "האירועים מוגבלים לשליחה אחת לשנייה. האירועים יתעלמו אם התור מלא. הגדרה זו נועדה למנוע ספאם התראות.",
"LabelNumberOfBooks": "מספר הספרים",
"LabelNumberOfEpisodes": "מספר הפרקים",
"LabelNumberOfEpisodes": "# פרקים",
"LabelOpenIDAdvancedPermsClaimDescription": "שם OpenID claim המכילה הרשאות מתקדמות לפעולות משתמש בתוך האפליקציה, אשר יחולו על תפקידים שאינם מנהלי מערכת (<b>אם הוגדרה</b>). אם התביעה חסרה בתגובה, הגישה ל-ABS תידחה. אם אפשרות אחת חסרה, היא תטופל כ-<code>false</code> יש לוודא שטענת ספק הזהויות תואמת את המבנה הצפוי:",
"LabelOpenIDClaims": "השאר את האפשרויות הבאות ריקות כדי להשבית הקצאת קבוצות והרשאות מתקדמת, ולאחר מכן להקצות אוטומטית את קבוצת 'משתמש'.",
"LabelOpenRSSFeed": "פתח ערוץ RSS",
"LabelOverwrite": "לשכפל",
"LabelPassword": "סיסמה",
@@ -433,13 +500,15 @@
"LabelProvider": "ספק",
"LabelPubDate": "תאריך פרסום",
"LabelPublishYear": "שנת הפרסום",
"LabelPublishedDate": "פורסם {0}",
"LabelPublisher": "מוציא לאור",
"LabelRSSFeedCustomOwnerEmail": "אימייל בעלים מותאם אישית",
"LabelRSSFeedCustomOwnerName": "שם בעלים מותאם אישית",
"LabelRSSFeedOpen": "פתח ערוץ RSS",
"LabelRSSFeedOpen": "ערוץ RSS פתוח",
"LabelRSSFeedPreventIndexing": "מנע רישום",
"LabelRSSFeedSlug": "Slug של ערוץ ה-RSS",
"LabelRSSFeedURL": "כתובת ערוץ ה-RSS",
"LabelRandomly": "באופן אקראי",
"LabelRead": "קריאה",
"LabelReadAgain": "קרא שוב",
"LabelReadEbookWithoutProgress": "קרא/י ספר אלקטרוני ללא שמירת התקדמות",
@@ -465,7 +534,7 @@
"LabelSeriesProgress": "התקדמות בסדרה",
"LabelServerYearReview": "השנה בסקירה של השרת ({0})",
"LabelSetEbookAsPrimary": "קבע כראשי",
"LabelSetEbookAsSupplementary": "קבע כספר אלקטרוני נלווה",
"LabelSetEbookAsSupplementary": "קבע כמשלים",
"LabelSettingsAudiobooksOnly": "רק ספרי קול",
"LabelSettingsAudiobooksOnlyHelp": "הפעלת ההגדרה הזו תתעלם מקבצי ספרים אלקטרוניים אלא אם כן הם נמצאים בתיקיית ספרי קול, שבמקרה זה יקבעו כספרים אלקטרוניים נלווים",
"LabelSettingsBookshelfViewHelp": "עיצוב סקאומורפי עם מדפי עץ",
@@ -500,7 +569,7 @@
"LabelShowAll": "הצג הכל",
"LabelSize": "גודל",
"LabelSleepTimer": "טיימר שינה",
"LabelStart": "התחלה",
"LabelStart": "התחל",
"LabelStartTime": "זמן התחלה",
"LabelStarted": "התחיל",
"LabelStartedAt": "התחיל ב",
@@ -576,8 +645,8 @@
"LabelViewQueue": "הצג תור נגן",
"LabelVolume": "עוצמת קול",
"LabelWeekdaysToRun": "ימי השבוע להרצה",
"LabelYearReviewHide": "הסתר שנת סקירה",
"LabelYearReviewShow": "הצג שנת סקירה",
"LabelYearReviewHide": "הסתר סקירת שנה",
"LabelYearReviewShow": "הצג סקירת שנה",
"LabelYourAudiobookDuration": "משך הספר הקולי שלך",
"LabelYourBookmarks": "הסימניות שלך",
"LabelYourPlaylists": "הפלייליסטים שלך",
@@ -628,8 +697,8 @@
"MessageDownloadingEpisode": "מוריד פרק",
"MessageDragFilesIntoTrackOrder": "גרור קבצים לסדר ההשמעה נכון",
"MessageEmbedFinished": "ההטמעה הושלמה!",
"MessageEpisodesQueuedForDownload": "{0} פרקים בתור להורדה",
"MessageFeedURLWillBe": "כתובת URL של העדכון תהיה {0}",
"MessageEpisodesQueuedForDownload": "{0} פרק/ים בתור להורדה",
"MessageFeedURLWillBe": "כתובת ה- URL של הערוץ תהיה {0}",
"MessageFetching": "מושך...",
"MessageForceReScanDescription": "תבוצע סריקה מחדש כמו סריקה חדש מאפס, תגי ID3 של קבצי קול, קבצי OPF, וקבצי טקסט ייסרקו כחדשים.",
"MessageImportantNotice": "הודעה חשובה!",
@@ -644,7 +713,7 @@
"MessageMapChapterTitles": "מפה שמות פרקים לפרקי הספר השמורים שלך ללא שינוי תגי זמן",
"MessageMarkAllEpisodesFinished": "סמן את כל הפרקים כהסתיימו",
"MessageMarkAllEpisodesNotFinished": "סמן את כל הפרקים כלא הסתיימו",
"MessageMarkAsFinished": "סמן כהסתיים",
"MessageMarkAsFinished": "סמן כהושלם",
"MessageMarkAsNotFinished": "סמן כלא הסתיים",
"MessageMatchBooksDescription": "ינסה להתאים ספרים בספריית הספרים שלך עם ספר מספק החיפוש הנבחר וימלא פרטים ריקים ותמונות כריכה. לא יחליף פרטים קיימים.",
"MessageNoAudioTracks": "אין רצועות שמע",
@@ -674,7 +743,7 @@
"MessageNoSeries": "אין סדרות",
"MessageNoTags": "אין תגיות",
"MessageNoTasksRunning": "אין משימות פעילות",
"MessageNoUpdatesWereNecessary": "לא היה צורך בעדכונים",
"MessageNoUpdatesWereNecessary": "לא נדרש עדכון",
"MessageNoUserPlaylists": "אין לך רשימות השמעה",
"MessageNotYetImplemented": "עדיין לא מיושם",
"MessageOr": "או",
@@ -682,6 +751,7 @@
"MessagePlayChapter": "הקשב לתחילת הפרק",
"MessagePlaylistCreateFromCollection": "צור רשימת השמעה מאוסף",
"MessagePodcastHasNoRSSFeedForMatching": "לפודקאסט אין כתובת URL של ערוץ RSS להתאמה",
"MessagePodcastSearchField": "הזן מונח חיפוש או כתובת URL של ערוץ RSS",
"MessageQuickMatchDescription": "ממלא פרטים ריקים וכריכות עם התוצאה הראשונה מ '{0}'. לא ימחק פרטים אלא אם הגדרת השרת 'העדף מטה-נתונים מותאמים' מופעלת.",
"MessageRemoveChapter": "הסר פרק",
"MessageRemoveEpisodes": "הסר {0} פרקים",
@@ -708,7 +778,7 @@
"NoteChangeRootPassword": "המשתמש root הוא המשתמש היחיד שיכולה להיות לו סיסמה ריקה",
"NoteChapterEditorTimes": "הערה: זמן ההתחלה של הפרק הראשון חייב להישאר 0:00 וזמן ההתחלה של הפרק האחרון לא יכול לחרוג מהזמן של ספר השמע.",
"NoteFolderPicker": "הערה: תיקיות שכבר מופו לא יוצגו",
"NoteRSSFeedPodcastAppsHttps": "אזהרה: רוב יישומי הפודקאסט דורשים שכתובת ה-URL ערוץ ה-RSS תשתמש ב-HTTPS",
"NoteRSSFeedPodcastAppsHttps": "אזהרה: רוב אפליקציות הפודקאסטים ידרשו שכתובת האתר של ערוץ ה-RSS תשתמש ב-HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "אזהרה: פרק אחד או יותר לא מכילים תאריך פרסום. חלק מיישומי הפודקאסט דורשים זאת.",
"NoteUploaderFoldersWithMediaFiles": "תיקיות עם קבצי מדיה יעובדו כפריטי ספריה נפרדים.",
"NoteUploaderOnlyAudioFiles": "אם מועלים רק קבצי שמע, כל קובץ שמע יעובד כספר שמע נפרד.",
@@ -741,7 +811,7 @@
"ToastCollectionUpdateSuccess": "האוסף עודכן בהצלחה",
"ToastItemCoverUpdateSuccess": "כריכת הפריט עודכנה בהצלחה",
"ToastItemDetailsUpdateSuccess": "פרטי הפריט עודכנו בהצלחה",
"ToastItemMarkedAsFinishedFailed": "סימון כפריט כהושלם נכשל",
"ToastItemMarkedAsFinishedFailed": "סימון כפריט שהושלם נכשל",
"ToastItemMarkedAsFinishedSuccess": "הפריט סומן כהושלם בהצלחה",
"ToastItemMarkedAsNotFinishedFailed": "סימון כפריט שלא הושלם נכשל",
"ToastItemMarkedAsNotFinishedSuccess": "הפריט סומן כלא הושלם בהצלחה",

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Popis za izvođenje",
"HeaderPlaylistItems": "Stavke popisa za izvođenje",
"HeaderPodcastsToAdd": "Podcasti za dodavanje",
"HeaderPresets": "Predlošci postavki",
"HeaderPreviewCover": "Pretpregled naslovnice",
"HeaderRSSFeedGeneral": "RSS pojedinosti",
"HeaderRSSFeedIsOpen": "RSS izvor je otvoren",
@@ -530,6 +531,7 @@
"LabelReleaseDate": "Datum izlaska",
"LabelRemoveAllMetadataAbs": "Ukloni sve datoteke metadata.abs",
"LabelRemoveAllMetadataJson": "Ukloni sve datoteke metadata.json",
"LabelRemoveAudibleBranding": "Ukloni Audibleove najave i odjave iz poglavlja",
"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.",
@@ -604,6 +606,7 @@
"LabelSlug": "Slug",
"LabelSortAscending": "Uzlazno",
"LabelSortDescending": "Silazno",
"LabelSortPubDate": "Sortiranje po datumu objave",
"LabelStart": "Početak",
"LabelStartTime": "Vrijeme početka",
"LabelStarted": "Započeto",
@@ -704,6 +707,8 @@
"LabelYourProgress": "Vaš napredak",
"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>.",
"MessageAsinCheck": "Upišite ASIN iz odgovarajuće Audibleove regije, ne s Amazonov.",
"MessageAuthenticationOIDCChangesRestart": "Ponovno pokrenite poslužitelj da biste primijenili OIDC promjene.",
"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",
"MessageBackupsLocationNoEditNote": "Napomena: Lokacija za sigurnosne kopije zadana je kroz varijablu okoline i ovdje se ne može izmijeniti.",
@@ -722,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Netočno vrijeme početka, mora biti manje od trajanja zvučne knjige",
"MessageChapterErrorStartLtPrev": "Netočno vrijeme početka, mora biti veće ili jednako vremenu početka prethodnog poglavlja",
"MessageChapterStartIsAfter": "Početak poglavlja je nakon kraja zvučne knjige",
"MessageChaptersNotFound": "Poglavlja nisu pronađena",
"MessageCheckingCron": "Provjeravam cron...",
"MessageConfirmCloseFeed": "Sigurno želite zatvoriti ovaj izvor?",
"MessageConfirmDeleteBackup": "Sigurno želite izbrisati sigurnosnu kopiju za {0}?",
@@ -778,6 +784,7 @@
"MessageForceReScanDescription": "će ponovno skenirati sve datoteke kao nove datoteke. ID3 tagovi zvučnih datoteka, OPF datoteke i tekstualne datoteke skenirat će se kao da su nove.",
"MessageImportantNotice": "Važna obavijest!",
"MessageInsertChapterBelow": "Unesi poglavlje ispod",
"MessageInvalidAsin": "Nevažeći ASIN",
"MessageItemsSelected": "{0} odabranih stavki",
"MessageItemsUpdated": "{0} stavki ažurirano",
"MessageJoinUsOn": "Pridruži nam se na",
@@ -849,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Pokreni svaki {0} u {1}",
"MessageSearchResultsFor": "Rezultati pretrage za",
"MessageSelected": "{0} odabrano",
"MessageSeriesSequenceCannotContainSpaces": "Slijed serijala ne može sadržavati praznine",
"MessageServerCouldNotBeReached": "Nije moguće pristupiti poslužitelju",
"MessageSetChaptersFromTracksDescription": "Postavi poglavlja koristeći se zvučnom datotekom kao poglavljem i nazivom datoteke kao naslovom poglavlja",
"MessageShareExpirationWillBe": "Vrijeme isteka će biti <strong>{0}</strong>",
@@ -967,6 +975,8 @@
"ToastCachePurgeFailed": "Čišćenje predmemorije nije uspjelo",
"ToastCachePurgeSuccess": "Predmemorija uspješno očišćena",
"ToastChaptersHaveErrors": "Poglavlja imaju pogreške",
"ToastChaptersInvalidShiftAmountLast": "Neispravna vrijednost pomaka. Početak zadnjeg poglavlja bio bi nakon duljine trajanja ove zvučne knjige.",
"ToastChaptersInvalidShiftAmountStart": "Neispravna vrijednost pomaka. Trajanje prvog poglavlja bilo bi nula ili negativno i drugo poglavlje bi ga prepisalo. Povećajte vrijeme početka drugog poglavlja.",
"ToastChaptersMustHaveTitles": "Poglavlja moraju imati naslove",
"ToastChaptersRemoved": "Poglavlja uklonjena",
"ToastChaptersUpdated": "Poglavlja su ažurirana",
@@ -1086,6 +1096,8 @@
"ToastUnknownError": "Nepoznata pogreška",
"ToastUnlinkOpenIdFailed": "Uklanjanje OpenID veze korisnika nije uspjelo",
"ToastUnlinkOpenIdSuccess": "Korisnik odspojen od OpenID-ja",
"ToastUploaderFilepathExistsError": "Putanja \"{0}\" već postoji na poslužitelju",
"ToastUploaderItemExistsInSubdirectoryError": "Stavka \"{0}\" koristi se podmapom u putanje za učitavanje.",
"ToastUserDeleteFailed": "Brisanje korisnika nije uspjelo",
"ToastUserDeleteSuccess": "Korisnik izbrisan",
"ToastUserPasswordChangeSuccess": "Zaporka je uspješno promijenjena",

View File

@@ -10,6 +10,8 @@
"ButtonApplyChapters": "Fejezetek alkalmazása",
"ButtonAuthors": "Szerzők",
"ButtonBack": "Vissza",
"ButtonBatchEditPopulateFromExisting": "Létezőből feltöltés",
"ButtonBatchEditPopulateMapDetails": "",
"ButtonBrowseForFolder": "Mappa keresése",
"ButtonCancel": "Mégse",
"ButtonCancelEncode": "Kódolás megszakítása",
@@ -432,7 +434,7 @@
"LabelMetadataProvider": "Metaadat-szolgáltató",
"LabelMinute": "Perc",
"LabelMinutes": "Perc",
"LabelMissing": "Hiányzó",
"LabelMissing": "Hiányzik",
"LabelMissingEbook": "Nincs e-könyve",
"LabelMissingSupplementaryEbook": "Nincs kiegészítő e-könyve",
"LabelMobileRedirectURIs": "Engedélyezett mobil átirányítási URI-k",
@@ -604,7 +606,7 @@
"LabelStatsBestDay": "Legjobb nap",
"LabelStatsDailyAverage": "Napi átlag",
"LabelStatsDays": "Napok",
"LabelStatsDaysListened": "Napon hallgatva",
"LabelStatsDaysListened": "Hallgatással töltött napok",
"LabelStatsHours": "Órák",
"LabelStatsInARow": "egymás után",
"LabelStatsItemsFinished": "Befejezett elem",

View File

@@ -13,7 +13,7 @@
"ButtonBatchEditPopulateFromExisting": "Popola da esistente",
"ButtonBatchEditPopulateMapDetails": "Inserisci i dettagli della mappa",
"ButtonBrowseForFolder": "Per Cartella",
"ButtonCancel": "Cancella",
"ButtonCancel": "Annulla",
"ButtonCancelEncode": "Ferma la codifica",
"ButtonChangeRootPassword": "Cambia la Password di root",
"ButtonCheckAndDownloadNewEpisodes": "Controlla & scarica i nuovi episodi",
@@ -177,6 +177,7 @@
"HeaderPlaylist": "Playlist",
"HeaderPlaylistItems": "Elementi della playlist",
"HeaderPodcastsToAdd": "Podcasts da Aggiungere",
"HeaderPresets": "Presets",
"HeaderPreviewCover": "Anteprima Cover",
"HeaderRSSFeedGeneral": "Dettagli RSS",
"HeaderRSSFeedIsOpen": "RSS Feed è aperto",
@@ -229,6 +230,7 @@
"LabelAddedDate": "Aggiunti {0}",
"LabelAdminUsersOnly": "Solo utenti Amministratori",
"LabelAll": "Tutti",
"LabelAllEpisodesDownloaded": "Tutti gli Episodi Scaricati",
"LabelAllUsers": "Tutti gli Utenti",
"LabelAllUsersExcludingGuests": "Tutti gli Utenti Esclusi gli ospiti",
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
@@ -252,7 +254,7 @@
"LabelBackToUser": "Torna a Utenti",
"LabelBackupAudioFiles": "Backup file Audio",
"LabelBackupLocation": "Percorso del Backup",
"LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico",
"LabelBackupsEnableAutomaticBackups": "Backup Automatico",
"LabelBackupsEnableAutomaticBackupsHelp": "I Backup saranno salvati in /metadata/backups",
"LabelBackupsMaxBackupSize": "Dimensione massima backup (in GB) (0 Illimitato)",
"LabelBackupsMaxBackupSizeHelp": "Come protezione contro gli errori di config, i backup falliranno se superano la dimensione configurata.",
@@ -279,12 +281,12 @@
"LabelCollections": "Raccolte",
"LabelComplete": "Completo",
"LabelConfirmPassword": "Conferma Password",
"LabelContinueListening": "Continua ad Ascoltare",
"LabelContinueReading": "Continua la Lettura",
"LabelContinueListening": "Continua l'ascolto",
"LabelContinueReading": "Continua la lettura",
"LabelContinueSeries": "Continua serie",
"LabelCover": "Copertina",
"LabelCoverImageURL": "Indirizzo della cover URL",
"LabelCoverProvider": "Cover Provider",
"LabelCoverProvider": "Cover Sorgente",
"LabelCreatedAt": "Creato A",
"LabelCronExpression": "Espressione Cron",
"LabelCurrent": "Attuale",
@@ -529,6 +531,7 @@
"LabelReleaseDate": "Data Release",
"LabelRemoveAllMetadataAbs": "Remuovi tutti i metadata.abs files",
"LabelRemoveAllMetadataJson": "Rimuovi tutti i metadata.json files",
"LabelRemoveAudibleBranding": "Rimuovi l'intro e il termine Audible dai capitoli",
"LabelRemoveCover": "Rimuovi cover",
"LabelRemoveMetadataFile": "Rimuovi i file metadata nella cartella della libreria",
"LabelRemoveMetadataFileHelp": "Rimuovi tutti i file metadata.json e i file metadata.abs nelle tue {0} cartelle.",
@@ -558,6 +561,8 @@
"LabelSettingsBookshelfViewHelp": "Design con scaffali in legno",
"LabelSettingsChromecastSupport": "Supporto a Chromecast",
"LabelSettingsDateFormat": "Formato Data",
"LabelSettingsEnableWatcher": "Scansiona le librerie Automaticamente per trovare modifiche",
"LabelSettingsEnableWatcherForLibrary": "Scansiona la libreria Automaticamente per trovare modifiche",
"LabelSettingsEnableWatcherHelp": "Abilita l'aggiunta/aggiornamento automatico degli elementi quando vengono rilevate modifiche ai file. *Richiede il riavvio del Server",
"LabelSettingsEpubsAllowScriptedContent": "Consenti contenuti con script negli epub",
"LabelSettingsEpubsAllowScriptedContentHelp": "Consenti ai file epub di eseguire script. Si consiglia di mantenere questa impostazione disabilitata a meno che non si ritenga attendibile l'origine dei file epub.",
@@ -601,6 +606,7 @@
"LabelSlug": "Lento",
"LabelSortAscending": "Crescente",
"LabelSortDescending": "Discendente",
"LabelSortPubDate": "Ordina per data di pubblicazione",
"LabelStart": "Inizo",
"LabelStartTime": "Tempo di inizio",
"LabelStarted": "Iniziato",
@@ -672,7 +678,7 @@
"LabelUpdateDetailsHelp": "Consenti la sovrascrittura dei dettagli esistenti per i libri selezionati quando viene individuata una corrispondenza",
"LabelUpdatedAt": "Aggiornato alle",
"LabelUploaderDragAndDrop": "Drag & drop file o Cartelle",
"LabelUploaderDragAndDropFilesOnly": "Drag & drop files",
"LabelUploaderDragAndDropFilesOnly": "Drag & drop file",
"LabelUploaderDropFiles": "Elimina file",
"LabelUploaderItemFetchMetadataHelp": "Recupera automaticamente titolo, autore e serie",
"LabelUseAdvancedOptions": "Usa le opzioni avanzate",
@@ -701,6 +707,8 @@
"LabelYourProgress": "Completato al",
"MessageAddToPlayerQueue": "Aggiungi alla coda di riproduzione",
"MessageAppriseDescription": "Per utilizzare questa funzione è necessario disporre di un'istanza di <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> in esecuzione o un'API che gestirà quelle stesse richieste. <br />L'API Url dovrebbe essere il percorso URL completo per inviare la notifica, ad esempio se la tua istanza API è servita cosi .<code>http://192.168.1.1:8337</code> Allora dovrai mettere <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Assicurati di utilizzare l'ASIN della regione Audible corretta, non di Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Riavvia il tuo server dopo aver salvato per applicare le modifiche OIDC.",
"MessageBackupsDescription": "I backup includono utenti, progressi degli utenti, dettagli sugli elementi della libreria, impostazioni del server e immagini archiviate in <code>/metadata/items</code> & <code>/metadata/authors</code>. I backup non includono i file archiviati nelle cartelle della libreria.",
"MessageBackupsLocationEditNote": "Nota: l'aggiornamento della posizione di backup non sposterà o modificherà i backup esistenti",
"MessageBackupsLocationNoEditNote": "Nota: la posizione del backup viene impostata tramite una variabile di ambiente e non può essere modificata qui.",
@@ -719,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "L'ora di inizio non valida deve essere inferiore alla durata dell'audiolibro",
"MessageChapterErrorStartLtPrev": "L'ora di inizio non valida deve essere maggiore o uguale all'ora di inizio del capitolo precedente",
"MessageChapterStartIsAfter": "L'inizio del capitolo è dopo la fine del tuo audiolibro",
"MessageChaptersNotFound": "Capitoli non trovati",
"MessageCheckingCron": "Controllo cron...",
"MessageConfirmCloseFeed": "Sei sicuro di voler chiudere questo feed?",
"MessageConfirmDeleteBackup": "Sei sicuro di voler eliminare il backup {0}?",
@@ -775,8 +784,9 @@
"MessageForceReScanDescription": "eseguirà nuovamente la scansione di tutti i file come una nuova scansione. I tag ID3 dei file audio, i file OPF e i file di testo verranno scansionati come nuovi.",
"MessageImportantNotice": "Avviso Importante!",
"MessageInsertChapterBelow": "Inserisci capitolo sotto",
"MessageItemsSelected": "{0} oggetti Selezionati",
"MessageItemsUpdated": "{0} Oggetti aggiornati",
"MessageInvalidAsin": "ASIN non Valido",
"MessageItemsSelected": "{0} oggetti selezionati",
"MessageItemsUpdated": "{0} oggetti aggiornati",
"MessageJoinUsOn": "Unisciti a noi su",
"MessageLoading": "Caricamento…",
"MessageLoadingFolders": "Caricamento Cartelle...",
@@ -808,7 +818,7 @@
"MessageNoItems": "Nessun oggetto",
"MessageNoItemsFound": "Nessun oggetto trovato",
"MessageNoListeningSessions": "Nessuna sessione di ascolto",
"MessageNoLogs": "Nessun Logs",
"MessageNoLogs": "Nessun Log",
"MessageNoMediaProgress": "Nessun progresso multimediale",
"MessageNoNotifications": "Nessuna notifica",
"MessageNoPodcastFeed": "Podcast non valido: nessun feed",
@@ -843,8 +853,10 @@
"MessageRestoreBackupConfirm": "Sei sicuro di voler ripristinare il backup creato su",
"MessageRestoreBackupWarning": "Il ripristino di un backup sovrascriverà l'intero database situato in /config e sovrascrive le immagini in /metadata/items & /metadata/authors.<br /><br />I backup non modificano alcun file nelle cartelle della libreria. Se hai abilitato le impostazioni del server per archiviare copertine e metadati nelle cartelle della libreria, questi non vengono sottoposti a backup o sovrascritti.<br /><br />Tutti i client che utilizzano il tuo server verranno aggiornati automaticamente.",
"MessageScheduleLibraryScanNote": "Per la maggior parte degli utenti, si consiglia di lasciare questa funzionalità disabilitata e di mantenere abilitata l'impostazione di folder watcher. Il folder watcher rileverà automaticamente le modifiche nelle cartelle della libreria. Il folder watcher non funziona per ogni file system (come NFS), quindi è possibile utilizzare le scansioni pianificate della libreria.",
"MessageScheduleRunEveryWeekdayAtTime": "Esegui ogni {0} alle {1}",
"MessageSearchResultsFor": "cerca risultati per",
"MessageSelected": "{0} selezionati",
"MessageSeriesSequenceCannotContainSpaces": "La sequenza della serie non può contenere spazi",
"MessageServerCouldNotBeReached": "Impossibile raggiungere il server",
"MessageSetChaptersFromTracksDescription": "Impostare i capitoli utilizzando ciascun file audio come capitolo e il titolo del capitolo come nome del file audio",
"MessageShareExpirationWillBe": "Scadrà tra <strong>{0}</strong>",
@@ -950,6 +962,7 @@
"ToastBackupRestoreFailed": "Ripristino fallito",
"ToastBackupUploadFailed": "Caricamento backup fallito",
"ToastBackupUploadSuccess": "Backup caricato",
"ToastBatchApplyDetailsToItemsSuccess": "Dettagli applicati agli articoli",
"ToastBatchDeleteFailed": "Eliminazione batch non riuscita",
"ToastBatchDeleteSuccess": "Eliminazione batch riuscita",
"ToastBatchQuickMatchFailed": "Batch Quick Match non riuscito!",
@@ -962,6 +975,8 @@
"ToastCachePurgeFailed": "Impossibile eliminare la cache",
"ToastCachePurgeSuccess": "Cache eliminata correttamente",
"ToastChaptersHaveErrors": "I capitoli contengono errori",
"ToastChaptersInvalidShiftAmountLast": "Quantità di spostamento non valida. L'orario di inizio dell'ultimo capitolo si estenderebbe oltre la durata di questo audiolibro.",
"ToastChaptersInvalidShiftAmountStart": "Quantità di spostamento non valida. Il primo capitolo avrebbe una lunghezza pari a zero o negativa e verrebbe sovrascritto dal secondo capitolo. Aumentare la durata iniziale del secondo capitolo.",
"ToastChaptersMustHaveTitles": "I capitoli devono avere titoli",
"ToastChaptersRemoved": "Capitoli rimossi",
"ToastChaptersUpdated": "Capitoli aggiornati",
@@ -1062,6 +1077,7 @@
"ToastSelectAtLeastOneUser": "Seleziona almeno un utente",
"ToastSendEbookToDeviceFailed": "Impossibile inviare il libro al dispositivo",
"ToastSendEbookToDeviceSuccess": "Libro inviato al dispositivo «{0}»",
"ToastSeriesSubmitFailedSameName": "Non è possibile aggiungere due serie con lo stesso nome",
"ToastSeriesUpdateFailed": "Aggiornamento Serie Fallito",
"ToastSeriesUpdateSuccess": "Serie Aggiornate",
"ToastServerSettingsUpdateSuccess": "Impostazioni del server aggiornate",
@@ -1080,6 +1096,8 @@
"ToastUnknownError": "Errore sconosciuto",
"ToastUnlinkOpenIdFailed": "Impossibile scollegare l'utente da OpenID",
"ToastUnlinkOpenIdSuccess": "Utente scollegato da OpenID",
"ToastUploaderFilepathExistsError": "Il percorso file \"{0}\" esiste già sul server",
"ToastUploaderItemExistsInSubdirectoryError": "L'elemento \"{0}\" utilizza una sottodirectory del percorso di caricamento.",
"ToastUserDeleteFailed": "Errore eliminazione utente",
"ToastUserDeleteSuccess": "Utente eliminato",
"ToastUserPasswordChangeSuccess": "Password modificata con successo",

View File

@@ -10,6 +10,7 @@
"ButtonApplyChapters": "Hoofdstukken toepassen",
"ButtonAuthors": "Auteurs",
"ButtonBack": "Terug",
"ButtonBatchEditPopulateFromExisting": "Vullen vanuit bestaande",
"ButtonBatchEditPopulateMapDetails": "Kaartgegevens invullen",
"ButtonBrowseForFolder": "Bladeren naar map",
"ButtonCancel": "Annuleren",
@@ -52,7 +53,7 @@
"ButtonNext": "Volgende",
"ButtonNextChapter": "Volgend hoofdstuk",
"ButtonNextItemInQueue": "Volgend Item in Wachtrij",
"ButtonOk": "Ok",
"ButtonOk": "Akkoord",
"ButtonOpenFeed": "Feed openen",
"ButtonOpenManager": "Manager openen",
"ButtonPause": "Pauze",
@@ -218,6 +219,7 @@
"LabelAccountTypeAdmin": "Beheerder",
"LabelAccountTypeGuest": "Gast",
"LabelAccountTypeUser": "Gebruiker",
"LabelActivities": "Activiteiten",
"LabelActivity": "Activiteit",
"LabelAddToCollection": "Toevoegen aan collectie",
"LabelAddToCollectionBatch": "{0} boeken toevoegen aan collectie",
@@ -227,6 +229,7 @@
"LabelAddedDate": "Toegevoegd {0}",
"LabelAdminUsersOnly": "Enkel Admin gebruikers",
"LabelAll": "Alle",
"LabelAllEpisodesDownloaded": "Alle afleveringen gedownload",
"LabelAllUsers": "Alle gebruikers",
"LabelAllUsersExcludingGuests": "Alle gebruikers exclusief gasten",
"LabelAllUsersIncludingGuests": "Alle gebruikers inclusief gasten",
@@ -282,6 +285,7 @@
"LabelContinueSeries": "Doorgaan met Serie",
"LabelCover": "Omslag",
"LabelCoverImageURL": "Coverafbeelding URL",
"LabelCoverProvider": "Omslag bron",
"LabelCreatedAt": "Gecreëerd op",
"LabelCronExpression": "Cron-uitdrukking",
"LabelCurrent": "Huidig",
@@ -433,7 +437,7 @@
"LabelMetadataProvider": "Metadatabron",
"LabelMinute": "Minuut",
"LabelMinutes": "Minuten",
"LabelMissing": "Ontbrekend",
"LabelMissing": "Missende",
"LabelMissingEbook": "Heeft geen ebook",
"LabelMissingSupplementaryEbook": "Heeft geen supplementair ebook",
"LabelMobileRedirectURIs": "Toegestane mobiele omleidings-URL's",
@@ -464,7 +468,7 @@
"LabelNotificationsMaxQueueSize": "Max rijgrootte voor notificatie gebeurtenissen",
"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",
"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.",

View File

@@ -17,7 +17,7 @@
"ButtonCheckAndDownloadNewEpisodes": "Sjekk og last ned nye episoder",
"ButtonChooseAFolder": "Velg mappe",
"ButtonChooseFiles": "Velg filer",
"ButtonClearFilter": "Bytt filter",
"ButtonClearFilter": "Fjern filter",
"ButtonCloseFeed": "Lukk Feed",
"ButtonCloseSession": "Lukk åpen økt",
"ButtonCollections": "Samlinger",

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Playlista",
"HeaderPlaylistItems": "Pozycje listy odtwarzania",
"HeaderPodcastsToAdd": "Podcasty do dodania",
"HeaderPresets": "Ustawienia wstępne",
"HeaderPreviewCover": "Podgląd okładki",
"HeaderRSSFeedGeneral": "Szczegóły RSS",
"HeaderRSSFeedIsOpen": "Kanał RSS jest otwarty",
@@ -219,6 +220,7 @@
"LabelAccountTypeAdmin": "Administrator",
"LabelAccountTypeGuest": "Gość",
"LabelAccountTypeUser": "Użytkownik",
"LabelActivities": "Aktywności",
"LabelActivity": "Aktywność",
"LabelAddToCollection": "Dodaj do kolekcji",
"LabelAddToCollectionBatch": "Dodaj {0} książki do kolekcji",
@@ -228,6 +230,7 @@
"LabelAddedDate": "Dodano {0}",
"LabelAdminUsersOnly": "Tylko użytkownicy administracyjni",
"LabelAll": "Wszystkie",
"LabelAllEpisodesDownloaded": "Wszystkie odcinki pobrane",
"LabelAllUsers": "Wszyscy użytkownicy",
"LabelAllUsersExcludingGuests": "Wszyscy użytkownicy z wyłączeniem gości",
"LabelAllUsersIncludingGuests": "Wszyscy użytkownicy, łącznie z gośćmi",
@@ -245,6 +248,7 @@
"LabelAutoFetchMetadata": "Automatycznie pobierz metadane",
"LabelAutoFetchMetadataHelp": "Pobiera metadane dotyczące tytułu, autora i serii, aby usprawnić przesyłanie. Po przesłaniu może być konieczne dopasowanie dodatkowych metadanych.",
"LabelAutoLaunch": "Uruchom automatycznie",
"LabelAutoLaunchDescription": "Automatyczne przekierowanie do dostawcy uwierzytelniania podczas przechodzenia na stronę logowania (ręczna zamiana ścieżki <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Automatyczna rejestracja",
"LabelAutoRegisterDescription": "Automatycznie utwórz nowych użytkowników po zalogowaniu",
"LabelBackToUser": "Powrót",
@@ -282,6 +286,7 @@
"LabelContinueSeries": "Kontynuuj serię",
"LabelCover": "Okładka",
"LabelCoverImageURL": "URL okładki",
"LabelCoverProvider": "Dostawca okładki",
"LabelCreatedAt": "Utworzone",
"LabelCronExpression": "Wyrażenie CRON",
"LabelCurrent": "Aktualny",

View File

@@ -10,6 +10,8 @@
"ButtonApplyChapters": "Aplicar Capítulos",
"ButtonAuthors": "Autores",
"ButtonBack": "Voltar",
"ButtonBatchEditPopulateFromExisting": "Popular de um existente",
"ButtonBatchEditPopulateMapDetails": "Popular mapeamento de detalhes",
"ButtonBrowseForFolder": "Procurar por Pasta",
"ButtonCancel": "Cancelar",
"ButtonCancelEncode": "Cancelar Codificação",
@@ -19,6 +21,7 @@
"ButtonChooseFiles": "Escolha arquivos",
"ButtonClearFilter": "Limpar Filtro",
"ButtonCloseFeed": "Fechar Feed",
"ButtonCloseSession": "Fechar Sessão Aberta",
"ButtonCollections": "Coleções",
"ButtonConfigureScanner": "Configurar Verificador",
"ButtonCreate": "Criar",
@@ -28,6 +31,9 @@
"ButtonEdit": "Editar",
"ButtonEditChapters": "Editar Capítulos",
"ButtonEditPodcast": "Editar Podcast",
"ButtonEnable": "Ativar",
"ButtonFireAndFail": "Disparar e Falhar",
"ButtonFireOnTest": "Disparar evento onTest",
"ButtonForceReScan": "Forcar Nova Verificação",
"ButtonFullPath": "Caminho Completo",
"ButtonHide": "Ocultar",
@@ -37,6 +43,7 @@
"ButtonJumpForward": "Adiantar",
"ButtonLatest": "Mais Recentes",
"ButtonLibrary": "Biblioteca",
"ButtonLogout": "Logout",
"ButtonLookup": "Procurar",
"ButtonManageTracks": "Gerenciar Faixas",
"ButtonMapChapterTitles": "Designar Títulos de Capítulos",
@@ -45,18 +52,24 @@
"ButtonNevermind": "Cancelar",
"ButtonNext": "Próximo",
"ButtonNextChapter": "Próximo Capítulo",
"ButtonNextItemInQueue": "Próximo Item da Fila",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Abrir Feed",
"ButtonOpenManager": "Abrir Gerenciador",
"ButtonPause": "Pausar",
"ButtonPlay": "Reproduzir",
"ButtonPlayAll": "Reproduzir Tudo",
"ButtonPlaying": "Reproduzindo",
"ButtonPlaylists": "Lista de Reprodução",
"ButtonPrevious": "Anterior",
"ButtonPreviousChapter": "Capítulo Anterior",
"ButtonProbeAudioFile": "Sondar Arquivo de Áudio",
"ButtonPurgeAllCache": "Apagar Todo o Cache",
"ButtonPurgeItemsCache": "Apagar o Cache de Itens",
"ButtonQueueAddItem": "Adicionar à Lista",
"ButtonQueueRemoveItem": "Remover da Lista",
"ButtonQuickEmbed": "Incorporação Rápida",
"ButtonQuickEmbedMetadata": "Incorporação Rápida de Metadata",
"ButtonQuickMatch": "Consulta rápida",
"ButtonReScan": "Nova Verificação",
"ButtonRead": "Ler",
@@ -77,6 +90,8 @@
"ButtonSaveTracklist": "Salvar Lista de Faixas",
"ButtonScan": "Verificar",
"ButtonScanLibrary": "Verificar Biblioteca",
"ButtonScrollLeft": "Arrastar para Esquerda",
"ButtonScrollRight": "Arrastar para Direita",
"ButtonSearch": "Pesquisar",
"ButtonSelectFolderPath": "Selecionar Caminho da Pasta",
"ButtonSeries": "Séries",
@@ -86,8 +101,11 @@
"ButtonShow": "Exibir",
"ButtonStartM4BEncode": "Iniciar Codificação M4B",
"ButtonStartMetadataEmbed": "Iniciar Inclusão de Metadados",
"ButtonStats": "Estatísticas",
"ButtonSubmit": "Enviar",
"ButtonTest": "Testar",
"ButtonUnlinkOpenId": "Desvincular OpenID",
"ButtonUpload": "Fazer Upload",
"ButtonUploadBackup": "Upload de Backup",
"ButtonUploadCover": "Upload de Capa",
"ButtonUploadOPMLFile": "Upload Arquivo OPML",
@@ -99,6 +117,7 @@
"ErrorUploadFetchMetadataNoResults": "Não foi possível buscar metadados - tente atualizar o título e/ou autor",
"ErrorUploadLacksTitle": "É preciso ter um título",
"HeaderAccount": "Conta",
"HeaderAddCustomMetadataProvider": "Adicionar Provedor de Metadados Personalizado",
"HeaderAdvanced": "Avançado",
"HeaderAppriseNotificationSettings": "Configuração de notificações Apprise",
"HeaderAudioTracks": "Trilhas de áudio",
@@ -196,6 +215,7 @@
"LabelAddToPlaylist": "Adicionar à Lista de Reprodução",
"LabelAddToPlaylistBatch": "Adicionar {0} itens à Lista de Reprodução",
"LabelAddedAt": "Acrescentado em",
"LabelAddedDate": "Adicionado {0}",
"LabelAdminUsersOnly": "Apenas usuários administradores",
"LabelAll": "Todos",
"LabelAllUsers": "Todos Usuários",

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Плейлист",
"HeaderPlaylistItems": "Элементы списка воспроизведения",
"HeaderPodcastsToAdd": "Подкасты для добавления",
"HeaderPresets": "Пресеты",
"HeaderPreviewCover": "Предпросмотр обложки",
"HeaderRSSFeedGeneral": "Сведения о RSS",
"HeaderRSSFeedIsOpen": "RSS-канал открыт",
@@ -211,15 +212,15 @@
"HeaderUsers": "Пользователи",
"HeaderYearReview": "Итоги {0} года",
"HeaderYourStats": "Ваша статистика",
"LabelAbridged": "Сокращенное издание",
"LabelAbridged": "Сокращенная форма",
"LabelAbridgedChecked": "Сокращено (отмечено)",
"LabelAbridgedUnchecked": "Без сокращений (не отмечено)",
"LabelAbridgedUnchecked": "Полное издание (не отмечено)",
"LabelAccessibleBy": "Доступ",
"LabelAccountType": "Тип учетной записи",
"LabelAccountTypeAdmin": "Администратор",
"LabelAccountTypeGuest": "Гость",
"LabelAccountTypeUser": "Пользователь",
"LabelActivities": "Мероприятия",
"LabelActivities": "События",
"LabelActivity": "Активность",
"LabelAddToCollection": "Добавить в коллекцию",
"LabelAddToCollectionBatch": "Добавить {0} книг в коллекцию",
@@ -229,6 +230,7 @@
"LabelAddedDate": "Добавлено {0}",
"LabelAdminUsersOnly": "Только для пользователей с правами администратора",
"LabelAll": "Все",
"LabelAllEpisodesDownloaded": "Все эпизоды загружены",
"LabelAllUsers": "Все пользователи",
"LabelAllUsersExcludingGuests": "Все пользователи, кроме гостей",
"LabelAllUsersIncludingGuests": "Все пользователи, включая гостей",
@@ -305,7 +307,7 @@
"LabelDownload": "Скачать",
"LabelDownloadNEpisodes": "Скачать {0} эпизодов",
"LabelDownloadable": "Загружаемый",
"LabelDuration": "Продолжительность",
"LabelDuration": "Длительность",
"LabelDurationComparisonExactMatch": "(точное совпадение)",
"LabelDurationComparisonLonger": "({0} дольше)",
"LabelDurationComparisonShorter": "({0} короче)",
@@ -344,8 +346,8 @@
"LabelExample": "Пример",
"LabelExpandSeries": "Развернуть серию",
"LabelExpandSubSeries": "Развернуть подсерию",
"LabelExplicit": "Явный",
"LabelExplicitChecked": "Явный (отмечено)",
"LabelExplicit": "18+",
"LabelExplicitChecked": "18+ (отмечено)",
"LabelExplicitUnchecked": "Не явно (не отмечено)",
"LabelExportOPML": "Экспорт OPML",
"LabelFeedURL": "URL канала",
@@ -529,6 +531,7 @@
"LabelReleaseDate": "Дата выхода",
"LabelRemoveAllMetadataAbs": "Удалите все файлы metadata.abs",
"LabelRemoveAllMetadataJson": "Удалите все файлы metadata.json",
"LabelRemoveAudibleBranding": "Удалить вступление и концовку Audible из глав",
"LabelRemoveCover": "Удалить обложку",
"LabelRemoveMetadataFile": "Удаление файлов метаданных в папках элементов библиотеки",
"LabelRemoveMetadataFileHelp": "Удалите все файлы metadata.json и metadata.abs из ваших папок {0}.",
@@ -603,6 +606,7 @@
"LabelSlug": "Слизень",
"LabelSortAscending": "По возрастанию",
"LabelSortDescending": "По убыванию",
"LabelSortPubDate": "Отсортировать по дате публикации",
"LabelStart": "Начало",
"LabelStartTime": "Время начала",
"LabelStarted": "Начат",
@@ -703,6 +707,8 @@
"LabelYourProgress": "Ваш прогресс",
"MessageAddToPlayerQueue": "Добавить в очередь проигрывателя",
"MessageAppriseDescription": "Для использования этой функции необходимо иметь запущенный экземпляр <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> или api которое обрабатывает те же самые запросы. <br />URL-адрес API Apprise должен быть полным URL-адресом для отправки уведомления, т.е., если API запущено по адресу <code>http://192.168.1.1:8337</code> тогда нужно указать <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Убедитесь, что вы используете ASIN из правильной региональной зоны Audible, а не из Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Перезапустите ваш сервер после сохранения для применения изменений в OIDC.",
"MessageBackupsDescription": "Бэкап включает пользователей, прогресс пользователей, данные элементов библиотеки, настройки сервера и изображения хранящиеся в <code>/metadata/items</code> и <code>/metadata/authors</code>. Бэкапы <strong>НЕ</strong> сохраняют файлы из папок библиотек.",
"MessageBackupsLocationEditNote": "Примечание: Обновление местоположения резервной копии не приведет к перемещению или изменению существующих резервных копий",
"MessageBackupsLocationNoEditNote": "Примечание: Местоположение резервного копирования задается с помощью переменной среды и не может быть изменено здесь.",
@@ -721,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Неверное время начала, должно быть меньше продолжительности аудиокниги",
"MessageChapterErrorStartLtPrev": "Неверное время начала, должно быть больше или равно времени начала предыдущей главы",
"MessageChapterStartIsAfter": "Глава начинается после окончания аудиокниги",
"MessageChaptersNotFound": "Главы не найденны",
"MessageCheckingCron": "Проверка cron...",
"MessageConfirmCloseFeed": "Вы уверены, что хотите закрыть этот канал?",
"MessageConfirmDeleteBackup": "Вы уверены, что хотите удалить бэкап для {0}?",
@@ -777,8 +784,9 @@
"MessageForceReScanDescription": "будет сканировать все файлы снова, как свежее сканирование. Теги ID3 аудиофайлов, OPF-файлы и текстовые файлы будут сканироваться как новые.",
"MessageImportantNotice": "Важное замечание!",
"MessageInsertChapterBelow": "Вставить главу ниже",
"MessageItemsSelected": "{0} Элементов выделено",
"MessageItemsUpdated": "{0} Элементов обновлено",
"MessageInvalidAsin": "Неправильный ASIN",
"MessageItemsSelected": "{0} элементов выделено",
"MessageItemsUpdated": "{0} элементов обновлено",
"MessageJoinUsOn": "Присоединяйтесь к нам в",
"MessageLoading": "Загрузка...",
"MessageLoadingFolders": "Загрузка каталогов...",
@@ -810,7 +818,7 @@
"MessageNoItems": "Нет элементов",
"MessageNoItemsFound": "Элементы не найдены",
"MessageNoListeningSessions": "Нет сеансов прослушивания",
"MessageNoLogs": "Нет логов",
"MessageNoLogs": "Нет записей",
"MessageNoMediaProgress": "Нет прогресса медиа",
"MessageNoNotifications": "Нет уведомлений",
"MessageNoPodcastFeed": "Недопустимый подкаст: Нет канала",
@@ -848,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Запуск каждые {0} по {1}",
"MessageSearchResultsFor": "Результаты поиска для",
"MessageSelected": "{0} выбрано",
"MessageSeriesSequenceCannotContainSpaces": "Последовательность серии должна быть без пропусков",
"MessageServerCouldNotBeReached": "Не удалось связаться с сервером",
"MessageSetChaptersFromTracksDescription": "Установка глав с использованием каждого аудиофайла в качестве главы и заголовка главы в качестве имени аудиофайла",
"MessageShareExpirationWillBe": "Срок действия истекает <strong>{0}</strong>",
@@ -953,6 +962,7 @@
"ToastBackupRestoreFailed": "Не удалось восстановить из бэкапа",
"ToastBackupUploadFailed": "Не удалось загрузить бэкап",
"ToastBackupUploadSuccess": "Бэкап загружен",
"ToastBatchApplyDetailsToItemsSuccess": "Подробности, применяемые к элементам",
"ToastBatchDeleteFailed": "Не удалось выполнить пакетное удаление",
"ToastBatchDeleteSuccess": "Успешное пакетное удаление",
"ToastBatchQuickMatchFailed": "Не удалось выполнить пакетное быстрое сопоставление!",
@@ -965,6 +975,8 @@
"ToastCachePurgeFailed": "Не удалось очистить кэш",
"ToastCachePurgeSuccess": "Кэш успешно очищен",
"ToastChaptersHaveErrors": "Главы имеют ошибки",
"ToastChaptersInvalidShiftAmountLast": "Некорректное значение сдвига. Начало последней главы будет превышать продолжительность этой аудиокниги.",
"ToastChaptersInvalidShiftAmountStart": "Некорректное значение сдвига. Первая глава будет иметь нулевую или отрицательную длину и будет перезаписана второй главой. Увеличьте начальную продолжительность второй главы.",
"ToastChaptersMustHaveTitles": "Главы должны содержать названия",
"ToastChaptersRemoved": "Удалены главы",
"ToastChaptersUpdated": "Обновленные главы",
@@ -1065,6 +1077,7 @@
"ToastSelectAtLeastOneUser": "Выберите хотя бы одного пользователя",
"ToastSendEbookToDeviceFailed": "Не удалось отправить e-книгу на устройство",
"ToastSendEbookToDeviceSuccess": "E-книга отправлена на устройство \"{0}\"",
"ToastSeriesSubmitFailedSameName": "Невозможно добавить две серии с одинаковым названием",
"ToastSeriesUpdateFailed": "Не удалось обновить серию",
"ToastSeriesUpdateSuccess": "Успешное обновление серии",
"ToastServerSettingsUpdateSuccess": "Обновлены настройки сервера",
@@ -1083,6 +1096,8 @@
"ToastUnknownError": "Неизвестная ошибка",
"ToastUnlinkOpenIdFailed": "Не удалось отвязать пользователя от OpenID",
"ToastUnlinkOpenIdSuccess": "Пользователь отвязан от OpenID",
"ToastUploaderFilepathExistsError": "Путь к файлу \"{0}\" уже существует на сервере",
"ToastUploaderItemExistsInSubdirectoryError": "Элемент «{0}» использует подкаталог пути загрузки.",
"ToastUserDeleteFailed": "Не удалось удалить пользователя",
"ToastUserDeleteSuccess": "Пользователь удален",
"ToastUserPasswordChangeSuccess": "Пароль успешно изменен",

View File

File diff suppressed because it is too large Load Diff

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Seznam predvajanja",
"HeaderPlaylistItems": "Elementi seznama predvajanja",
"HeaderPodcastsToAdd": "Podcasti za dodajanje",
"HeaderPresets": "Prednastavitve",
"HeaderPreviewCover": "Naslovnica za predogled",
"HeaderRSSFeedGeneral": "RSS podrobnosti",
"HeaderRSSFeedIsOpen": "Vir RSS je odprt",
@@ -530,6 +531,7 @@
"LabelReleaseDate": "Datum izdaje",
"LabelRemoveAllMetadataAbs": "Odstrani vse datoteke metadata.abs",
"LabelRemoveAllMetadataJson": "Odstrani vse datoteke metadata.json",
"LabelRemoveAudibleBranding": "Odstrani Audible uvod in zaključek iz poglavij",
"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}.",
@@ -604,6 +606,7 @@
"LabelSlug": "Slug",
"LabelSortAscending": "Naraščajoče",
"LabelSortDescending": "Padajoče",
"LabelSortPubDate": "Razvrsti po datumu objave",
"LabelStart": "Začetek",
"LabelStartTime": "Čas začetka",
"LabelStarted": "Začeto",
@@ -704,6 +707,8 @@
"LabelYourProgress": "Tvoj napredek",
"MessageAddToPlayerQueue": "Dodaj v čakalno vrsto predvajalnika",
"MessageAppriseDescription": "Če želite uporabljati to funkcijo, morate imeti zagnano namestitev <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">API Apprise</a> ali API, ki bo obravnavala te iste zahteve. <br />Url API-ja Apprise mora biti celotna pot URL-ja za pošiljanje obvestila, npr. če je vaša namestitev API-ja postrežena na <code>http://192.168.1.1:8337</code>, bi morali vnesti <code >http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Prepričajte se, da uporabljate ASIN iz pravilne zvočne regije, ne iz Amazona.",
"MessageAuthenticationOIDCChangesRestart": "Za uveljavitev OIDC sprememb, po shranjevanju znova zaženite strežnik.",
"MessageBackupsDescription": "Varnostne kopije vključujejo uporabnike, napredek uporabnikov, podrobnosti elementov knjižnice, nastavitve strežnika in slike, shranjene v <code>/metadata/items</code> & <code>/metadata/authors</code>. Varnostne kopije <strong>ne</strong> vključujejo datotek, shranjenih v mapah vaše knjižnice.",
"MessageBackupsLocationEditNote": "Opomba: Posodabljanje lokacije varnostne kopije ne bo premaknilo ali spremenilo obstoječih varnostnih kopij",
"MessageBackupsLocationNoEditNote": "Opomba: Lokacija varnostne kopije je nastavljena s spremenljivko okolja in je tu ni mogoče spremeniti.",
@@ -722,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Neveljaven začetni čas, mora biti krajši od trajanja zvočne knjige",
"MessageChapterErrorStartLtPrev": "Neveljaven začetni čas mora biti večji od ali enak začetnemu času prejšnjega poglavja",
"MessageChapterStartIsAfter": "Začetek poglavja je po koncu vaše zvočne knjige",
"MessageChaptersNotFound": "Poglavij ni bilo najdenih",
"MessageCheckingCron": "Preverjam cron...",
"MessageConfirmCloseFeed": "Ali ste prepričani, da želite zapreti ta vir?",
"MessageConfirmDeleteBackup": "Ali ste prepričani, da želite izbrisati varnostno kopijo za {0}?",
@@ -778,6 +784,7 @@
"MessageForceReScanDescription": "bo znova pregledal vse datoteke kot pregled od začetka. Oznake ID3 zvočnih datotek, datoteke OPF in besedilne datoteke bodo pregledane kot nove.",
"MessageImportantNotice": "Pomembno obvestilo!",
"MessageInsertChapterBelow": "Spodaj vstavite poglavje",
"MessageInvalidAsin": "Neveljaven ASIN",
"MessageItemsSelected": "{0} izbranih elementov",
"MessageItemsUpdated": "Št. posodobljenih elementov: {0}",
"MessageJoinUsOn": "Pridružite se nam",
@@ -849,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Zaženi vsakih {0} ob {1}",
"MessageSearchResultsFor": "Rezultati iskanja za",
"MessageSelected": "{0} izbrano",
"MessageSeriesSequenceCannotContainSpaces": "Zaporedje serij ne sme vsebovati presledkov",
"MessageServerCouldNotBeReached": "Strežnika ni bilo mogoče doseči",
"MessageSetChaptersFromTracksDescription": "Nastavi poglavja z uporabo vsake zvočne datoteke kot poglavja in naslova poglavja kot imena zvočne datoteke",
"MessageShareExpirationWillBe": "Potečeno bo <strong>{0}</strong>",
@@ -967,6 +975,8 @@
"ToastCachePurgeFailed": "Čiščenje predpomnilnika ni uspelo",
"ToastCachePurgeSuccess": "Predpomnilnik je bil uspešno očiščen",
"ToastChaptersHaveErrors": "Poglavja imajo napake",
"ToastChaptersInvalidShiftAmountLast": "Neveljavna vrednost zamika. Začetni čas zadnjega poglavja bi presegel trajanje te zvočne knjige.",
"ToastChaptersInvalidShiftAmountStart": "Neveljavna vrednost zamika. Prvo poglavje bi imelo ničelno ali negativno dolžino in bi ga prepisalo drugo poglavje. Povečajte začetno trajanje drugega poglavja.",
"ToastChaptersMustHaveTitles": "Poglavja morajo imeti naslove",
"ToastChaptersRemoved": "Poglavja so odstranjena",
"ToastChaptersUpdated": "Poglavja so posodobljena",
@@ -1086,6 +1096,8 @@
"ToastUnknownError": "Neznana napaka",
"ToastUnlinkOpenIdFailed": "Prekinitev povezave uporabnika z OpenID ni uspela",
"ToastUnlinkOpenIdSuccess": "Uporabnik je prekinil povezavo z OpenID",
"ToastUploaderFilepathExistsError": "Datoteka s potjo \"{0}\" že obstaja na strežniku",
"ToastUploaderItemExistsInSubdirectoryError": "Element \"{0}\" uporablja podmapo v poti za nalaganje.",
"ToastUserDeleteFailed": "Brisanje uporabnika ni uspelo",
"ToastUserDeleteSuccess": "Uporabnik je bil izbrisan",
"ToastUserPasswordChangeSuccess": "Geslo je bilo uspešno spremenjeno",

View File

@@ -32,6 +32,8 @@
"ButtonEditChapters": "Redigera kapitel",
"ButtonEditPodcast": "Redigera podcast",
"ButtonEnable": "Aktivera",
"ButtonFireAndFail": "Starta och Misslyckas",
"ButtonFireOnTest": "Starta onTest händelse",
"ButtonForceReScan": "Starta ny skanning",
"ButtonFullPath": "Fullständig sökväg",
"ButtonHide": "Dölj",
@@ -102,6 +104,7 @@
"ButtonStats": "Statistik",
"ButtonSubmit": "Skicka",
"ButtonTest": "Testa",
"ButtonUnlinkOpenId": "Koppla från OpenID",
"ButtonUpload": "Ladda upp",
"ButtonUploadBackup": "Läs in säkerhetskopia",
"ButtonUploadCover": "Ladda upp omslag",
@@ -209,6 +212,7 @@
"HeaderYearReview": "Sammanställning av {0}",
"HeaderYourStats": "Din statistik",
"LabelAbridged": "Förkortad version",
"LabelAbridgedChecked": "Förkortad (kontrollerad)",
"LabelAbridgedUnchecked": "Oavkortad (okontrollerad)",
"LabelAccessibleBy": "Tillgänglig för",
"LabelAccountType": "Kontotyp",
@@ -249,7 +253,7 @@
"LabelBackToUser": "Tillbaka till användaren",
"LabelBackupAudioFiles": "Säkerhetskopiera ljudfiler",
"LabelBackupLocation": "Plats för säkerhetskopia",
"LabelBackupsEnableAutomaticBackups": "Aktivera automatisk säkerhetskopiering",
"LabelBackupsEnableAutomaticBackups": "Automatisk säkerhetskopiering",
"LabelBackupsEnableAutomaticBackupsHelp": "Säkerhetskopior sparas i \"/metadata/backups\"",
"LabelBackupsMaxBackupSize": "Maximal storlek på säkerhetskopia i GigaByte (0 = obegränsad)",
"LabelBackupsMaxBackupSizeHelp": "Som ett skydd mot en felaktig konfiguration kommer säkerhetskopior inte att genomföras om de överskrider den konfigurerade storleken.",
@@ -271,6 +275,7 @@
"LabelClosePlayer": "Stäng spelaren",
"LabelCodec": "Codec",
"LabelCollapseSeries": "Komprimera serier",
"LabelCollapseSubSeries": "Komprimera underserier",
"LabelCollection": "Samling",
"LabelCollections": "Samlingar",
"LabelComplete": "Komplett",
@@ -339,6 +344,7 @@
"LabelEpisodic": "Uppdelad i avsnitt",
"LabelExample": "Exempel",
"LabelExpandSeries": "Expandera serier",
"LabelExpandSubSeries": "Expandera Underserier",
"LabelExplicit": "Explicit version",
"LabelExplicitChecked": "Explicit version (markerad)",
"LabelExplicitUnchecked": "Ej Explicit version (ej markerad)",
@@ -362,6 +368,7 @@
"LabelFontItalic": "Kursiv",
"LabelFontScale": "Skala på typsnitt",
"LabelFontStrikethrough": "Genomstruken",
"LabelFormat": "Format",
"LabelFull": "Komplett",
"LabelGenre": "Kategori",
"LabelGenres": "Kategorier",
@@ -434,6 +441,8 @@
"LabelMissing": "Saknar",
"LabelMissingEbook": "Saknar e-bok",
"LabelMissingSupplementaryEbook": "Saknar kompletterande e-bok",
"LabelMobileRedirectURIs": "Tillåtna mobila omdirigerings-URI:er",
"LabelMobileRedirectURIsDescription": "Detta är en vitlista över giltiga omdirigerings-URI:er för mobila appar. Standard är <code>audiobookshelf://oauth</code>, som du kan radera eller komplettera med ytterligare URI:er för integrering av tredje-parts appar. Används ett asterisk (<code>*</code>) som enda inmatning tillåts alla URI:er.",
"LabelMore": "Mer",
"LabelMoreInfo": "Mer information",
"LabelName": "Namn",
@@ -544,7 +553,8 @@
"LabelSettingsBookshelfViewHelp": "Bakgrund med ett utseende liknande en bokhylla i trä",
"LabelSettingsChromecastSupport": "Stöd för Chromecast",
"LabelSettingsDateFormat": "Datumformat",
"LabelSettingsEnableWatcher": "Automatiskt upptäcka förändringar i biblioteket",
"LabelSettingsEnableWatcher": "Upptäck automatiskt förändringar i biblioteket",
"LabelSettingsEnableWatcherForLibrary": "Upptäck automatiskt förändringar i biblioteket",
"LabelSettingsEnableWatcherHelp": "Aktiverar automatik att upptäcka när objekt<br>adderas, uppdateras eller raderas.<br>OBS: Kräver en omstart av servern",
"LabelSettingsEpubsAllowScriptedContent": "Tillåt e-böcker i epubs-format som innehåller script",
"LabelSettingsEpubsAllowScriptedContentHelp": "Tillåt att epub-filer får innehålla script.<br>Det rekommenderas att denna inställning är<br>avstängd när du inte litar på källan för epub-filerna.",
@@ -819,12 +829,13 @@
"MessageResetChaptersConfirm": "Är du säker på att du vill återställa alla kapitel och ångra de ändringarna du gjort?",
"MessageRestoreBackupConfirm": "Är du säker på att du vill läsa in säkerhetskopian som skapades den",
"MessageRestoreBackupWarning": "Att återställa en säkerhetskopia kommer att skriva över hela databasen som finns i /config och omslagsbilder i /metadata/items & /metadata/authors.<br /><br />Säkerhetskopior ändrar inte några filer i dina biblioteksmappar. Om du har aktiverat serverinställningar för att lagra omslagskonst och metadata i dina biblioteksmappar säkerhetskopieras eller skrivs de inte över.<br /><br />Alla klienter som använder din server kommer att uppdateras automatiskt.",
"MessageScheduleLibraryScanNote": "För de flesta användare rekommenderas att denna funktion ej aktiveras. Istället bör funktionen som automatisk upptäcker ändringar av filerna vara aktiverad. För vissa filsystem (som t.ex. NFS) fungerar inte denna funktion. Då kan schemalagda skanningar av biblioteken användas istället.",
"MessageScheduleLibraryScanNote": "För de flesta användare rekommenderas att denna funktion ej aktiveras. Istället bör funktionen som automatisk upptäcker ändringar i biblioteket vara aktiverad. För vissa filsystem (som t.ex. NFS) fungerar inte denna funktion. Då kan schemalagda skanningar av biblioteken användas istället.",
"MessageScheduleRunEveryWeekdayAtTime": "Startar varje {0} klockan {1}",
"MessageSearchResultsFor": "Sökresultat för",
"MessageSelected": "{0} valda",
"MessageServerCouldNotBeReached": "Servern kunde inte nås",
"MessageSetChaptersFromTracksDescription": "Använd varje ljudfil som ett kapitel och ljudfilens namn som kapitlets rubrik",
"MessageShareExpiresIn": "Upphör om {0}",
"MessageStartPlaybackAtTime": "Starta uppspelning av \"{0}\" vid tidpunkt {1}?",
"MessageTaskAudioFileNotWritable": "Det går inte att skriva till ljudfilen \"{0}\"",
"MessageTaskCanceledByUser": "Uppgiften avslutades av användaren",
@@ -909,6 +920,7 @@
"ToastAuthorUpdateMerged": "Författaren sammanslagen",
"ToastAuthorUpdateSuccess": "Författaren uppdaterad",
"ToastAuthorUpdateSuccessNoImageFound": "Författaren uppdaterad (ingen bild hittad)",
"ToastBackupAppliedSuccess": "Säkerhetskopian är importerad",
"ToastBackupCreateFailed": "Det gick inte att skapa en säkerhetskopia",
"ToastBackupCreateSuccess": "Säkerhetskopian har skapats",
"ToastBackupDeleteFailed": "Det gick inte att radera säkerhetskopian",
@@ -918,6 +930,7 @@
"ToastBackupRestoreFailed": "Det gick inte att återställa säkerhetskopian",
"ToastBackupUploadFailed": "Det gick inte att ladda upp säkerhetskopian",
"ToastBackupUploadSuccess": "Säkerhetskopian uppladdad",
"ToastBatchApplyDetailsToItemsSuccess": "Informationen har adderats till alla objekt",
"ToastBatchQuickMatchStarted": "Snabbmatchning av {0} böcker har påbörjats!",
"ToastBatchUpdateFailed": "Batchuppdateringen misslyckades",
"ToastBatchUpdateSuccess": "Batchuppdateringen lyckades",
@@ -948,6 +961,8 @@
"ToastEpisodeDownloadQueueClearSuccess": "Kö för nedladdning av avsnitt har tömts",
"ToastEpisodeUpdateSuccess": "{0} avsnitt uppdaterades",
"ToastFailedToLoadData": "Misslyckades med att ladda data",
"ToastFailedToMatch": "Misslyckades med att matcha",
"ToastFailedToShare": "Misslyckades med att dela",
"ToastFailedToUpdate": "Misslyckades med att uppdatera",
"ToastInvalidImageUrl": "Felaktig URL-adress till omslagsbilden",
"ToastInvalidMaxEpisodesToDownload": "Ogiltigt maximalt antal avsnitt att ladda ner",
@@ -1030,6 +1045,7 @@
"ToastSortingPrefixesUpdateSuccess": "{0} begrepp för sortering har uppdateras",
"ToastTitleRequired": "En titel måste anges",
"ToastUnknownError": "Ett okänt fel inträffade",
"ToastUploaderFilepathExistsError": "En fil med namnet \"{0}\" finns redan på servern",
"ToastUserDeleteFailed": "Misslyckades med att ta bort användaren",
"ToastUserDeleteSuccess": "Användaren borttagen",
"ToastUserPasswordChangeSuccess": "Lösenordet har ändrats",

View File

@@ -47,6 +47,8 @@
"ButtonLookup": "Sorgula",
"ButtonManageTracks": "Parçaları Yönet",
"ButtonMapChapterTitles": "Bölüm Başlıklarını Haritalandır",
"ButtonMatchAllAuthors": "Bütün Yazarlarla Eşleştir",
"ButtonMatchBooks": "Kitapları Eşleştir",
"ButtonNevermind": "Vazgeç",
"ButtonNext": "Sonraki",
"ButtonNextChapter": "Sonraki Bölüm",
@@ -66,6 +68,9 @@
"ButtonPurgeItemsCache": "Öğenin Önbelleğini Temizle",
"ButtonQueueAddItem": "Sıraya ekle",
"ButtonQueueRemoveItem": "Sıradan çıkar",
"ButtonQuickEmbed": "Hızlı Embed",
"ButtonQuickEmbedMetadata": "Hızlı Embed Üstverisi",
"ButtonQuickMatch": "Hızlı Eşleştirme",
"ButtonReScan": "Yeniden Tara",
"ButtonRead": "Oku",
"ButtonReadLess": "Daha az göster",
@@ -74,14 +79,37 @@
"ButtonRemove": "Kaldır",
"ButtonRemoveAll": "Hepsini Sil",
"ButtonRemoveAllLibraryItems": "Bütün Kütüphane Öğelerini Sil",
"ButtonRemoveFromContinueListening": "Dinlemeye Devam Etmekten Çıkar",
"ButtonRemoveFromContinueReading": "Okumaya Devam Etmekten Çıkar",
"ButtonRemoveSeriesFromContinueSeries": "Seriye Devam Et'ten Seriyi Çıkar",
"ButtonReset": "Sıfırla",
"ButtonResetToDefault": "Varsayılana sıfırla",
"ButtonRestore": "Geri getir",
"ButtonSave": "Kaydet",
"ButtonSaveAndClose": "Kaydet & Kapat",
"ButtonSaveTracklist": "Parça Listesini Kaydet",
"ButtonScan": "Tara",
"ButtonScanLibrary": "Kütüphaneyi Tara",
"ButtonScrollLeft": "Sola Kaydır",
"ButtonScrollRight": "Sağa Kaydır",
"ButtonSearch": "Ara",
"ButtonSeries": "Dizi",
"ButtonSelectFolderPath": "Klasör Yolunu Seç",
"ButtonSeries": "Seriler",
"ButtonSubmit": "Gönder",
"ButtonViewAll": "Tümünü Görüntüle",
"ButtonYes": "Evet",
"ErrorUploadFetchMetadataAPI": "Üst veriyi almakta hata",
"ErrorUploadFetchMetadataNoResults": "Üstveri alınamadı - başlık ve(ya) yazarı güncellemeyi deneyin",
"ErrorUploadLacksTitle": "Başlığa sahip olmalı",
"HeaderAccount": "Hesap",
"HeaderAddCustomMetadataProvider": "Özel Üstveri Sağlayıcısı Ekle",
"HeaderAdvanced": "Gelişmiş",
"HeaderAppriseNotificationSettings": "Bildirim Ayarlarının Haberini Ver",
"HeaderAudioTracks": "Ses Kanalları",
"HeaderAudiobookTools": "Sesli Kitap Dosya Yönetim Araçları",
"HeaderAuthentication": "Kimlik Doğrulama",
"HeaderBackups": "Yedeklemeler",
"HeaderChangePassword": "Parolayı Değiştir",
"HeaderChapters": "Bölümler",
"HeaderCollection": "Koleksiyon",
"HeaderCollectionItems": "Koleksiyon Öğeleri",
@@ -89,37 +117,99 @@
"HeaderEbookFiles": "Ebook Dosyaları",
"HeaderEpisodes": "Bölümler",
"HeaderEreaderSettings": "Ereader Ayarları",
"HeaderFiles": "Dosyalar",
"HeaderIgnoredFiles": "Görmezden Gelinen Dosyalar",
"HeaderItemFiles": "Öğe Dosyaları",
"HeaderItemMetadataUtils": "Öğe Üstveri Araçları",
"HeaderLastListeningSession": "Son Dinleme Oturumu",
"HeaderLatestEpisodes": "En son bölümler",
"HeaderLibraries": "Kütüphaneler",
"HeaderLibraryFiles": "Kütüphane Dosyaları",
"HeaderLibraryStats": "Kütüphane İstatistikleri",
"HeaderListeningSessions": "Dinleme Oturumları",
"HeaderListeningStats": "Dinleme İstatistikleri",
"HeaderLogin": "Giriş Yap",
"HeaderLogs": "Günlükler",
"HeaderManageGenres": "Türleri Yönet",
"HeaderManageTags": "Etiketleri Yönet",
"HeaderMapDetails": "Detayları haritalandır",
"HeaderMatch": "Eşleştir",
"HeaderMetadataOrderOfPrecedence": "Üstveri öncelik sırası",
"HeaderMetadataToEmbed": "Gömülecek üstveri",
"HeaderNewAccount": "Yeni Hesap",
"HeaderNewLibrary": "Yeni Kütüphane",
"HeaderNotificationCreate": "Bildirim Oluştur",
"HeaderNotificationUpdate": "Güncelleme Bildirimi",
"HeaderNotifications": "Bildirimler",
"HeaderOpenRSSFeed": "RSS Akışını Aç",
"HeaderOtherFiles": "Diğer Dosyalar",
"HeaderPasswordAuthentication": "Parola Doğrulaması",
"HeaderPermissions": "İzinler",
"HeaderPlayerQueue": "Oynatıcı Sırası",
"HeaderPlayerSettings": "Oynatıcı Ayarları",
"HeaderPlaylist": "Oynatma listesi",
"HeaderPlaylistItems": "Oynatma Listesi Öğeleri",
"HeaderPodcastsToAdd": "Eklenecek Podcastler",
"HeaderPreviewCover": "Kapak Önizlemesi",
"HeaderRSSFeedGeneral": "RSS Detayları",
"HeaderRSSFeedIsOpen": "RSS Akışıık",
"HeaderRSSFeeds": "RSS Bültenleri",
"HeaderRemoveEpisode": "Bölümü Kaldır",
"HeaderRemoveEpisodes": "{0} Bölümü Kaldır",
"HeaderSavedMediaProgress": "Kaydedilen Medya İlerleyişi",
"HeaderSchedule": "Program",
"HeaderSettings": "Ayarlar",
"HeaderSleepTimer": "Uyku Zamanlayıcısı",
"HeaderStatsMinutesListeningChart": "Dinlenilen Dakika (son 7 gün)",
"HeaderStatsRecentSessions": "Geçmiş Oturumlar",
"HeaderTableOfContents": "İçindekiler",
"HeaderUpdateAuthor": "Yazarı Güncelle",
"HeaderUpdateDetails": "Detayları Güncelle",
"HeaderUpdateLibrary": "Kütüphaneyi Güncelle",
"HeaderUsers": "Kullanıcılar",
"HeaderYearReview": "{0} Yılına Bir Bakış",
"HeaderYourStats": "İstatistiklerin",
"LabelAccountType": "Hesap Türü",
"LabelAccountTypeAdmin": "Yönetici",
"LabelAccountTypeGuest": "Ziyaretçi",
"LabelAccountTypeUser": "Kullanıcı",
"LabelActivities": "Etkinlikler",
"LabelActivity": "Etkinlik",
"LabelAddToCollection": "Koleksiyona Ekle",
"LabelAddToCollectionBatch": "Koleksiyona {0} Kitap Ekle",
"LabelAddToPlaylist": "Oynatma Listesine Ekle",
"LabelAddToPlaylistBatch": "Çalma Listesine {0} Öğe Ekle",
"LabelAddedAt": "Eklenme Zamanı",
"LabelAddedDate": "Eklendi {0}",
"LabelAdminUsersOnly": "Yalnızca yönetici kullanıcılar",
"LabelAll": "Hepsi",
"LabelAllEpisodesDownloaded": "Tüm bölümler indirildi",
"LabelAllUsers": "Tüm Kullanıcılar",
"LabelAllUsersExcludingGuests": "Ziyaretçiler dışında tüm kullanıcılar",
"LabelAllUsersIncludingGuests": "Ziyaretçiler dahil tüm kullanıcılar",
"LabelAlreadyInYourLibrary": "Zaten kütüphanenizde var",
"LabelApiToken": "API Token",
"LabelAuthor": "Yazar",
"LabelAuthorFirstLast": "Yazar (İlk Son)",
"LabelAuthorLastFirst": "Yazar (Son, İlk)",
"LabelAuthors": "Yazarlar",
"LabelAutoDownloadEpisodes": "Bölümleri Otomatik Olarak İndir",
"LabelBooks": "Kitaplar",
"LabelChangePassword": "Şifreyi Değiştir",
"LabelChapters": "Bölümler",
"LabelClickForMoreInfo": "Daha fazla bilgi için tıklayın",
"LabelClosePlayer": "Oynatıcıyı kapat",
"LabelCollapseSeries": "Seriyi Daralt",
"LabelComplete": "Tamamlandı",
"LabelContinueListening": "Dinlemeye Devam Et",
"LabelContinueReading": "Okumaya Devam Et",
"LabelContinueSeries": "Seriye Devam Et",
"LabelDeleteFromFileSystemCheckbox": "Dosya sisteminden sil (sadece veritabanından silmek için işareti kaldır)",
"LabelDescription": "Açıklama",
"LabelDeselectAll": "Tümünün Seçimini Kaldır",
"LabelDevice": "Cihaz",
"LabelDeviceInfo": "Cihaz Bilgisi",
"LabelDirectory": "Dizin",
"LabelDiscover": "Keşfet",
"LabelDownload": "İndir",
"LabelDuration": "Süre",
@@ -179,6 +269,7 @@
"LabelReadAgain": "Tekrar Oku",
"LabelRecentlyAdded": "Yakınlarda Eklenmiş",
"LabelSeason": "Sezon",
"LabelSeries": "Seriler",
"LabelSetEbookAsPrimary": "Birincil olarak ayarla",
"LabelSetEbookAsSupplementary": "Yedek olarak ayarla",
"LabelShowAll": "Hepsini Göster",
@@ -205,5 +296,8 @@
"LabelUnknown": "Bilinmeyen",
"LabelUser": "Kullanıcı",
"LabelUsername": "Kullanıcı Adı",
"LabelYourBookmarks": "Yer İşaretleriniz"
"LabelYearReviewHide": "Yıla Bakışı Sakla",
"LabelYearReviewShow": "Yıla Bakışı Göster",
"LabelYourBookmarks": "Yer İşaretleriniz",
"LabelYourProgress": "Gelişiminiz"
}

View File

@@ -177,6 +177,7 @@
"HeaderPlaylist": "Список відтворення",
"HeaderPlaylistItems": "Елементи списку відтворення",
"HeaderPodcastsToAdd": "Додати подкасти",
"HeaderPresets": "Пресети",
"HeaderPreviewCover": "Попередній перегляд",
"HeaderRSSFeedGeneral": "Подробиці RSS",
"HeaderRSSFeedIsOpen": "RSS-канал відкрито",
@@ -530,6 +531,7 @@
"LabelReleaseDate": "Дата публікації",
"LabelRemoveAllMetadataAbs": "Видалити всі файли metadata.abs",
"LabelRemoveAllMetadataJson": "Видалити всі файли metadata.json",
"LabelRemoveAudibleBranding": "Видалити звуковий вступ та завершення з розділів",
"LabelRemoveCover": "Видалити обкладинку",
"LabelRemoveMetadataFile": "Видалити файли метаданих у папках елементів бібліотеки",
"LabelRemoveMetadataFileHelp": "Видалити всі файли metadata.json та metadata.abs у ваших папках {0}.",
@@ -604,10 +606,11 @@
"LabelSlug": "Назва",
"LabelSortAscending": "По зростанню",
"LabelSortDescending": "По спаданню",
"LabelSortPubDate": "Сортувати дату публікації",
"LabelStart": "Початок",
"LabelStartTime": "Час початку",
"LabelStarted": "Почато",
"LabelStartedAt": "Почато",
"LabelStarted": "Стартував",
"LabelStartedAt": "Почато з",
"LabelStatsAudioTracks": "Аудіодоріжки",
"LabelStatsAuthors": "Автори",
"LabelStatsBestDay": "Найкращий день",
@@ -704,6 +707,8 @@
"LabelYourProgress": "Ваш прогрес",
"MessageAddToPlayerQueue": "Додати до черги відтворення",
"MessageAppriseDescription": "Щоб скористатися цією функцією, вам потрібно мати запущену <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> або API, що оброблятиме ті ж запити. <br />Аби надсилати сповіщення, URL-адреса API Apprise мусить бути повною, наприклад, якщо ваш API розміщено за адресою <code>http://192.168.1.1:8337</code>, то необхідно вказати адресу <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "Переконайтесь, що ви використовуєте ASIN з правильної регіональної Audible зони, а не з Amazon.",
"MessageAuthenticationOIDCChangesRestart": "Перезавантажте сервер після збереження, щоб застосувати зміни OIDC.",
"MessageBackupsDescription": "Резервні копії містять користувачів, прогрес, подробиці елементів бібліотеки, налаштування сервера та зображення з <code>/metadata/items</code> та <code>/metadata/authors</code>. Резервні копії <strong>не</strong> містять жодних файлів з тек бібліотеки.",
"MessageBackupsLocationEditNote": "Примітка: оновлення розташування резервної копії не переносить та не змінює існуючих копій",
"MessageBackupsLocationNoEditNote": "Примітка: розташування резервної копії встановлюється за допомогою змінної середовища та не може бути змінене тут.",
@@ -722,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Час початку мусить бути меншим за тривалість аудіокниги",
"MessageChapterErrorStartLtPrev": "Неприпустимий час початку, має бути більшим за час початку попередньої глави",
"MessageChapterStartIsAfter": "Початок глави знаходиться після закінчення книги",
"MessageChaptersNotFound": "Розділи не знайдені",
"MessageCheckingCron": "Перевірка планувальника...",
"MessageConfirmCloseFeed": "Ви дійсно бажаєте закрити цей канал?",
"MessageConfirmDeleteBackup": "Ви дійсно бажаєте видалити резервну копію за {0}?",
@@ -778,6 +784,7 @@
"MessageForceReScanDescription": "Просканує усі файли заново, неначе вперше. ID3-мітки, файли OPF та текстові файли будуть проскановані як нові.",
"MessageImportantNotice": "Важливе повідомлення!",
"MessageInsertChapterBelow": "Введіть главу нижче",
"MessageInvalidAsin": "Невірний ASIN",
"MessageItemsSelected": "Вибрано елементів: {0}",
"MessageItemsUpdated": "Оновлено елементів: {0}",
"MessageJoinUsOn": "Приєднуйтесь до",
@@ -811,7 +818,7 @@
"MessageNoItems": "Елементи відсутні",
"MessageNoItemsFound": "Елементів не знайдено",
"MessageNoListeningSessions": "Сеанси прослуховування відсутні",
"MessageNoLogs": "Журнал порожній",
"MessageNoLogs": "Немає журнали",
"MessageNoMediaProgress": "Прогрес відсутній",
"MessageNoNotifications": "Сповіщення відсутні",
"MessageNoPodcastFeed": "Невірний подкаст: Немає каналу",
@@ -849,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Запуск кожні {0} о {1}",
"MessageSearchResultsFor": "Результати пошуку для",
"MessageSelected": "Вибрано: {0}",
"MessageSeriesSequenceCannotContainSpaces": "Послідовність серій не може містити пробілів",
"MessageServerCouldNotBeReached": "Не вдалося підключитися до сервера",
"MessageSetChaptersFromTracksDescription": "Створити глави з аудіодоріжок, встановивши назви файлів за заголовки",
"MessageShareExpirationWillBe": "Термін сплине за <strong>{0}</strong>",
@@ -967,6 +975,8 @@
"ToastCachePurgeFailed": "Не вдалося очистити кеш",
"ToastCachePurgeSuccess": "Кеш очищено",
"ToastChaptersHaveErrors": "Глави містять помилки",
"ToastChaptersInvalidShiftAmountLast": "Недійсна тривалість зсуву. Час початку останнього розділу перевищує тривалість цієї аудіокниги.",
"ToastChaptersInvalidShiftAmountStart": "Недійсна величина зсуву. Перший розділ матиме нульову або від’ємну тривалість і буде перезаписаний другим розділом. Збільште початкову тривалість другого розділу.",
"ToastChaptersMustHaveTitles": "Глави повинні мати назви",
"ToastChaptersRemoved": "Розділи видалені",
"ToastChaptersUpdated": "Розділи оновлені",
@@ -1086,6 +1096,8 @@
"ToastUnknownError": "Невідома помилка",
"ToastUnlinkOpenIdFailed": "Не вдалося відв'язати користувача від OpenID",
"ToastUnlinkOpenIdSuccess": "Користувача відв'язано від OpenID",
"ToastUploaderFilepathExistsError": "Шлях до файлу \"{0}\" уже існує на сервері",
"ToastUploaderItemExistsInSubdirectoryError": "Елемент \"{0}\" використовує підкаталог шляху завантаження.",
"ToastUserDeleteFailed": "Не вдалося видалити користувача",
"ToastUserDeleteSuccess": "Користувача видалено",
"ToastUserPasswordChangeSuccess": "Пароль успішно змінено",

View File

@@ -21,7 +21,7 @@
"ButtonChooseFiles": "选择文件",
"ButtonClearFilter": "清除过滤器",
"ButtonCloseFeed": "关闭源",
"ButtonCloseSession": "关闭开放会话",
"ButtonCloseSession": "关闭活动会话",
"ButtonCollections": "收藏",
"ButtonConfigureScanner": "配置扫描",
"ButtonCreate": "创建",
@@ -177,6 +177,7 @@
"HeaderPlaylist": "播放列表",
"HeaderPlaylistItems": "播放列表项目",
"HeaderPodcastsToAdd": "要添加的播客",
"HeaderPresets": "预设",
"HeaderPreviewCover": "预览封面",
"HeaderRSSFeedGeneral": "RSS 详细信息",
"HeaderRSSFeedIsOpen": "RSS 源已打开",
@@ -229,6 +230,7 @@
"LabelAddedDate": "已添加 {0}",
"LabelAdminUsersOnly": "仅限管理员用户",
"LabelAll": "全部",
"LabelAllEpisodesDownloaded": "所有剧集已下载",
"LabelAllUsers": "所有用户",
"LabelAllUsersExcludingGuests": "除访客外的所有用户",
"LabelAllUsersIncludingGuests": "包括访客的所有用户",
@@ -529,6 +531,7 @@
"LabelReleaseDate": "发布日期",
"LabelRemoveAllMetadataAbs": "删除所有 metadata.abs 文件",
"LabelRemoveAllMetadataJson": "删除所有 metadata.json 文件",
"LabelRemoveAudibleBranding": "删除章节中的 Audible 简介和结尾",
"LabelRemoveCover": "移除封面",
"LabelRemoveMetadataFile": "删除库项目文件夹中的元数据文件",
"LabelRemoveMetadataFileHelp": "删除 {0} 文件夹中的所有 metadata.json 和 metadata.abs 文件.",
@@ -603,6 +606,7 @@
"LabelSlug": "Slug",
"LabelSortAscending": "升序",
"LabelSortDescending": "降序",
"LabelSortPubDate": "按出版日期排序",
"LabelStart": "开始",
"LabelStartTime": "开始时间",
"LabelStarted": "开始于",
@@ -703,6 +707,8 @@
"LabelYourProgress": "你的进度",
"MessageAddToPlayerQueue": "添加到播放队列",
"MessageAppriseDescription": "要使用此功能,你需要运行一个 <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> 实例或一个可以处理这些相同请求的 API. <br />Apprise API Url 应该是发送通知的完整 URL 路径, 例如: 如果你的 API 实例运行在 <code>http://192.168.1.1:8337</code>, 那么你可以输入 <code>http://192.168.1.1:8337/notify</code>.",
"MessageAsinCheck": "确保你使用的 ASIN 来自正确的 Audible 地区, 而不是亚马逊.",
"MessageAuthenticationOIDCChangesRestart": "保存后重新启动服务器以应用 OIDC 更改.",
"MessageBackupsDescription": "备份包括用户, 用户进度, 媒体库项目详细信息, 服务器设置和图像, 存储在 <code>/metadata/items</code> & <code>/metadata/authors</code>. 备份不包括存储在你的媒体库文件夹中的任何文件.",
"MessageBackupsLocationEditNote": "注意: 更新备份位置不会移动或修改现有备份",
"MessageBackupsLocationNoEditNote": "注意: 备份位置是通过环境变量设置的, 不能在此处更改.",
@@ -721,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "无效的开始时间, 必须小于有声读物持续时间",
"MessageChapterErrorStartLtPrev": "无效的开始时间, 必须大于或等于上一章节的开始时间",
"MessageChapterStartIsAfter": "章节开始是在有声读物结束之后",
"MessageChaptersNotFound": "未找到章节",
"MessageCheckingCron": "检查计划任务...",
"MessageConfirmCloseFeed": "你确定要关闭此订阅源吗?",
"MessageConfirmDeleteBackup": "你确定要删除备份 {0}?",
@@ -777,6 +784,7 @@
"MessageForceReScanDescription": "将像重新扫描一样再次扫描所有文件. 音频文件 ID3 标签, OPF 文件和文本文件将被扫描为新文件.",
"MessageImportantNotice": "重要通知!",
"MessageInsertChapterBelow": "在下面插入章节",
"MessageInvalidAsin": "无效的 ASIN",
"MessageItemsSelected": "已选定 {0} 个项目",
"MessageItemsUpdated": "已更新 {0} 个项目",
"MessageJoinUsOn": "加入我们",
@@ -848,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "每隔 {0} 在 {1} 运行一次",
"MessageSearchResultsFor": "搜索结果",
"MessageSelected": "{0} 已选择",
"MessageSeriesSequenceCannotContainSpaces": "系列序列不能包含空格",
"MessageServerCouldNotBeReached": "无法访问服务器",
"MessageSetChaptersFromTracksDescription": "把每个音频文件设置为章节并将章节标题设置为音频文件名",
"MessageShareExpirationWillBe": "到期日期为 <strong>{0}</strong>",
@@ -953,6 +962,7 @@
"ToastBackupRestoreFailed": "备份还原失败",
"ToastBackupUploadFailed": "上传备份失败",
"ToastBackupUploadSuccess": "备份已上传",
"ToastBatchApplyDetailsToItemsSuccess": "应用于项目的详细信息",
"ToastBatchDeleteFailed": "批量删除失败",
"ToastBatchDeleteSuccess": "批量删除成功",
"ToastBatchQuickMatchFailed": "批量快速匹配失败!",
@@ -965,6 +975,8 @@
"ToastCachePurgeFailed": "清除缓存失败",
"ToastCachePurgeSuccess": "缓存清除成功",
"ToastChaptersHaveErrors": "章节有错误",
"ToastChaptersInvalidShiftAmountLast": "偏移量无效. 最后一章的开始时间将超过这本有声读物的持续时间.",
"ToastChaptersInvalidShiftAmountStart": "偏移量无效. 第一章的长度将为零或负数, 并会被第二章覆盖. 请增加第二章的起始时长.",
"ToastChaptersMustHaveTitles": "章节必须有标题",
"ToastChaptersRemoved": "已删除章节",
"ToastChaptersUpdated": "章节已更新",
@@ -1065,6 +1077,7 @@
"ToastSelectAtLeastOneUser": "至少选择一位用户",
"ToastSendEbookToDeviceFailed": "发送电子书到设备失败",
"ToastSendEbookToDeviceSuccess": "电子书已经发送到设备 \"{0}\"",
"ToastSeriesSubmitFailedSameName": "无法添加两个同名系列",
"ToastSeriesUpdateFailed": "更新系列失败",
"ToastSeriesUpdateSuccess": "系列已更新",
"ToastServerSettingsUpdateSuccess": "服务器设置已更新",
@@ -1083,6 +1096,8 @@
"ToastUnknownError": "未知错误",
"ToastUnlinkOpenIdFailed": "无法取消用户与 OpenID 的关联",
"ToastUnlinkOpenIdSuccess": "用户已取消与 OpenID 的关联",
"ToastUploaderFilepathExistsError": "文件路径 \"{0}\" 在服务器上已存在",
"ToastUploaderItemExistsInSubdirectoryError": "项目 \"{0}\" 正在使用上传路径的子目录。",
"ToastUserDeleteFailed": "删除用户失败",
"ToastUserDeleteSuccess": "用户已删除",
"ToastUserPasswordChangeSuccess": "密码修改成功",

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "audiobookshelf",
"version": "2.20.0",
"version": "2.24.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "audiobookshelf",
"version": "2.20.0",
"version": "2.24.0",
"license": "GPL-3.0",
"dependencies": {
"axios": "^0.27.2",

View File

@@ -1,6 +1,6 @@
{
"name": "audiobookshelf",
"version": "2.20.0",
"version": "2.24.0",
"buildNumber": 1,
"description": "Self-hosted audiobook and podcast server",
"main": "index.js",

View File

@@ -20,10 +20,7 @@ class Auth {
// Map of openId sessions indexed by oauth2 state-variable
this.openIdAuthSession = new Map()
const escapedRouterBasePath = escapeRegExp(global.RouterBasePath)
this.ignorePatterns = [
new RegExp(`^(${escapedRouterBasePath}/api)?/items/[^/]+/cover$`),
new RegExp(`^(${escapedRouterBasePath}/api)?/authors/[^/]+/image$`)
]
this.ignorePatterns = [new RegExp(`^(${escapedRouterBasePath}/api)?/items/[^/]+/cover$`), new RegExp(`^(${escapedRouterBasePath}/api)?/authors/[^/]+/image$`)]
}
/**

View File

@@ -310,10 +310,10 @@ class Server {
})
)
router.use(express.urlencoded({ extended: true, limit: '5mb' }))
router.use(express.json({ limit: '5mb' }))
router.use(express.json({ limit: '10mb' }))
router.use('/api', this.auth.ifAuthNeeded(this.authMiddleware.bind(this)), this.apiRouter.router)
router.use('/hls', this.authMiddleware.bind(this), this.hlsRouter.router)
router.use('/hls', this.hlsRouter.router)
router.use('/public', this.publicRouter.router)
// Static path to generated nuxt
@@ -395,10 +395,19 @@ class Server {
})
router.get('/healthcheck', (req, res) => res.sendStatus(200))
this.server.listen(this.Port, this.Host, () => {
if (this.Host) Logger.info(`Listening on http://${this.Host}:${this.Port}`)
else Logger.info(`Listening on port :${this.Port}`)
})
const unixSocketPrefix = 'unix/'
if (this.Host?.startsWith(unixSocketPrefix)) {
const sockPath = this.Host.slice(unixSocketPrefix.length)
this.server.listen(sockPath, async () => {
await fs.chmod(sockPath, 0o666)
Logger.info(`Listening on unix socket ${sockPath}`)
})
} else {
this.server.listen(this.Port, this.Host, () => {
if (this.Host) Logger.info(`Listening on http://${this.Host}:${this.Port}`)
else Logger.info(`Listening on port :${this.Port}`)
})
}
// Start listening for socket connections
SocketAuthority.initialize(this)

View File

@@ -84,6 +84,42 @@ class SocketAuthority {
}
}
/**
* Emits event with library item to all clients that can access the library item
* Note: Emits toOldJSONExpanded()
*
* @param {string} evt
* @param {import('./models/LibraryItem')} libraryItem
*/
libraryItemEmitter(evt, libraryItem) {
for (const socketId in this.clients) {
if (this.clients[socketId].user?.checkCanAccessLibraryItem(libraryItem)) {
this.clients[socketId].socket.emit(evt, libraryItem.toOldJSONExpanded())
}
}
}
/**
* Emits event with library items to all clients that can access the library items
* Note: Emits toOldJSONExpanded()
*
* @param {string} evt
* @param {import('./models/LibraryItem')[]} libraryItems
*/
libraryItemsEmitter(evt, libraryItems) {
for (const socketId in this.clients) {
if (this.clients[socketId].user) {
const libraryItemsAccessibleToUser = libraryItems.filter((li) => this.clients[socketId].user.checkCanAccessLibraryItem(li))
if (libraryItemsAccessibleToUser.length) {
this.clients[socketId].socket.emit(
evt,
libraryItemsAccessibleToUser.map((li) => li.toOldJSONExpanded())
)
}
}
}
}
/**
* Closes the Socket.IO server and disconnect all clients
*

View File

@@ -152,10 +152,7 @@ class AuthorController {
for (const libraryItem of libraryItems) {
await libraryItem.saveMetadataFile()
}
SocketAuthority.emitter(
'items_updated',
libraryItems.map((li) => li.toOldJSONExpanded())
)
SocketAuthority.libraryItemsEmitter('items_updated', libraryItems)
}
// Remove old author
@@ -210,10 +207,7 @@ class AuthorController {
}
if (libraryItems.length) {
SocketAuthority.emitter(
'items_updated',
libraryItems.map((li) => li.toOldJSONExpanded())
)
SocketAuthority.libraryItemsEmitter('items_updated', libraryItems)
}
} else {
numBooksForAuthor = await Database.bookAuthorModel.getCountForAuthor(req.author.id)

View File

@@ -84,49 +84,67 @@ class FileSystemController {
*/
async checkPathExists(req, res) {
if (!req.user.canUpload) {
Logger.error(`[FileSystemController] Non-admin user "${req.user.username}" attempting to check path exists`)
Logger.error(`[FileSystemController] User "${req.user.username}" without upload permissions attempting to check path exists`)
return res.sendStatus(403)
}
const { filepath, directory, folderPath } = req.body
const { directory, folderPath } = req.body
if (!filepath?.length || typeof filepath !== 'string') {
if (!directory?.length || typeof directory !== 'string' || !folderPath?.length || typeof folderPath !== 'string') {
Logger.error(`[FileSystemController] Invalid request body: ${JSON.stringify(req.body)}`)
return res.status(400).json({
error: 'Invalid request body'
})
}
// Check that library folder exists
const libraryFolder = await Database.libraryFolderModel.findOne({
where: {
path: folderPath
}
})
if (!libraryFolder) {
Logger.error(`[FileSystemController] Library folder not found: ${folderPath}`)
return res.sendStatus(404)
}
const filepath = Path.posix.join(libraryFolder.path, directory)
// Ensure filepath is inside library folder (prevents directory traversal)
if (!filepath.startsWith(libraryFolder.path)) {
Logger.error(`[FileSystemController] Filepath is not inside library folder: ${filepath}`)
return res.sendStatus(400)
}
const exists = await fs.pathExists(filepath)
if (exists) {
if (await fs.pathExists(filepath)) {
return res.json({
exists: true
})
}
// If directory and folderPath are passed in, check if a library item exists in a subdirectory
// Check if a library item exists in a subdirectory
// See: https://github.com/advplyr/audiobookshelf/issues/4146
if (typeof directory === 'string' && typeof folderPath === 'string' && directory.length > 0 && folderPath.length > 0) {
const cleanedDirectory = directory.split('/').filter(Boolean).join('/')
if (cleanedDirectory.includes('/')) {
// Can only be 2 levels deep
const possiblePaths = []
const subdir = Path.dirname(directory)
possiblePaths.push(fileUtils.filePathToPOSIX(Path.join(folderPath, subdir)))
if (subdir.includes('/')) {
possiblePaths.push(fileUtils.filePathToPOSIX(Path.join(folderPath, Path.dirname(subdir))))
}
const cleanedDirectory = directory.split('/').filter(Boolean).join('/')
if (cleanedDirectory.includes('/')) {
// Can only be 2 levels deep
const possiblePaths = []
const subdir = Path.dirname(directory)
possiblePaths.push(fileUtils.filePathToPOSIX(Path.join(folderPath, subdir)))
if (subdir.includes('/')) {
possiblePaths.push(fileUtils.filePathToPOSIX(Path.join(folderPath, Path.dirname(subdir))))
}
const libraryItem = await Database.libraryItemModel.findOne({
where: {
path: possiblePaths
}
const libraryItem = await Database.libraryItemModel.findOne({
where: {
path: possiblePaths
}
})
if (libraryItem) {
return res.json({
exists: true,
libraryItemTitle: libraryItem.title
})
if (libraryItem) {
return res.json({
exists: true,
libraryItemTitle: libraryItem.title
})
}
}
}

View File

@@ -1188,10 +1188,7 @@ class LibraryController {
}
if (itemsUpdated.length) {
SocketAuthority.emitter(
'items_updated',
itemsUpdated.map((li) => li.toOldJSONExpanded())
)
SocketAuthority.libraryItemsEmitter('items_updated', itemsUpdated)
}
res.json({
@@ -1232,10 +1229,7 @@ class LibraryController {
}
if (itemsUpdated.length) {
SocketAuthority.emitter(
'items_updated',
itemsUpdated.map((li) => li.toOldJSONExpanded())
)
SocketAuthority.libraryItemsEmitter('items_updated', itemsUpdated)
}
res.json({

View File

@@ -253,7 +253,7 @@ class LibraryItemController {
}
Logger.debug(`[LibraryItemController] Updated library item media ${req.libraryItem.media.title}`)
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
}
res.json({
updated: hasUpdates,
@@ -300,7 +300,7 @@ class LibraryItemController {
req.libraryItem.changed('updatedAt', true)
await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json({
success: true,
cover: result.cover
@@ -332,7 +332,7 @@ class LibraryItemController {
req.libraryItem.changed('updatedAt', true)
await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
}
res.json({
success: true,
@@ -358,7 +358,7 @@ class LibraryItemController {
await CacheManager.purgeCoverCache(req.libraryItem.id)
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
}
res.sendStatus(200)
@@ -485,7 +485,7 @@ class LibraryItemController {
req.libraryItem.media.changed('audioFiles', true)
await req.libraryItem.media.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json(req.libraryItem.toOldJSON())
}
@@ -663,7 +663,7 @@ class LibraryItemController {
await libraryItem.saveMetadataFile()
Logger.debug(`[LibraryItemController] Updated library item media "${libraryItem.media.title}"`)
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
itemsUpdated++
}
}
@@ -834,8 +834,8 @@ class LibraryItemController {
}
if (req.libraryItem.isMissing || !req.libraryItem.isBook || !req.libraryItem.media.includedAudioFiles.length) {
Logger.error(`[LibraryItemController] Invalid library item`)
return res.sendStatus(500)
Logger.error(`[LibraryItemController] getMetadataObject: Invalid library item "${req.libraryItem.media.title}"`)
return res.sendStatus(400)
}
res.json(this.audioMetadataManager.getMetadataObjectForApi(req.libraryItem))
@@ -894,7 +894,7 @@ class LibraryItemController {
await req.libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
}
res.json({
@@ -1005,7 +1005,7 @@ class LibraryItemController {
await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.sendStatus(200)
}
@@ -1153,7 +1153,7 @@ class LibraryItemController {
await req.libraryItem.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.sendStatus(200)
}

View File

@@ -37,25 +37,31 @@ class MiscController {
Logger.warn(`User "${req.user.username}" attempted to upload without permission`)
return res.sendStatus(403)
}
if (!req.files) {
if (!req.files || !Object.values(req.files).length) {
Logger.error('Invalid request, no files')
return res.sendStatus(400)
}
const files = Object.values(req.files)
const { title, author, series, folder: folderId, library: libraryId } = req.body
let { title, author, series, folder: folderId, library: libraryId } = req.body
// Validate request body
if (!libraryId || !folderId || typeof libraryId !== 'string' || typeof folderId !== 'string' || !title || typeof title !== 'string') {
return res.status(400).send('Invalid request body')
}
if (!series || typeof series !== 'string') {
series = null
}
if (!author || typeof author !== 'string') {
author = null
}
const library = await Database.libraryModel.findByIdWithFolders(libraryId)
if (!library) {
return res.status(404).send(`Library not found with id ${libraryId}`)
return res.status(404).send('Library not found')
}
const folder = library.libraryFolders.find((fold) => fold.id === folderId)
if (!folder) {
return res.status(404).send(`Folder not found with id ${folderId} in library ${library.name}`)
}
if (!files.length || !title) {
return res.status(500).send(`Invalid post data`)
return res.status(404).send('Folder not found')
}
// Podcasts should only be one folder deep
@@ -216,7 +222,7 @@ class MiscController {
// Update nameIgnorePrefix column on series
const allSeries = await Database.seriesModel.findAll({
attributes: ['id', 'name', 'nameIgnorePrefix']
attributes: ['id', 'name', 'nameIgnorePrefix', 'libraryId']
})
const bulkUpdateSeries = []
allSeries.forEach((series) => {
@@ -224,6 +230,8 @@ class MiscController {
if (nameIgnorePrefix !== series.nameIgnorePrefix) {
bulkUpdateSeries.push({
id: series.id,
name: series.name,
libraryId: series.libraryId,
nameIgnorePrefix
})
}
@@ -343,7 +351,7 @@ class MiscController {
})
await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++
}
}
@@ -386,7 +394,7 @@ class MiscController {
})
await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++
}
@@ -481,7 +489,7 @@ class MiscController {
})
await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++
}
}
@@ -524,7 +532,7 @@ class MiscController {
})
await libraryItem.saveMetadataFile()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
numItemsUpdated++
}

View File

@@ -9,6 +9,7 @@ const fs = require('../libs/fsExtra')
const { getPodcastFeed, findMatchingEpisodes } = require('../utils/podcastUtils')
const { getFileTimestampsWithIno, filePathToPOSIX } = require('../utils/fileUtils')
const { validateUrl } = require('../utils/index')
const htmlSanitizer = require('../utils/htmlSanitizer')
const Scanner = require('../scanner/Scanner')
const CoverManager = require('../managers/CoverManager')
@@ -161,7 +162,7 @@ class PodcastController {
}
}
SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_added', newLibraryItem)
res.json(newLibraryItem.toOldJSONExpanded())
@@ -379,7 +380,7 @@ class PodcastController {
const overrideDetails = req.query.override === '1'
const episodesUpdated = await Scanner.quickMatchPodcastEpisodes(req.libraryItem, { overrideDetails })
if (episodesUpdated) {
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
}
res.json({
@@ -404,6 +405,15 @@ class PodcastController {
const supportedStringKeys = ['title', 'subtitle', 'description', 'pubDate', 'episode', 'season', 'episodeType']
for (const key in req.body) {
if (supportedStringKeys.includes(key) && typeof req.body[key] === 'string') {
// Sanitize description HTML
if (key === 'description' && req.body[key]) {
const sanitizedDescription = htmlSanitizer.sanitize(req.body[key])
if (sanitizedDescription !== req.body[key]) {
Logger.debug(`[PodcastController] Sanitized description from "${req.body[key]}" to "${sanitizedDescription}"`)
req.body[key] = sanitizedDescription
}
}
updatePayload[key] = req.body[key]
} else if (key === 'chapters' && Array.isArray(req.body[key]) && req.body[key].every((ch) => typeof ch === 'object' && ch.title && ch.start)) {
updatePayload[key] = req.body[key]
@@ -418,7 +428,7 @@ class PodcastController {
Logger.info(`[PodcastController] Updated episode "${episode.title}" keys`, episode.changed())
await episode.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
} else {
Logger.info(`[PodcastController] No changes to episode "${episode.title}"`)
}
@@ -504,7 +514,7 @@ class PodcastController {
req.libraryItem.media.numEpisodes = req.libraryItem.media.podcastEpisodes.length
await req.libraryItem.media.save()
SocketAuthority.emitter('item_updated', req.libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem)
res.json(req.libraryItem.toOldJSON())
}

View File

@@ -108,12 +108,12 @@ class SearchController {
async findChapters(req, res) {
const asin = req.query.asin
if (!isValidASIN(asin.toUpperCase())) {
return res.json({ error: 'Invalid ASIN' })
return res.json({ error: 'Invalid ASIN', stringKey: 'MessageInvalidAsin' })
}
const region = (req.query.region || 'us').toLowerCase()
const chapterData = await BookFinder.findChapters(asin, region)
if (!chapterData) {
return res.json({ error: 'Chapters not found' })
return res.json({ error: 'Chapters not found', stringKey: 'MessageChaptersNotFound' })
}
res.json(chapterData)
}

View File

@@ -1,7 +1,9 @@
const Path = require('path')
const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const Database = require('../Database')
const { toNumber, isUUID } = require('../utils/index')
const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUtils')
const ShareManager = require('../managers/ShareManager')
@@ -266,6 +268,51 @@ class SessionController {
this.playbackSessionManager.syncLocalSessionsRequest(req, res)
}
/**
* GET: /public/session/:id/track/:index
* While a session is open, this endpoint can be used to stream the audio track
*
* @this {import('../routers/PublicRouter')}
*
* @param {Request} req
* @param {Response} res
*/
async getTrack(req, res) {
const audioTrackIndex = toNumber(req.params.index, null)
if (audioTrackIndex === null) {
Logger.error(`[SessionController] Invalid audio track index "${req.params.index}"`)
return res.sendStatus(400)
}
const playbackSession = this.playbackSessionManager.getSession(req.params.id)
if (!playbackSession) {
Logger.error(`[SessionController] Unable to find playback session with id=${req.params.id}`)
return res.sendStatus(404)
}
const audioTrack = playbackSession.audioTracks.find((t) => t.index === audioTrackIndex)
if (!audioTrack) {
Logger.error(`[SessionController] Unable to find audio track with index=${audioTrackIndex}`)
return res.sendStatus(404)
}
const user = await Database.userModel.getUserById(playbackSession.userId)
Logger.debug(`[SessionController] Serving audio track ${audioTrack.index} for session "${req.params.id}" belonging to user "${user.username}"`)
if (global.XAccel) {
const encodedURI = encodeUriPath(global.XAccel + audioTrack.metadata.path)
Logger.debug(`Use X-Accel to serve static file ${encodedURI}`)
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
}
// Express does not set the correct mimetype for m4b files so use our defined mimetypes if available
const audioMimeType = getAudioMimeTypeFromExtname(Path.extname(audioTrack.metadata.path))
if (audioMimeType) {
res.setHeader('Content-Type', audioMimeType)
}
res.sendFile(audioTrack.metadata.path)
}
/**
*
* @param {RequestWithUser} req

View File

@@ -0,0 +1,75 @@
const { Request, Response, NextFunction } = require('express')
const Logger = require('../Logger')
const adminStats = require('../utils/queries/adminStats')
/**
* @typedef RequestUserObject
* @property {import('../models/User')} user
*
* @typedef {Request & RequestUserObject} RequestWithUser
*/
class StatsController {
constructor() {}
/**
* GET: /api/stats/server
* Currently not in use
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getServerStats(req, res) {
Logger.debug('[StatsController] getServerStats')
const totalSize = await adminStats.getTotalSize()
const numAudioFiles = await adminStats.getNumAudioFiles()
res.json({
books: {
...totalSize.books,
numAudioFiles: numAudioFiles.numBookAudioFiles
},
podcasts: {
...totalSize.podcasts,
numAudioFiles: numAudioFiles.numPodcastAudioFiles
},
total: {
...totalSize.total,
numAudioFiles: numAudioFiles.numAudioFiles
}
})
}
/**
* GET: /api/stats/year/:year
*
* @param {RequestWithUser} req
* @param {Response} res
*/
async getAdminStatsForYear(req, res) {
const year = Number(req.params.year)
if (isNaN(year) || year < 2000 || year > 9999) {
Logger.error(`[StatsController] Invalid year "${year}"`)
return res.status(400).send('Invalid year')
}
const stats = await adminStats.getStatsForYear(year)
res.json(stats)
}
/**
*
* @param {RequestWithUser} req
* @param {Response} res
* @param {NextFunction} next
*/
async middleware(req, res, next) {
if (!req.user.isAdminOrUp) {
Logger.error(`[StatsController] Non-admin user "${req.user.username}" attempted to access stats route`)
return res.sendStatus(403)
}
next()
}
}
module.exports = new StatsController()

View File

@@ -48,6 +48,7 @@ class ToolsController {
}
const options = req.query || {}
Logger.info(`[ToolsController] encodeM4b: Starting audiobook merge for "${req.libraryItem.media.title}" with options: ${JSON.stringify(options)}`)
this.abMergeManager.startAudiobookMerge(req.user.id, req.libraryItem, options)
res.sendStatus(200)

View File

@@ -26,6 +26,12 @@ class PlaybackSessionManager {
this.sessions = []
}
/**
* Get open session by id
*
* @param {string} sessionId
* @returns {PlaybackSession}
*/
getSession(sessionId) {
return this.sessions.find((s) => s.id === sessionId)
}
@@ -175,6 +181,25 @@ class PlaybackSessionManager {
// New session from local
session = new PlaybackSession(sessionJson)
session.deviceInfo = deviceInfo
if (session.mediaMetadata == null) {
session.mediaMetadata = {}
}
// Populate mediaMetadata with the current library items metadata for any keys not set by client
const libraryItemMediaMetadata = libraryItem.media.oldMetadataToJSON()
for (const key in libraryItemMediaMetadata) {
if (session.mediaMetadata[key] === undefined) {
session.mediaMetadata[key] = libraryItemMediaMetadata[key]
}
}
if (session.displayTitle == null || session.displayTitle === '') {
session.displayTitle = libraryItem.title
}
if (session.displayAuthor == null || session.displayAuthor === '') {
session.displayAuthor = libraryItem.authorNamesFirstLast
}
session.duration = libraryItem.media.getPlaybackDuration(sessionJson.episodeId)
Logger.debug(`[PlaybackSessionManager] Inserting new session for "${session.displayTitle}" (${session.id})`)

View File

@@ -211,6 +211,14 @@ class PodcastManager {
const podcastEpisode = await Database.podcastEpisodeModel.createFromRssPodcastEpisode(this.currentDownload.rssPodcastEpisode, libraryItem.media.id, audioFile)
libraryItem.libraryFiles.push(libraryFile.toJSON())
// Re-calculating library item size because this wasnt being updated properly for podcasts in v2.20.0 and below
let libraryItemSize = 0
libraryItem.libraryFiles.forEach((lf) => {
if (lf.metadata.size && !isNaN(lf.metadata.size)) {
libraryItemSize += Number(lf.metadata.size)
}
})
libraryItem.size = libraryItemSize
libraryItem.changed('libraryFiles', true)
libraryItem.media.podcastEpisodes.push(podcastEpisode)
@@ -246,7 +254,7 @@ class PodcastManager {
await libraryItem.media.save()
}
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
const podcastEpisodeExpanded = podcastEpisode.toOldJSONExpanded(libraryItem.id)
podcastEpisodeExpanded.libraryItem = libraryItem.toOldJSONExpanded()
SocketAuthority.emitter('episode_added', podcastEpisodeExpanded)
@@ -359,7 +367,7 @@ class PodcastManager {
libraryItem.changed('updatedAt', true)
await libraryItem.save()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
return libraryItem.media.autoDownloadEpisodes
}
@@ -417,7 +425,7 @@ class PodcastManager {
libraryItem.changed('updatedAt', true)
await libraryItem.save()
SocketAuthority.emitter('item_updated', libraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_updated', libraryItem)
return newEpisodes || []
}
@@ -704,7 +712,7 @@ class PodcastManager {
}
}
SocketAuthority.emitter('item_added', newLibraryItem.toOldJSONExpanded())
SocketAuthority.libraryItemEmitter('item_added', newLibraryItem)
// Turn on podcast auto download cron if not already on
if (newLibraryItem.media.autoDownloadEpisodes) {

View File

@@ -377,8 +377,17 @@ class Book extends Model {
if (typeof payload.metadata[key] == 'number') {
payload.metadata[key] = String(payload.metadata[key])
}
if ((typeof payload.metadata[key] === 'string' || payload.metadata[key] === null) && this[key] !== payload.metadata[key]) {
// Sanitize description HTML
if (key === 'description' && payload.metadata[key]) {
const sanitizedDescription = htmlSanitizer.sanitize(payload.metadata[key])
if (sanitizedDescription !== payload.metadata[key]) {
Logger.debug(`[Book] "${this.title}" Sanitized description from "${payload.metadata[key]}" to "${sanitizedDescription}"`)
payload.metadata[key] = sanitizedDescription
}
}
this[key] = payload.metadata[key] || null
if (key === 'title') {

View File

@@ -215,9 +215,13 @@ class FeedEpisode extends Model {
* @returns {Promise<FeedEpisode[]>}
*/
static async createFromBooks(books, feed, slug, transaction) {
const earliestLibraryItemCreatedAt = books.reduce((earliest, book) => {
return book.libraryItem.createdAt < earliest.libraryItem.createdAt ? book : earliest
}).libraryItem.createdAt
// This is never null unless the books array is empty, as this method is not invoked when no books. Reduce needs an initial item
const earliestLibraryItemCreatedAt =
books.length > 0
? books.reduce((earliest, book) => {
return book.libraryItem.createdAt < earliest.libraryItem.createdAt ? book : earliest
}).libraryItem.createdAt
: null
const feedEpisodeObjs = []
let numExisting = 0

View File

@@ -246,7 +246,6 @@ class LibraryItem extends Model {
include
})
if (!libraryItem) {
Logger.error(`[LibraryItem] Library item not found`)
return null
}

View File

@@ -246,9 +246,10 @@ class MediaProgress extends Model {
// For local sync
if (progressPayload.lastUpdate) {
this.updatedAt = progressPayload.lastUpdate
this.changed('updatedAt', true)
}
return this.save()
return this.save({ silent: !!progressPayload.lastUpdate })
}
}

View File

@@ -2,6 +2,7 @@ const { DataTypes, Model } = require('sequelize')
const { getTitlePrefixAtEnd, getTitleIgnorePrefix } = require('../utils')
const Logger = require('../Logger')
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
const htmlSanitizer = require('../utils/htmlSanitizer')
/**
* @typedef PodcastExpandedProperties
@@ -215,6 +216,15 @@ class Podcast extends Model {
newKey = 'itunesPageURL'
}
if ((typeof payload.metadata[key] === 'string' || payload.metadata[key] === null) && payload.metadata[key] !== this[newKey]) {
// Sanitize description HTML
if (key === 'description' && payload.metadata[key]) {
const sanitizedDescription = htmlSanitizer.sanitize(payload.metadata[key])
if (sanitizedDescription !== payload.metadata[key]) {
Logger.debug(`[Podcast] "${this.title}" Sanitized description from "${payload.metadata[key]}" to "${sanitizedDescription}"`)
payload.metadata[key] = sanitizedDescription
}
}
this[newKey] = payload.metadata[key] || null
if (key === 'title') {

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