Compare commits

...
Author SHA1 Message Date
advplyr 79f7fa32ab iOS version bump 0.9.79 2025-01-26 17:11:49 -06:00
advplyr 703ab710e9 Version bump v0.9.79-beta 2025-01-26 16:41:06 -06:00
advplyrandGitHub bc782ba9ee Merge pull request #1451 from weblate/weblate-audiobookshelf-abs-mobile-app
Translations update from Hosted Weblate
2025-01-26 16:16:20 -06:00
Максим ГорпинічandHosted Weblate f2eef64d84 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (341 of 341 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-26 22:35:04 +01:00
Simple16andHosted Weblate abb3a7a3a9 Translated using Weblate (Russian)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/ru/
2025-01-26 22:35:03 +01:00
advplyrandHosted Weblate ef61e020b6 Added translation using Weblate (Japanese) 2025-01-26 22:35:03 +01:00
Jan-Eric MyhrgrenandHosted Weblate 66c87f37e6 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-26 22:35:02 +01:00
Jan-Eric MyhrgrenandHosted Weblate 56caab19f1 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-26 22:35:02 +01:00
Jan-Eric MyhrgrenandHosted Weblate 27eb5f72f7 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-26 22:35:01 +01:00
advplyr 23a80a60b9 Show missing button with dialog, show missing indicator on covers 2025-01-26 15:34:54 -06:00
advplyr 0520cbd538 Update collection/playlist play button to show pause when playing #1394, update collections to play local item if available 2025-01-26 15:11:49 -06:00
advplyr c79ecbb92e Fix crash downloading with old server, check server version to append token on image requests #1450 2025-01-26 14:22:35 -06:00
advplyrandGitHub 08651d28ef Merge pull request #1455 from anstosa/defaultpodcastsort
Sensible default sort for podcasts
2025-01-26 12:49:48 -06:00
advplyrandGitHub 3060d186a1 Merge pull request #1453 from nichwall/android_sleep_timer_cleanup
Android sleep timer cleanup
2025-01-26 12:47:09 -06:00
advplyr 0509d7105e Update confirm disable auto timer message 2025-01-26 12:40:39 -06:00
advplyr b6ab7dc8a7 Update sleep timer modal to not show negative time remaining 2025-01-26 12:36:11 -06:00
Ansel Santosa 822ca65349 Sensible default sort for podcasts 2025-01-26 07:43:44 -08:00
advplyr 4b4a2b46c1 Merge branch 'master' into android_sleep_timer_cleanup 2025-01-26 09:36:48 -06:00
Nicholas Wallace 13b020732f General cleanup, only disable auto-sleep temporarily
Auto sleep timer is only disabled until the end of
the current time period (e.g. when the sleep timer
would be disabled automatically).
2025-01-25 19:00:43 -07:00
advplyr fb9ca7f5f3 Update item description to support rich text #1281 2025-01-25 14:10:35 -06:00
advplyr e21d37b20f Remove con.android.systemui from valid media browsers #1446 2025-01-25 12:27:43 -06:00
Nicholas Wallace 161614f6c9 Fix: scale end of chapter time by playback speed 2025-01-24 22:18:03 -07:00
Nicholas Wallace 16472e1de8 Simplify increase/decrease sleep timer 2025-01-24 20:05:43 -07:00
Nicholas Wallace d81e47204c Auto formatted code and added function comments 2025-01-24 19:55:03 -07:00
advplyrandGitHub 7ec93cd91e Merge pull request #1444 from weblate/weblate-audiobookshelf-abs-mobile-app
Translations update from Hosted Weblate
2025-01-23 04:12:43 -06:00
Jan-Eric MyhrgrenandHosted Weblate af516991a9 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-23 08:55:12 +01:00
Jan-Eric MyhrgrenandHosted Weblate 2cac88cf7c Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-23 08:49:26 +01:00
Milo IvirandHosted Weblate 1546a85195 Translated using Weblate (Croatian)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/hr/
2025-01-23 02:01:54 +01:00
LucasandHosted Weblate 9eba3e4dc4 Translated using Weblate (Spanish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/es/
2025-01-23 02:01:53 +01:00
akynrandHosted Weblate b568e2ecf1 Translated using Weblate (German)
Currently translated at 99.1% (337 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/de/
2025-01-23 02:01:53 +01:00
Lukas EßmannandHosted Weblate 9dce119530 Translated using Weblate (German)
Currently translated at 99.1% (337 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/de/
2025-01-23 02:01:53 +01:00
Andreas Morell-RengandHosted Weblate 24f9b134cd Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 13:07:16 +01:00
Andreas Morell-RengandHosted Weblate c3e6bdd73d Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 12:34:57 +01:00
Andreas Morell-RengandHosted Weblate 80e11c1492 Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 11:59:05 +01:00
Andreas Morell-RengandHosted Weblate bdebb4972e Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 11:59:00 +01:00
Andreas Morell-RengandHosted Weblate 9b5f9e00d9 Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 11:42:19 +01:00
Jan-Eric MyhrgrenandHosted Weblate 57167b8a10 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-21 11:41:37 +01:00
RaHoniandHosted Weblate 98889a0baf Translated using Weblate (German)
Currently translated at 97.9% (333 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/de/
2025-01-21 11:41:37 +01:00
Nicky LarstrupandHosted Weblate 0c535bb2d8 Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 11:41:37 +01:00
Andreas Morell-RengandHosted Weblate f4c34a3102 Translated using Weblate (Danish)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-21 11:41:37 +01:00
Nicky LarstrupandHosted Weblate 1f4b4d30ee Translated using Weblate (Danish)
Currently translated at 97.6% (332 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-20 15:13:32 +01:00
Jan-Eric MyhrgrenandHosted Weblate 1b1dc91c72 Translated using Weblate (Swedish)
Currently translated at 91.1% (310 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-20 15:12:53 +01:00
Petter Schaug-PettersenandHosted Weblate 5a6a76bd63 Translated using Weblate (Norwegian Bokmål)
Currently translated at 69.7% (237 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/nb_NO/
2025-01-20 15:12:53 +01:00
ugyesandHosted Weblate e5263f7719 Translated using Weblate (Hungarian)
Currently translated at 99.7% (339 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/hu/
2025-01-20 15:12:53 +01:00
Nicky LarstrupandHosted Weblate 267229f929 Translated using Weblate (Danish)
Currently translated at 97.6% (332 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/da/
2025-01-20 15:12:53 +01:00
Jan-Eric MyhrgrenandHosted Weblate 79ee8b09d6 Translated using Weblate (Swedish)
Currently translated at 90.8% (309 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-20 11:58:16 +01:00
thehijackerandHosted Weblate 7824693254 Translated using Weblate (Slovenian)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sl/
2025-01-20 11:56:48 +01:00
SunSpringandHosted Weblate 0b2319fbaa Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/zh_Hans/
2025-01-20 11:56:48 +01:00
Jan-Eric MyhrgrenandHosted Weblate dea3844090 Translated using Weblate (Swedish)
Currently translated at 90.5% (308 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-20 11:56:48 +01:00
Илья ЧервонныйandHosted Weblate be2c5759f2 Translated using Weblate (Russian)
Currently translated at 96.1% (327 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/ru/
2025-01-20 11:56:48 +01:00
J. LavoieandHosted Weblate c8b14d7822 Translated using Weblate (Italian)
Currently translated at 96.4% (328 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/it/
2025-01-20 11:56:48 +01:00
biuklijaandHosted Weblate 1b54016035 Translated using Weblate (Croatian)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/hr/
2025-01-20 11:56:48 +01:00
J. LavoieandHosted Weblate 50fe370585 Translated using Weblate (French)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fr/
2025-01-20 11:56:48 +01:00
J. LavoieandHosted Weblate e423ad168a Translated using Weblate (German)
Currently translated at 97.6% (332 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/de/
2025-01-20 11:56:48 +01:00
Vito0912andHosted Weblate 1d7670830c Translated using Weblate (German)
Currently translated at 97.6% (332 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/de/
2025-01-20 11:56:48 +01:00
LosicekandHosted Weblate d05dbfd5fb Translated using Weblate (Czech)
Currently translated at 96.4% (328 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/cs/
2025-01-20 11:56:47 +01:00
advplyr 7e3f1f1ffa Update issue template versions 2025-01-19 12:52:23 -06:00
advplyr 882ed1871a iOS version bump 0.9.78 2025-01-18 17:45:04 -06:00
advplyr 7c5c7d5632 Version bump v0.9.78-beta 2025-01-18 16:56:36 -06:00
advplyrandGitHub 240c0da577 Merge pull request #1438 from weblate/weblate-audiobookshelf-abs-mobile-app
Translations update from Hosted Weblate
2025-01-18 16:42:07 -06:00
Максим ГорпинічandHosted Weblate 7472ef01a8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (340 of 340 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:44 +00:00
Максим ГорпинічandHosted Weblate 9907095a2d Translated using Weblate (Ukrainian)
Currently translated at 100.0% (337 of 337 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:44 +00:00
Максим ГорпинічandHosted Weblate 658a527d93 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:43 +00:00
Максим ГорпинічandHosted Weblate 3d25f3dd62 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:42 +00:00
Bezruchenko SimonandHosted Weblate 6290e983e9 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:41 +00:00
Максим ГорпинічandHosted Weblate 10ae92ec41 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (333 of 333 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/uk/
2025-01-18 22:24:41 +00:00
Jan-Eric MyhrgrenandHosted Weblate 2c25286155 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:40 +00:00
Jan-Eric MyhrgrenandHosted Weblate 656ede98b6 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:40 +00:00
Kieli PuoliandHosted Weblate 5fb0118f60 Translated using Weblate (Finnish)
Currently translated at 88.5% (294 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fi/
2025-01-18 22:24:39 +00:00
Jan-Eric MyhrgrenandHosted Weblate 27e47b2b4b Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:39 +00:00
Kieli PuoliandHosted Weblate f02e3358aa Translated using Weblate (Finnish)
Currently translated at 88.2% (293 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fi/
2025-01-18 22:24:38 +00:00
Jan-Eric MyhrgrenandHosted Weblate 7caae3171c Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:38 +00:00
Kieli PuoliandHosted Weblate 0cded599b1 Translated using Weblate (Finnish)
Currently translated at 87.9% (292 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fi/
2025-01-18 22:24:37 +00:00
Kieli PuoliandHosted Weblate 4e48240158 Translated using Weblate (Finnish)
Currently translated at 87.6% (291 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fi/
2025-01-18 22:24:36 +00:00
Jan-Eric MyhrgrenandHosted Weblate b488e24798 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:36 +00:00
Jan-Eric MyhrgrenandHosted Weblate 7e7d87c147 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:35 +00:00
Jan-Eric MyhrgrenandHosted Weblate 8b6389cf3a Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:34 +00:00
Kieli PuoliandHosted Weblate 8a2725b48b Translated using Weblate (Finnish)
Currently translated at 83.7% (278 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/fi/
2025-01-18 22:24:34 +00:00
Jan-Eric MyhrgrenandHosted Weblate a7e8fe12f4 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:33 +00:00
Jan-Eric MyhrgrenandHosted Weblate 67a5473e27 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:33 +00:00
Jan-Eric MyhrgrenandHosted Weblate e16fba8eab Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:32 +00:00
Jan-Eric MyhrgrenandHosted Weblate cdfbafc789 Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:31 +00:00
Jan-Eric MyhrgrenandHosted Weblate c318f5d57b Translated using Weblate (Swedish)
Currently translated at 92.4% (307 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:30 +00:00
Jan-Eric MyhrgrenandHosted Weblate 556ab85b0d Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:30 +00:00
Jan-Eric MyhrgrenandHosted Weblate 20018aed27 Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:29 +00:00
Jan-Eric MyhrgrenandHosted Weblate e2facc87f0 Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:29 +00:00
Jan-Eric MyhrgrenandHosted Weblate 07e951039c Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:28 +00:00
Jan-Eric MyhrgrenandHosted Weblate 386d9ebc52 Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:28 +00:00
Jan-Eric MyhrgrenandHosted Weblate d8e058a416 Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:27 +00:00
Jan-Eric MyhrgrenandHosted Weblate f5d9c6076c Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:26 +00:00
Jan-Eric MyhrgrenandHosted Weblate e870855602 Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:26 +00:00
Jan-Eric MyhrgrenandHosted Weblate a3a6b4618b Translated using Weblate (Swedish)
Currently translated at 91.8% (305 of 332 strings)

Translation: Audiobookshelf/Abs Mobile App
Translate-URL: https://hosted.weblate.org/projects/audiobookshelf/abs-mobile-app/sv/
2025-01-18 22:24:25 +00:00
advplyr 3ecae3e16b Fix ereader settings scroll #1374 2025-01-18 16:24:18 -06:00
advplyr 111e8d38dc Remove token from image requests & fix download raw cover image #1328 2025-01-18 15:42:40 -06:00
advplyr d5fa36b11a Update error icon on audio player cover to show progress sync alert dialog when tapped #1396 2025-01-18 14:46:12 -06:00
advplyr a35c94cf03 Update numbers to use Intl.NumberFormat with selected locale #1427 2025-01-18 14:24:44 -06:00
advplyr b2eff46c38 Add # of episodes sort option for podcast libraries 2025-01-18 14:19:14 -06:00
advplyr 07c0187423 Update podcast items incomplete episodes display 2025-01-18 14:15:34 -06:00
advplyr 0074078539 Update server connections list to show warning for connections with an old user id #1411 2025-01-18 13:44:16 -06:00
advplyr d1641ac0e8 Update epub reader settings to be 75vh 2025-01-18 11:48:41 -06:00
advplyrandGitHub 13d3489cde Merge pull request #1439 from advplyr/reader-keep-screen-awake
Add epub reader setting to keep screen awake #1207
2025-01-18 11:37:52 -06:00
65 changed files with 760 additions and 390 deletions
+2 -2
View File
@@ -62,10 +62,10 @@ body:
description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.* description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.*
multiple: true multiple: true
options: options:
- Android App - 0.9.78
- iOS App - 0.9.78
- Android App - 0.9.77 - Android App - 0.9.77
- iOS App - 0.9.77 - iOS App - 0.9.77
- Android App - 0.9.76
- iOS App - 0.9.76
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
+2 -2
View File
@@ -43,10 +43,10 @@ body:
description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.* description: Please ensure your app is up to date. *If you are using a 3rd-party app, please reach out to them directly.*
multiple: true multiple: true
options: options:
- Android App - 0.9.78
- iOS App - 0.9.78
- Android App - 0.9.77 - Android App - 0.9.77
- iOS App - 0.9.77 - iOS App - 0.9.77
- Android App - 0.9.76
- iOS App - 0.9.76
validations: validations:
required: true required: true
- type: textarea - type: textarea
+2 -2
View File
@@ -36,8 +36,8 @@ android {
applicationId "com.audiobookshelf.app" applicationId "com.audiobookshelf.app"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 108 versionCode 110
versionName "0.9.77-beta" versionName "0.9.79-beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [ manifestPlaceholders = [
"appAuthRedirectScheme": "com.audiobookshelf.app" "appAuthRedirectScheme": "com.audiobookshelf.app"
@@ -1,133 +1,212 @@
package com.audiobookshelf.app.managers package com.audiobookshelf.app.managers
import android.content.Context import android.content.Context
import android.media.metrics.PlaybackSession
import android.os.* import android.os.*
import android.util.Log import android.util.Log
import com.audiobookshelf.app.device.DeviceManager import com.audiobookshelf.app.device.DeviceManager
import com.audiobookshelf.app.player.PlayerNotificationService import com.audiobookshelf.app.player.PlayerNotificationService
import com.audiobookshelf.app.player.SLEEP_TIMER_WAKE_UP_EXPIRATION import com.audiobookshelf.app.player.SLEEP_TIMER_WAKE_UP_EXPIRATION
import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
import kotlin.math.roundToInt import kotlin.math.roundToInt
class SleepTimerManager constructor(private val playerNotificationService: PlayerNotificationService) { class SleepTimerManager
constructor(private val playerNotificationService: PlayerNotificationService) {
private val tag = "SleepTimerManager" private val tag = "SleepTimerManager"
private var sleepTimerTask:TimerTask? = null private var sleepTimerTask: TimerTask? = null
private var sleepTimerRunning:Boolean = false private var sleepTimerRunning: Boolean = false
private var sleepTimerEndTime:Long = 0L private var sleepTimerEndTime: Long = 0L
private var sleepTimerLength:Long = 0L private var sleepTimerLength: Long = 0L
private var sleepTimerElapsed:Long = 0L private var sleepTimerElapsed: Long = 0L
private var sleepTimerFinishedAt:Long = 0L private var sleepTimerFinishedAt: Long = 0L
private var isAutoSleepTimer:Boolean = false // When timer was auto-set private var isAutoSleepTimer: Boolean = false // When timer was auto-set
private var isFirstAutoSleepTimer: Boolean = true private var autoTimerDisabled: Boolean = false // Disable until out of auto timer period
private var sleepTimerSessionId:String = "" private var sleepTimerSessionId: String = ""
private fun getCurrentTime():Long { /**
* Gets the current time from the player notification service.
* @return Long - the current time in milliseconds.
*/
private fun getCurrentTime(): Long {
return playerNotificationService.getCurrentTime() return playerNotificationService.getCurrentTime()
} }
private fun getDuration():Long { /**
* Gets the duration of the current playback.
* @return Long - the duration in milliseconds.
*/
private fun getDuration(): Long {
return playerNotificationService.getDuration() return playerNotificationService.getDuration()
} }
private fun getIsPlaying():Boolean { /**
* Checks if the player is currently playing.
* @return Boolean - true if the player is playing, false otherwise.
*/
private fun getIsPlaying(): Boolean {
return playerNotificationService.currentPlayer.isPlaying return playerNotificationService.currentPlayer.isPlaying
} }
private fun setVolume(volume:Float) { /**
* Gets the playback speed of the player.
* @return Float - the playback speed.
*/
private fun getPlaybackSpeed(): Float {
return playerNotificationService.currentPlayer.playbackParameters.speed
}
/**
* Sets the volume of the player.
* @param volume Float - the volume level to set.
*/
private fun setVolume(volume: Float) {
playerNotificationService.currentPlayer.volume = volume playerNotificationService.currentPlayer.volume = volume
} }
/** Pauses the player. */
private fun pause() { private fun pause() {
playerNotificationService.currentPlayer.pause() playerNotificationService.currentPlayer.pause()
} }
/** Plays the player. */
private fun play() { private fun play() {
playerNotificationService.currentPlayer.play() playerNotificationService.currentPlayer.play()
} }
private fun getSleepTimerTimeRemainingSeconds():Int { /**
* Gets the remaining time of the sleep timer in seconds.
* @param speed Float - the playback speed of the player, default value is 1.
* @return Int - the remaining time in seconds.
*/
private fun getSleepTimerTimeRemainingSeconds(speed: Float = 1f): Int {
if (sleepTimerEndTime == 0L && sleepTimerLength > 0) { // For regular timer if (sleepTimerEndTime == 0L && sleepTimerLength > 0) { // For regular timer
return ((sleepTimerLength - sleepTimerElapsed) / 1000).toDouble().roundToInt() return ((sleepTimerLength - sleepTimerElapsed) / 1000).toDouble().roundToInt()
} }
// For chapter end timer // For chapter end timer
if (sleepTimerEndTime <= 0) return 0 if (sleepTimerEndTime <= 0) return 0
return (((sleepTimerEndTime - getCurrentTime()) / 1000).toDouble()).roundToInt() return (((sleepTimerEndTime - getCurrentTime()) / 1000).toDouble() / speed).roundToInt()
} }
private fun setSleepTimer(time: Long, isChapterTime: Boolean) : Boolean { /**
Log.d(tag, "Setting Sleep Timer for $time is chapter time $isChapterTime") * Sets the sleep timer.
* @param time Long - the time to set the sleep timer for. When 0L, use end of chapter/track time.
* @return Boolean - true if the sleep timer was set successfully, false otherwise.
*/
private fun setSleepTimer(time: Long): Boolean {
Log.d(tag, "Setting Sleep Timer for $time")
sleepTimerTask?.cancel() sleepTimerTask?.cancel()
sleepTimerRunning = true sleepTimerRunning = true
sleepTimerFinishedAt = 0L sleepTimerFinishedAt = 0L
sleepTimerElapsed = 0L sleepTimerElapsed = 0L
setVolume(1f) setVolume(1f)
// Register shake sensor if (time == 0L) {
playerNotificationService.registerSensor() // Get the current chapter time and set the sleep timer to the end of the chapter
val chapterEndTime = this.getChapterEndTime()
val currentTime = getCurrentTime() if (chapterEndTime == null) {
if (isChapterTime) { Log.e(tag, "Setting sleep timer to end of chapter/track but there is no current session")
if (currentTime > time) {
Log.d(tag, "Invalid sleep timer - current time is already passed chapter time $time")
return false return false
} }
sleepTimerEndTime = time
sleepTimerLength = 0 val currentTime = getCurrentTime()
if (currentTime > chapterEndTime) {
Log.d(tag, "Invalid sleep timer - time is already past chapter time $chapterEndTime")
return false
}
sleepTimerEndTime = chapterEndTime
if (sleepTimerEndTime > getDuration()) { if (sleepTimerEndTime > getDuration()) {
sleepTimerEndTime = getDuration() sleepTimerEndTime = getDuration()
} }
} else { } else {
sleepTimerLength = time
sleepTimerEndTime = 0L sleepTimerEndTime = 0L
} }
playerNotificationService.clientEventEmitter?.onSleepTimerSet(getSleepTimerTimeRemainingSeconds(), isAutoSleepTimer) // Set sleep timer length. Will be 0L if using chapter end time
sleepTimerLength = time
sleepTimerTask = Timer("SleepTimer", false).schedule(0L, 1000L) { // Register shake sensor
Handler(Looper.getMainLooper()).post { playerNotificationService.registerSensor()
if (getIsPlaying()) {
sleepTimerElapsed += 1000L
val sleepTimeSecondsRemaining = getSleepTimerTimeRemainingSeconds() playerNotificationService.clientEventEmitter?.onSleepTimerSet(
Log.d(tag, "Timer Elapsed $sleepTimerElapsed | Sleep TIMER time remaining $sleepTimeSecondsRemaining s") getSleepTimerTimeRemainingSeconds(getPlaybackSpeed()),
isAutoSleepTimer
)
if (sleepTimeSecondsRemaining > 0) { sleepTimerTask =
playerNotificationService.clientEventEmitter?.onSleepTimerSet(sleepTimeSecondsRemaining, isAutoSleepTimer) Timer("SleepTimer", false).schedule(0L, 1000L) {
} Handler(Looper.getMainLooper()).post {
if (getIsPlaying()) {
sleepTimerElapsed += 1000L
if (sleepTimeSecondsRemaining <= 0) { val sleepTimeSecondsRemaining =
Log.d(tag, "Sleep Timer Pausing Player on Chapter") getSleepTimerTimeRemainingSeconds(getPlaybackSpeed())
pause() Log.d(
tag,
"Timer Elapsed $sleepTimerElapsed | Sleep TIMER time remaining $sleepTimeSecondsRemaining s"
)
playerNotificationService.clientEventEmitter?.onSleepTimerEnded(getCurrentTime()) if (sleepTimeSecondsRemaining > 0) {
clearSleepTimer() playerNotificationService.clientEventEmitter?.onSleepTimerSet(
sleepTimerFinishedAt = System.currentTimeMillis() sleepTimeSecondsRemaining,
} else if (sleepTimeSecondsRemaining <= 60 && DeviceManager.deviceData.deviceSettings?.disableSleepTimerFadeOut != true) { isAutoSleepTimer
// Start fading out audio down to 10% volume )
val percentToReduce = 1 - (sleepTimeSecondsRemaining / 60F) }
val volume = 1f - (percentToReduce * 0.9f)
Log.d(tag, "SLEEP VOLUME FADE $volume | ${sleepTimeSecondsRemaining}s remaining") if (sleepTimeSecondsRemaining <= 0) {
setVolume(volume) Log.d(tag, "Sleep Timer Pausing Player on Chapter")
} else { pause()
setVolume(1f)
} playerNotificationService.clientEventEmitter?.onSleepTimerEnded(
} getCurrentTime()
} )
} clearSleepTimer()
sleepTimerFinishedAt = System.currentTimeMillis()
} else if (sleepTimeSecondsRemaining <= 60 &&
DeviceManager.deviceData
.deviceSettings
?.disableSleepTimerFadeOut != true
) {
// Start fading out audio down to 10% volume
val percentToReduce = 1 - (sleepTimeSecondsRemaining / 60F)
val volume = 1f - (percentToReduce * 0.9f)
Log.d(
tag,
"SLEEP VOLUME FADE $volume | ${sleepTimeSecondsRemaining}s remaining"
)
setVolume(volume)
} else {
setVolume(1f)
}
}
}
}
return true return true
} }
fun setManualSleepTimer(playbackSessionId:String, time: Long, isChapterTime:Boolean):Boolean { /**
* Sets a manual sleep timer.
* @param playbackSessionId String - the playback session ID.
* @param time Long - the time to set the sleep timer for.
* @param isChapterTime Boolean - true if the time is for the end of a chapter, false otherwise.
* @return Boolean - true if the sleep timer was set successfully, false otherwise.
*/
fun setManualSleepTimer(playbackSessionId: String, time: Long, isChapterTime: Boolean): Boolean {
sleepTimerSessionId = playbackSessionId sleepTimerSessionId = playbackSessionId
isAutoSleepTimer = false isAutoSleepTimer = false
return setSleepTimer(time, isChapterTime) if (isChapterTime) {
Log.d(tag, "Setting manual sleep timer for end of chapter")
return setSleepTimer(0L)
} else {
Log.d(tag, "Setting manual sleep timer for $time")
return setSleepTimer(time)
}
} }
/** Clears the sleep timer. */
private fun clearSleepTimer() { private fun clearSleepTimer() {
sleepTimerTask?.cancel() sleepTimerTask?.cancel()
sleepTimerTask = null sleepTimerTask = null
@@ -138,32 +217,36 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
setVolume(1f) setVolume(1f)
} }
fun getSleepTimerTime():Long { /**
* Gets the sleep timer end time.
* @return Long - the sleep timer end time in milliseconds.
*/
fun getSleepTimerTime(): Long {
return sleepTimerEndTime return sleepTimerEndTime
} }
/** Cancels the sleep timer. */
fun cancelSleepTimer() { fun cancelSleepTimer() {
Log.d(tag, "Canceling Sleep Timer") Log.d(tag, "Canceling Sleep Timer")
if (isAutoSleepTimer) { if (isAutoSleepTimer) {
Log.i(tag, "Disabling auto sleep timer") Log.i(tag, "Disabling auto sleep timer for this time period")
DeviceManager.deviceData.deviceSettings?.autoSleepTimer = false autoTimerDisabled = true
DeviceManager.dbManager.saveDeviceData(DeviceManager.deviceData)
} }
clearSleepTimer() clearSleepTimer()
playerNotificationService.clientEventEmitter?.onSleepTimerSet(0, false) playerNotificationService.clientEventEmitter?.onSleepTimerSet(0, false)
} }
// Vibrate when resetting sleep timer /** Provides vibration feedback when resetting the sleep timer. */
private fun vibrateFeedback() { private fun vibrateFeedback() {
if (DeviceManager.deviceData.deviceSettings?.disableSleepTimerResetFeedback == true) return if (DeviceManager.deviceData.deviceSettings?.disableSleepTimerResetFeedback == true) return
val context = playerNotificationService.getContext() val context = playerNotificationService.getContext()
val vibrator:Vibrator val vibrator: Vibrator
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val vibratorManager = val vibratorManager =
context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibrator = vibratorManager.defaultVibrator vibrator = vibratorManager.defaultVibrator
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -172,18 +255,20 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
vibrator.let { vibrator.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val vibrationEffect = VibrationEffect.createWaveform(longArrayOf(0, 150, 150, 150),-1) val vibrationEffect = VibrationEffect.createWaveform(longArrayOf(0, 150, 150, 150), -1)
it.vibrate(vibrationEffect) it.vibrate(vibrationEffect)
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION") it.vibrate(10)
it.vibrate(10)
} }
} }
} }
// Get the chapter end time for use in End of Chapter timers /**
// if less than 2s remain in chapter then use the next chapter * Gets the chapter end time for use in End of Chapter timers. If less than 2 seconds remain in
private fun getChapterEndTime():Long? { * the chapter, then use the next chapter.
* @return Long? - the chapter end time in milliseconds, or null if there is no current session.
*/
private fun getChapterEndTime(): Long? {
val currentChapterEndTimeMs = playerNotificationService.getEndTimeOfChapterOrTrack() val currentChapterEndTimeMs = playerNotificationService.getEndTimeOfChapterOrTrack()
if (currentChapterEndTimeMs == null) { if (currentChapterEndTimeMs == null) {
Log.e(tag, "Getting chapter sleep timer end of chapter/track but there is no current session") Log.e(tag, "Getting chapter sleep timer end of chapter/track but there is no current session")
@@ -195,7 +280,10 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
Log.i(tag, "Getting chapter sleep timer time and current chapter has less than 2s remaining") Log.i(tag, "Getting chapter sleep timer time and current chapter has less than 2s remaining")
val nextChapterEndTimeMs = playerNotificationService.getEndTimeOfNextChapterOrTrack() val nextChapterEndTimeMs = playerNotificationService.getEndTimeOfNextChapterOrTrack()
if (nextChapterEndTimeMs == null || currentChapterEndTimeMs == nextChapterEndTimeMs) { if (nextChapterEndTimeMs == null || currentChapterEndTimeMs == nextChapterEndTimeMs) {
Log.e(tag, "Invalid next chapter time. No current session or equal to current chapter. $nextChapterEndTimeMs") Log.e(
tag,
"Invalid next chapter time. No current session or equal to current chapter. $nextChapterEndTimeMs"
)
null null
} else { } else {
nextChapterEndTimeMs nextChapterEndTimeMs
@@ -205,17 +293,35 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
} }
} }
private fun resetChapterTimer() { /**
this.getChapterEndTime()?.let { chapterEndTime -> * Rewind auto sleep timer if setting enabled. To ensure the first rewind of the time period does
Log.d(tag, "Resetting stopped sleep timer to end of chapter $chapterEndTime") * not take place, make sure to set `isAutoSleepTimer` after calling this function.
vibrateFeedback() */
setSleepTimer(chapterEndTime, true) private fun tryRewindAutoSleepTimer() {
play() DeviceManager.deviceData.deviceSettings?.let { deviceSettings ->
if (isAutoSleepTimer && deviceSettings.autoSleepTimerAutoRewind) {
Log.i(
tag,
"Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms"
)
playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime)
}
} }
} }
/** Checks if the sleep timer should be reset. */
private fun checkShouldResetSleepTimer() { private fun checkShouldResetSleepTimer() {
if (!sleepTimerRunning) { if (sleepTimerRunning) {
// Reset the sleep timer if it has been running for at least 3 seconds or it is an end of
// chapter/track timer
if (sleepTimerLength == 0L || sleepTimerElapsed > 3000L) {
Log.d(tag, "Resetting running sleep timer")
vibrateFeedback()
setSleepTimer(sleepTimerLength)
play()
}
} else {
if (sleepTimerFinishedAt <= 0L) return if (sleepTimerFinishedAt <= 0L) return
val finishedAtDistance = System.currentTimeMillis() - sleepTimerFinishedAt val finishedAtDistance = System.currentTimeMillis() - sleepTimerFinishedAt
@@ -226,49 +332,18 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
return return
} }
// Automatically Rewind in the book if settings is enabled // Automatically rewind in the book if settings are enabled
if (isAutoSleepTimer) { tryRewindAutoSleepTimer()
DeviceManager.deviceData.deviceSettings?.let { deviceSettings ->
if (deviceSettings.autoSleepTimerAutoRewind && !isFirstAutoSleepTimer) {
Log.i(tag, "Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms")
playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime)
}
isFirstAutoSleepTimer = false
}
}
// Set sleep timer // Set sleep timer
// When sleepTimerLength is 0 then use end of chapter/track time Log.d(tag, "Resetting stopped sleep timer")
if (sleepTimerLength == 0L) {
Log.d(tag, "Resetting stopped chapter sleep timer")
resetChapterTimer()
} else {
Log.d(tag, "Resetting stopped sleep timer to length $sleepTimerLength")
vibrateFeedback()
setSleepTimer(sleepTimerLength, false)
play()
}
return
}
// Does not apply to chapter sleep timers and timer must be running for at least 3 seconds
if (sleepTimerLength > 0L && sleepTimerElapsed > 3000L) {
Log.d(tag, "Resetting running sleep timer to length $sleepTimerLength")
vibrateFeedback() vibrateFeedback()
setSleepTimer(sleepTimerLength, false) setSleepTimer(sleepTimerLength)
} else if (sleepTimerLength == 0L) { play()
// When navigating to previous chapters make sure this is still the end of the current chapter
this.getChapterEndTime()?.let { chapterEndTime ->
if (chapterEndTime != sleepTimerEndTime) {
Log.d(tag, "Resetting chapter sleep timer to end of chapter $chapterEndTime from $sleepTimerEndTime")
vibrateFeedback()
setSleepTimer(chapterEndTime, true)
play()
}
}
} }
} }
/** Handles the shake event to reset the sleep timer. */
fun handleShake() { fun handleShake() {
if (sleepTimerRunning || sleepTimerFinishedAt > 0L) { if (sleepTimerRunning || sleepTimerFinishedAt > 0L) {
if (DeviceManager.deviceData.deviceSettings?.disableShakeToResetSleepTimer == true) { if (DeviceManager.deviceData.deviceSettings?.disableShakeToResetSleepTimer == true) {
@@ -279,48 +354,63 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
} }
} }
/**
* Increases the sleep timer time.
* @param time Long - the time to increase the sleep timer by.
*/
fun increaseSleepTime(time: Long) { fun increaseSleepTime(time: Long) {
Log.d(tag, "Increase Sleep time $time") Log.d(tag, "Increase Sleep time $time")
if (!sleepTimerRunning) return if (!sleepTimerRunning) return
// Increase the sleep timer time (if using fixed length) or end time (if using chapter end time)
// and ensure it doesn't go over the duration of the current playback item
if (sleepTimerEndTime == 0L) { if (sleepTimerEndTime == 0L) {
// Fixed length
sleepTimerLength += time sleepTimerLength += time
if (sleepTimerLength + getCurrentTime() > getDuration()) sleepTimerLength = getDuration() - getCurrentTime() sleepTimerLength = minOf(sleepTimerLength, getDuration() - getCurrentTime())
} else { } else {
val newSleepEndTime = sleepTimerEndTime + time // Chapter end time
sleepTimerEndTime = if (newSleepEndTime >= getDuration()) { sleepTimerEndTime =
getDuration() minOf(sleepTimerEndTime + (time * getPlaybackSpeed()).roundToInt(), getDuration())
} else {
newSleepEndTime
}
} }
setVolume(1F) setVolume(1F)
playerNotificationService.clientEventEmitter?.onSleepTimerSet(getSleepTimerTimeRemainingSeconds(), isAutoSleepTimer) playerNotificationService.clientEventEmitter?.onSleepTimerSet(
getSleepTimerTimeRemainingSeconds(getPlaybackSpeed()),
isAutoSleepTimer
)
} }
/**
* Decreases the sleep timer time.
* @param time Long - the time to decrease the sleep timer by.
*/
fun decreaseSleepTime(time: Long) { fun decreaseSleepTime(time: Long) {
Log.d(tag, "Decrease Sleep time $time") Log.d(tag, "Decrease Sleep time $time")
if (!sleepTimerRunning) return if (!sleepTimerRunning) return
// Decrease the sleep timer time (if using fixed length) or end time (if using chapter end time)
// and ensure it doesn't go below 1 second
if (sleepTimerEndTime == 0L) { if (sleepTimerEndTime == 0L) {
sleepTimerLength -= time // Fixed length
if (sleepTimerLength <= 0) sleepTimerLength = 1000L sleepTimerLength = maxOf(sleepTimerLength - time, 1000L)
} else { } else {
val newSleepEndTime = sleepTimerEndTime - time // Chapter end time
sleepTimerEndTime = if (newSleepEndTime <= 1000) { sleepTimerEndTime =
// End sleep timer in 1 second maxOf(
getCurrentTime() + 1000 sleepTimerEndTime - (time * getPlaybackSpeed()).roundToInt(),
} else { getCurrentTime() + 1000
newSleepEndTime )
}
} }
setVolume(1F) setVolume(1F)
playerNotificationService.clientEventEmitter?.onSleepTimerSet(getSleepTimerTimeRemainingSeconds(), isAutoSleepTimer) playerNotificationService.clientEventEmitter?.onSleepTimerSet(
getSleepTimerTimeRemainingSeconds(getPlaybackSpeed()),
isAutoSleepTimer
)
} }
/** Checks whether the auto sleep timer should be set, and set up auto sleep timer if so. */
fun checkAutoSleepTimer() { fun checkAutoSleepTimer() {
if (sleepTimerRunning) { // Sleep timer already running if (sleepTimerRunning) { // Sleep timer already running
return return
@@ -337,10 +427,13 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
val currentCalendar = Calendar.getInstance() val currentCalendar = Calendar.getInstance()
// In cases where end time is before start time then we shift the time window forward or backward based on the current time. // In cases where end time is before start time then we shift the time window forward or
// backward based on the current time.
// e.g. start time 22:00 and end time 06:00. // e.g. start time 22:00 and end time 06:00.
// If current time is less than start time (e.g. 00:30) then start time will be the previous day. // If current time is less than start time (e.g. 00:30) then start time will be the
// If current time is greater than start time (e.g. 23:00) then end time will be the next day. // previous day.
// If current time is greater than start time (e.g. 23:00) then end time will be the
// next day.
if (endCalendar.before(startCalendar)) { if (endCalendar.before(startCalendar)) {
if (currentCalendar.before(startCalendar)) { // Shift start back a day if (currentCalendar.before(startCalendar)) { // Shift start back a day
startCalendar.add(Calendar.DAY_OF_MONTH, -1) startCalendar.add(Calendar.DAY_OF_MONTH, -1)
@@ -349,47 +442,52 @@ class SleepTimerManager constructor(private val playerNotificationService: Playe
} }
} }
val currentHour = SimpleDateFormat("HH:mm", Locale.getDefault()).format(currentCalendar.time) val isDuringAutoTime =
if (currentCalendar.after(startCalendar) && currentCalendar.before(endCalendar)) { currentCalendar.after(startCalendar) && currentCalendar.before(endCalendar)
Log.i(tag, "Current hour $currentHour is between ${deviceSettings.autoSleepTimerStartTime} and ${deviceSettings.autoSleepTimerEndTime} - starting sleep timer")
// Automatically Rewind in the book if settings is enabled // Determine whether to set the auto sleep timer or not
if (deviceSettings.autoSleepTimerAutoRewind && !isFirstAutoSleepTimer) { if (autoTimerDisabled) {
Log.i(tag, "Auto sleep timer auto rewind seeking back ${deviceSettings.autoSleepTimerAutoRewindTime}ms") if (!isDuringAutoTime) {
playerNotificationService.seekBackward(deviceSettings.autoSleepTimerAutoRewindTime) // Check if sleep timer was disabled during the previous period and enable again
} Log.i(tag, "Leaving disabled auto sleep time period, enabling for next time period")
isFirstAutoSleepTimer = false autoTimerDisabled = false
// Set sleep timer
// When sleepTimerLength is 0 then use end of chapter/track time
if (deviceSettings.sleepTimerLength == 0L) {
val chapterEndTimeMs = this.getChapterEndTime()
if (chapterEndTimeMs == null) {
Log.e(tag, "Setting auto sleep timer to end of chapter/track but there is no current session")
} else {
isAutoSleepTimer = true
setSleepTimer(chapterEndTimeMs, true)
}
} else { } else {
isAutoSleepTimer = true // Auto time is disabled, do not set sleep timer
setSleepTimer(deviceSettings.sleepTimerLength, false) Log.i(tag, "Auto sleep timer is disabled for this time period")
} }
} else { } else {
isFirstAutoSleepTimer = true if (isDuringAutoTime) {
Log.d(tag, "Current hour $currentHour is NOT between ${deviceSettings.autoSleepTimerStartTime} and ${deviceSettings.autoSleepTimerEndTime}") // Start an auto sleep timer
val currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY)
val currentMin = currentCalendar.get(Calendar.MINUTE)
Log.i(tag, "Starting sleep timer at $currentHour:$currentMin")
// Automatically rewind in the book if settings is enabled
tryRewindAutoSleepTimer()
// Set `isAutoSleepTimer` to true to indicate that the timer was set automatically
// and to not cause the timer to rewind
isAutoSleepTimer = true
setSleepTimer(deviceSettings.sleepTimerLength)
} else {
Log.d(tag, "Not in auto sleep time period")
}
} }
} }
} }
fun handleMediaPlayEvent(playbackSessionId:String) { /**
* Handles the media play event and checks if the sleep timer should be reset or set.
* @param playbackSessionId String - the playback session ID.
*/
fun handleMediaPlayEvent(playbackSessionId: String) {
// Check if the playback session has changed // Check if the playback session has changed
// If it hasn't changed OR the sleep timer is running then check reset the timer // If it hasn't changed OR the sleep timer is running then check reset the timer
// e.g. You set a manual sleep timer for 10 mins, then decide to change books, the sleep timer will stay on and reset to 10 mins // e.g. You set a manual sleep timer for 10 mins, then decide to change books, the sleep timer
// will stay on and reset to 10 mins
if (sleepTimerSessionId == playbackSessionId || sleepTimerRunning) { if (sleepTimerSessionId == playbackSessionId || sleepTimerRunning) {
checkShouldResetSleepTimer() checkShouldResetSleepTimer()
} else { } else {}
isFirstAutoSleepTimer = true
}
sleepTimerSessionId = playbackSessionId sleepTimerSessionId = playbackSessionId
checkAutoSleepTimer() checkAutoSleepTimer()
@@ -42,7 +42,10 @@ data class DownloadItemPart(
val finalDestinationUri = Uri.fromFile(finalDestinationFile) val finalDestinationUri = Uri.fromFile(finalDestinationFile)
var downloadUrl = "${DeviceManager.serverAddress}${serverPath}?token=${DeviceManager.token}" var downloadUrl = "${DeviceManager.serverAddress}${serverPath}?token=${DeviceManager.token}"
if (serverPath.endsWith("/cover")) downloadUrl += "&format=jpeg&raw=1" // For cover images force to jpeg if (serverPath.endsWith("/cover")) {
downloadUrl += "&raw=1" // Download raw cover image
}
val downloadUri = Uri.parse(downloadUrl) val downloadUri = Uri.parse(downloadUrl)
Log.d("DownloadItemPart", "Audio File Destination Uri: $destinationUri | Final Destination Uri: $finalDestinationUri | Download URI $downloadUri") Log.d("DownloadItemPart", "Audio File Destination Uri: $destinationUri | Final Destination Uri: $finalDestinationUri | Download URI $downloadUri")
return DownloadItemPart( return DownloadItemPart(
@@ -77,7 +80,7 @@ data class DownloadItemPart(
val isInternalStorage get() = localFolderId.startsWith("internal-") val isInternalStorage get() = localFolderId.startsWith("internal-")
@get:JsonIgnore @get:JsonIgnore
val serverUrl get() = "${DeviceManager.serverAddress}${serverPath}?token=${DeviceManager.token}" val serverUrl get() = uri.toString()
@JsonIgnore @JsonIgnore
fun getDownloadRequest(): DownloadManager.Request { fun getDownloadRequest(): DownloadManager.Request {
@@ -988,7 +988,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
// //
// MEDIA BROWSER STUFF (ANDROID AUTO) // MEDIA BROWSER STUFF (ANDROID AUTO)
// //
private val VALID_MEDIA_BROWSERS = mutableListOf("com.audiobookshelf.app", "com.audiobookshelf.app.debug", "com.android.systemui", ANDROID_AUTO_PKG_NAME, ANDROID_AUTO_SIMULATOR_PKG_NAME, ANDROID_WEARABLE_PKG_NAME, ANDROID_GSEARCH_PKG_NAME, ANDROID_AUTOMOTIVE_PKG_NAME) private val VALID_MEDIA_BROWSERS = mutableListOf("com.audiobookshelf.app", "com.audiobookshelf.app.debug", ANDROID_AUTO_PKG_NAME, ANDROID_AUTO_SIMULATOR_PKG_NAME, ANDROID_WEARABLE_PKG_NAME, ANDROID_GSEARCH_PKG_NAME, ANDROID_AUTOMOTIVE_PKG_NAME)
private val AUTO_MEDIA_ROOT = "/" private val AUTO_MEDIA_ROOT = "/"
private val LIBRARIES_ROOT = "__LIBRARIES__" private val LIBRARIES_ROOT = "__LIBRARIES__"
@@ -1015,7 +1015,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
// No further calls will be made to other media browsing methods. // No further calls will be made to other media browsing methods.
null null
} else { } else {
Log.d(tag, "Android Auto starting") Log.d(tag, "Android Auto starting $clientPackageName $clientUid")
isStarted = true isStarted = true
// Reset cache if no longer connected to server or server changed // Reset cache if no longer connected to server or server changed
+13 -1
View File
@@ -52,4 +52,16 @@
text-indent: 0px !important; text-indent: 0px !important;
text-align: start !important; text-align: start !important;
text-align-last: start !important; text-align-last: start !important;
} }
.default-style.less-spacing p {
margin-block-start: 0;
}
.default-style.less-spacing ul {
margin-block-start: 0;
}
.default-style.less-spacing ol {
margin-block-start: 0;
}
+9 -1
View File
@@ -35,7 +35,7 @@
<covers-book-cover v-if="libraryItem || localLibraryItemCoverSrc" ref="cover" :library-item="libraryItem" :download-cover="localLibraryItemCoverSrc" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" raw @imageLoaded="coverImageLoaded" /> <covers-book-cover v-if="libraryItem || localLibraryItemCoverSrc" ref="cover" :library-item="libraryItem" :download-cover="localLibraryItemCoverSrc" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" raw @imageLoaded="coverImageLoaded" />
</div> </div>
<div v-if="syncStatus === $constants.SyncStatus.FAILED" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-30"> <div v-if="syncStatus === $constants.SyncStatus.FAILED" class="absolute top-0 left-0 w-full h-full flex items-center justify-center z-30" @click.stop="showSyncsFailedDialog">
<span class="material-icons text-error text-3xl">error</span> <span class="material-icons text-error text-3xl">error</span>
</div> </div>
</div> </div>
@@ -107,6 +107,7 @@
<script> <script>
import { Capacitor } from '@capacitor/core' import { Capacitor } from '@capacitor/core'
import { AbsAudioPlayer } from '@/plugins/capacitor' import { AbsAudioPlayer } from '@/plugins/capacitor'
import { Dialog } from '@capacitor/dialog'
import { FastAverageColor } from 'fast-average-color' import { FastAverageColor } from 'fast-average-color'
import WrappingMarquee from '@/assets/WrappingMarquee.js' import WrappingMarquee from '@/assets/WrappingMarquee.js'
@@ -390,6 +391,13 @@ export default {
} }
}, },
methods: { methods: {
showSyncsFailedDialog() {
Dialog.alert({
title: this.$strings.HeaderProgressSyncFailed,
message: this.$strings.MessageProgressSyncFailed,
cancelText: this.$strings.ButtonOk
})
},
clickChaptersBtn() { clickChaptersBtn() {
if (!this.chapters.length) return if (!this.chapters.length) return
this.showChapterModal = true this.showChapterModal = true
-3
View File
@@ -42,9 +42,6 @@ export default {
} }
}, },
computed: { computed: {
userToken() {
return this.$store.getters['user/getToken']
},
_author() { _author() {
return this.author || {} return this.author || {}
}, },
+3 -3
View File
@@ -67,7 +67,7 @@
</div> </div>
<!-- Error widget --> <!-- Error widget -->
<div v-if="showError" :style="{ height: 1.5 * sizeMultiplier + 'rem', width: 2.5 * sizeMultiplier + 'rem' }" class="bg-error rounded-r-full shadow-md flex items-center justify-end border-r border-b border-red-300"> <div v-if="showError" :style="{ height: 1.5 * sizeMultiplier + 'rem', width: 2.5 * sizeMultiplier + 'rem' }" class="bg-error rounded-r-full shadow-md flex items-center justify-end border-r border-b border-red-300 absolute bottom-4 left-0 z-10">
<span class="material-icons text-red-100 pr-1" :style="{ fontSize: 0.875 * sizeMultiplier + 'rem' }">priority_high</span> <span class="material-icons text-red-100 pr-1" :style="{ fontSize: 0.875 * sizeMultiplier + 'rem' }">priority_high</span>
</div> </div>
@@ -94,8 +94,8 @@
</div> </div>
<!-- Podcast Num Episodes Incomplete --> <!-- Podcast Num Episodes Incomplete -->
<div v-else-if="numEpisodesIncomplete && !isSelectionMode" class="absolute rounded-full bg-black bg-opacity-90 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }"> <div v-else-if="numEpisodesIncomplete && !isSelectionMode" class="absolute rounded-full bg-yellow-400 box-shadow-md z-10 flex items-center justify-center" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', width: 1.25 * sizeMultiplier + 'rem', height: 1.25 * sizeMultiplier + 'rem' }">
<p class="text-white" :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">{{ numEpisodesIncomplete }}</p> <p class="text-black" :style="{ fontSize: sizeMultiplier * 0.8 + 'rem' }">{{ numEpisodesIncomplete }}</p>
</div> </div>
</div> </div>
</template> </template>
+14 -7
View File
@@ -21,7 +21,13 @@
<p class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displayAuthor }}</p> <p class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displayAuthor }}</p>
<p v-if="displaySortLine" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displaySortLine }}</p> <p v-if="displaySortLine" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ displaySortLine }}</p>
<p v-if="duration" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ $elapsedPretty(duration) }}</p> <p v-if="duration" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ $elapsedPretty(duration) }}</p>
<p v-if="episodes" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">{{ episodes }}</p>
<p v-if="numEpisodesIncomplete" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">
{{ $getString('LabelNumEpisodesIncomplete', [numEpisodes, numEpisodesIncomplete]) }}
</p>
<p v-else-if="numEpisodes" class="truncate text-fg-muted" :style="{ fontSize: 0.7 * sizeMultiplier + 'rem' }">
{{ $getString('LabelNumEpisodes', [numEpisodes]) }}
</p>
</div> </div>
<div v-if="localLibraryItem || isLocal" class="absolute top-0 right-0 z-20" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }"> <div v-if="localLibraryItem || isLocal" class="absolute top-0 right-0 z-20" :style="{ top: 0.375 * sizeMultiplier + 'rem', right: 0.375 * sizeMultiplier + 'rem', padding: `${0.1 * sizeMultiplier}rem ${0.25 * sizeMultiplier}rem` }">
@@ -106,12 +112,13 @@ export default {
isPodcast() { isPodcast() {
return this.mediaType === 'podcast' return this.mediaType === 'podcast'
}, },
episodes() { numEpisodes() {
if (this.isPodcast) { if (this.isLocal && this.isPodcast && this.media.episodes) return this.media.episodes.length
return this.$getString('LabelNumEpisodes', [this.media.numEpisodes]) return this.media.numEpisodes
} else { },
return null numEpisodesIncomplete() {
} if (this.isLocal) return 0
return this._libraryItem.numEpisodesIncomplete || 0
}, },
placeholderUrl() { placeholderUrl() {
return '/book_placeholder.jpg' return '/book_placeholder.jpg'
+22 -5
View File
@@ -3,12 +3,19 @@
<div v-show="!loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg px-4 py-6 w-full"> <div v-show="!loggedIn" class="mt-8 bg-primary overflow-hidden shadow rounded-lg px-4 py-6 w-full">
<!-- list of server connection configs --> <!-- list of server connection configs -->
<template v-if="!showForm"> <template v-if="!showForm">
<div v-for="config in serverConnectionConfigs" :key="config.id" class="flex items-center py-4 my-1 border-b border-fg/10 relative" @click="connectToServer(config)"> <div v-for="config in serverConnectionConfigs" :key="config.id" class="border-b border-fg/10 py-4">
<span class="material-icons-outlined text-xl text-fg-muted">dns</span> <div class="flex items-center my-1 relative" @click="connectToServer(config)">
<p class="pl-3 pr-6 text-base text-fg">{{ config.name }}</p> <span class="material-icons-outlined text-xl text-fg-muted">dns</span>
<p class="pl-3 pr-6 text-base text-fg">{{ config.name }}</p>
<div class="absolute top-0 right-0 h-full px-4 flex items-center" @click.stop="editServerConfig(config)"> <div class="absolute top-0 right-0 h-full px-4 flex items-center" @click.stop="editServerConfig(config)">
<span class="material-icons text-lg text-fg-muted">more_vert</span> <span class="material-icons text-lg text-fg-muted">more_vert</span>
</div>
</div>
<!-- warning message if server connection config is using an old user id -->
<div v-if="!checkIdUuid(config.userId)" class="flex flex-nowrap justify-between items-center space-x-4 pt-4">
<p class="text-xs text-warning">{{ $strings.MessageOldServerConnectionWarning }}</p>
<ui-btn class="text-xs whitespace-nowrap" :padding-x="2" :padding-y="1" @click="showOldUserIdWarningDialog">{{ $strings.LabelMoreInfo }}</ui-btn>
</div> </div>
</div> </div>
<div class="my-1 py-4 w-full"> <div class="my-1 py-4 w-full">
@@ -141,6 +148,16 @@ export default {
} }
}, },
methods: { methods: {
showOldUserIdWarningDialog() {
Dialog.alert({
title: 'Old Server Connection Warning',
message: this.$strings.MessageOldServerConnectionWarningHelp,
cancelText: this.$strings.ButtonOk
})
},
checkIdUuid(userId) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId)
},
/** /**
* Initiates the login process using OpenID via OAuth2.0. * Initiates the login process using OpenID via OAuth2.0.
* 1. Verifying the server's address * 1. Verifying the server's address
+6 -5
View File
@@ -39,9 +39,6 @@ export default {
} }
}, },
computed: { computed: {
userToken() {
return this.$store.getters['user/getToken']
},
_author() { _author() {
return this.author || {} return this.author || {}
}, },
@@ -59,11 +56,15 @@ export default {
}, },
imgSrc() { imgSrc() {
if (!this.imagePath || !this.serverAddress) return null if (!this.imagePath || !this.serverAddress) return null
const urlQuery = new URLSearchParams({ ts: this.updatedAt })
if (this.$store.getters.getDoesServerImagesRequireToken) {
urlQuery.append('token', this.$store.getters['user/getToken'])
}
if (process.env.NODE_ENV !== 'production' && this.serverAddress.startsWith('http://192.168')) { if (process.env.NODE_ENV !== 'production' && this.serverAddress.startsWith('http://192.168')) {
// Testing // Testing
return `http://localhost:3333/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}` return `http://localhost:3333/api/authors/${this.authorId}/image?${urlQuery.toString()}`
} }
return `${this.serverAddress}/api/authors/${this.authorId}/image?token=${this.userToken}&ts=${this.updatedAt}` return `${this.serverAddress}/api/authors/${this.authorId}/image?${urlQuery.toString()}`
} }
}, },
methods: { methods: {
-3
View File
@@ -141,9 +141,6 @@ export default {
}, },
authorBottom() { authorBottom() {
return 0.75 * this.sizeMultiplier return 0.75 * this.sizeMultiplier
},
userToken() {
return this.$store.getters['user/getToken']
} }
}, },
methods: { methods: {
+2 -2
View File
@@ -2,8 +2,8 @@
<div class="w-full h-9 bg-bg relative z-20"> <div class="w-full h-9 bg-bg relative z-20">
<div id="bookshelf-toolbar" class="absolute top-0 left-0 w-full h-full z-20 flex items-center px-2"> <div id="bookshelf-toolbar" class="absolute top-0 left-0 w-full h-full z-20 flex items-center px-2">
<div class="flex items-center w-full text-sm"> <div class="flex items-center w-full text-sm">
<p v-show="!selectedSeriesName" class="pt-1">{{ totalEntities }} {{ entityTitle }}</p> <p v-show="!selectedSeriesName" class="pt-1">{{ $formatNumber(totalEntities) }} {{ entityTitle }}</p>
<p v-show="selectedSeriesName" class="ml-2 pt-1">{{ selectedSeriesName }} ({{ totalEntities }})</p> <p v-show="selectedSeriesName" class="ml-2 pt-1">{{ selectedSeriesName }} ({{ $formatNumber(totalEntities) }})</p>
<div class="flex-grow" /> <div class="flex-grow" />
<span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="changeView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span> <span v-if="page == 'library' || seriesBookPage" class="material-icons px-2" @click="changeView">{{ !bookshelfListView ? 'view_list' : 'grid_view' }}</span>
<template v-if="page === 'library'"> <template v-if="page === 'library'">
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<div ref="wrapper" class="modal modal-bg w-screen fixed bottom-0 left-0 flex items-center justify-center z-50" :class="halfScreen ? 'h-[50vh] min-h-[400px]' : 'h-screen'" @click.stop @touchstart.stop @touchend.stop> <div ref="wrapper" class="modal modal-bg w-screen fixed bottom-0 left-0 flex items-center justify-center z-50" :class="threeQuartersScreen ? 'h-[75vh] min-h-[400px]' : 'h-screen'" @click.stop @touchstart.stop @touchend.stop>
<div ref="content" class="relative text-fg h-full w-full bg-bg"> <div ref="content" class="relative text-fg h-full w-full bg-bg">
<slot /> <slot />
</div> </div>
@@ -11,7 +11,7 @@ export default {
props: { props: {
value: Boolean, value: Boolean,
processing: Boolean, processing: Boolean,
halfScreen: Boolean threeQuartersScreen: Boolean
}, },
data() { data() {
return { return {
+4
View File
@@ -86,6 +86,10 @@ export default {
text: this.$strings.LabelSize, text: this.$strings.LabelSize,
value: 'size' value: 'size'
}, },
{
text: this.$strings.LabelNumberOfEpisodes,
value: 'media.numTracks'
},
{ {
text: this.$strings.LabelFileBirthtime, text: this.$strings.LabelFileBirthtime,
value: 'birthtimeMs' value: 'birthtimeMs'
+5 -1
View File
@@ -85,7 +85,11 @@ export default {
return [5, 10, 15, 30, 45, 60, 90] return [5, 10, 15, 30, 45, 60, 90]
}, },
timeRemainingPretty() { timeRemainingPretty() {
if (this.currentTime <= 0) return '0:00'
return this.$secondsToTimestamp(this.currentTime) return this.$secondsToTimestamp(this.currentTime)
},
isIos() {
return this.$platform === 'ios'
} }
}, },
methods: { methods: {
@@ -105,7 +109,7 @@ export default {
if (this.isAuto) { if (this.isAuto) {
const { value } = await Dialog.confirm({ const { value } = await Dialog.confirm({
title: 'Confirm', title: 'Confirm',
message: 'Are you sure you want to disable the auto sleep timer? You will need to enable this again in settings.' message: this.$strings.MessageConfirmDisableAutoTimer
}) })
if (!value) return if (!value) return
} }
+4 -4
View File
@@ -54,15 +54,15 @@
</modals-fullscreen-modal> </modals-fullscreen-modal>
<!-- ereader settings modal --> <!-- ereader settings modal -->
<modals-fullscreen-modal v-model="showSettingsModal" :theme="ereaderTheme"> <modals-fullscreen-modal v-model="showSettingsModal" :theme="ereaderTheme" threeQuartersScreen>
<div style="box-shadow: 0px -8px 8px #11111155"> <div style="box-shadow: 0px -8px 8px #11111155">
<div class="flex items-end justify-between h-20 px-4 pb-2 mb-6"> <div class="flex items-end justify-between h-14 px-4 pb-2 mb-6">
<h1 class="text-lg">{{ $strings.HeaderEreaderSettings }}</h1> <h1 class="text-lg">{{ $strings.HeaderEreaderSettings }}</h1>
<button class="flex" @click="showSettingsModal = false"> <button class="flex" @click="showSettingsModal = false">
<span class="material-icons">close</span> <span class="material-icons">close</span>
</button> </button>
</div> </div>
<div class="w-full overflow-y-auto overflow-x-hidden h-full max-h-[calc(100vh-85px)]"> <div class="w-full overflow-y-auto overflow-x-hidden h-full max-h-[calc(75vh-85px)]">
<div class="w-full h-full px-4"> <div class="w-full h-full px-4">
<div class="flex items-center mb-6"> <div class="flex items-center mb-6">
<div class="w-32"> <div class="w-32">
@@ -106,7 +106,7 @@
</div> </div>
<ui-toggle-btns v-model="ereaderSettings.navigateWithVolumeWhilePlaying" name="navigate-volume-playing" :items="onOffToggleButtonItems" @input="settingsUpdated" /> <ui-toggle-btns v-model="ereaderSettings.navigateWithVolumeWhilePlaying" name="navigate-volume-playing" :items="onOffToggleButtonItems" @input="settingsUpdated" />
</div> </div>
<div class="flex items-center"> <div class="flex items-center mb-6">
<div class="w-32"> <div class="w-32">
<p class="text-sm">{{ $strings.LabelKeepScreenAwake }}</p> <p class="text-sm">{{ $strings.LabelKeepScreenAwake }}</p>
</div> </div>
+4 -4
View File
@@ -33,22 +33,22 @@
<div class="flex justify-between pt-12"> <div class="flex justify-between pt-12">
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ totalMinutesListeningThisWeek }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(totalMinutesListeningThisWeek) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ averageMinutesPerDay }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(averageMinutesPerDay) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ mostListenedDay }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(mostListenedDay) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ daysInARow }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(daysInARow) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p>
</div> </div>
</div> </div>
+22 -3
View File
@@ -6,7 +6,7 @@
</div> </div>
<div class="book-table-content h-full px-2 flex items-center"> <div class="book-table-content h-full px-2 flex items-center">
<div class="max-w-full"> <div class="max-w-full">
<p class="truncate block text-sm">{{ bookTitle }}</p> <p class="truncate block text-sm">{{ bookTitle }} <span v-if="localLibraryItem" class="material-icons text-success text-base align-text-bottom">download_done</span></p>
<p class="truncate block text-fg-muted text-xs">{{ bookAuthor }}</p> <p class="truncate block text-fg-muted text-xs">{{ bookAuthor }}</p>
<p v-if="media.duration" class="text-xxs text-fg-muted">{{ bookDuration }}</p> <p v-if="media.duration" class="text-xxs text-fg-muted">{{ bookDuration }}</p>
</div> </div>
@@ -39,6 +39,9 @@ export default {
libraryItemId() { libraryItemId() {
return this.book.id return this.book.id
}, },
localLibraryItem() {
return this.book.localLibraryItem
},
media() { media() {
return this.book.media || {} return this.book.media || {}
}, },
@@ -73,18 +76,34 @@ export default {
showPlayBtn() { showPlayBtn() {
return !this.isMissing && !this.isInvalid && this.tracks.length return !this.isMissing && !this.isInvalid && this.tracks.length
}, },
isStreaming() { playerIsStartingPlayback() {
// Play has been pressed and waiting for native play response
return this.$store.state.playerIsStartingPlayback
},
isOpenInPlayer() {
if (this.localLibraryItem && this.$store.getters['getIsMediaStreaming'](this.localLibraryItem.id)) return true
return this.$store.getters['getIsMediaStreaming'](this.libraryItemId) return this.$store.getters['getIsMediaStreaming'](this.libraryItemId)
}, },
streamIsPlaying() { streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming return this.$store.state.playerIsPlaying && this.isOpenInPlayer
} }
}, },
methods: { methods: {
async playClick() { async playClick() {
if (this.playerIsStartingPlayback) return
await this.$hapticsImpact() await this.$hapticsImpact()
if (this.streamIsPlaying) { if (this.streamIsPlaying) {
this.$eventBus.$emit('pause-item') this.$eventBus.$emit('pause-item')
return
}
this.$store.commit('setPlayerIsStartingPlayback', this.libraryItemId)
if (this.localLibraryItem) {
this.$eventBus.$emit('play-item', {
libraryItemId: this.localLibraryItem.id,
serverLibraryItemId: this.libraryItemId
})
} else { } else {
this.$eventBus.$emit('play-item', { this.$eventBus.$emit('play-item', {
libraryItemId: this.libraryItemId libraryItemId: this.libraryItemId
@@ -50,9 +50,6 @@ export default {
libraryItemId() { libraryItemId() {
return this.libraryItem.id return this.libraryItem.id
}, },
userToken() {
return this.$store.getters['user/getToken']
},
ebookFiles() { ebookFiles() {
return (this.libraryItem.libraryFiles || []).filter((lf) => lf.fileType === 'ebook') return (this.libraryItem.libraryFiles || []).filter((lf) => lf.fileType === 'ebook')
}, },
@@ -24,9 +24,6 @@ export default {
return {} return {}
}, },
computed: { computed: {
userToken() {
return this.$store.getters['user/getToken']
},
userCanUpdate() { userCanUpdate() {
return this.$store.getters['user/getUserCanUpdate'] return this.$store.getters['user/getUserCanUpdate']
}, },
+2 -2
View File
@@ -113,12 +113,12 @@ export default {
showPlayBtn() { showPlayBtn() {
return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode) return !this.isMissing && !this.isInvalid && (this.tracks.length || this.episode)
}, },
isStreaming() { isOpenInPlayer() {
if (this.localLibraryItem && this.localEpisode && this.$store.getters['getIsMediaStreaming'](this.localLibraryItem.id, this.localEpisode.id)) return true if (this.localLibraryItem && this.localEpisode && this.$store.getters['getIsMediaStreaming'](this.localLibraryItem.id, this.localEpisode.id)) return true
return this.$store.getters['getIsMediaStreaming'](this.libraryItem.id, this.episodeId) return this.$store.getters['getIsMediaStreaming'](this.libraryItem.id, this.episodeId)
}, },
streamIsPlaying() { streamIsPlaying() {
return this.$store.state.playerIsPlaying && this.isStreaming return this.$store.state.playerIsPlaying && this.isOpenInPlayer
}, },
playerIsStartingPlayback() { playerIsStartingPlayback() {
// Play has been pressed and waiting for native play response // Play has been pressed and waiting for native play response
@@ -278,6 +278,7 @@ export default {
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, episode.id) return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId, episode.id)
}, },
init() { init() {
this.sortDesc = this.mediaMetadata.type === 'episodic'
this.episodesCopy = this.episodes.map((ep) => { this.episodesCopy = this.episodes.map((ep) => {
return { ...ep } return { ...ep }
}) })
+4 -4
View File
@@ -744,12 +744,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icons; ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 34; CURRENT_PROJECT_VERSION = 36;
DEVELOPMENT_TEAM = 7UFJ7D8V6A; DEVELOPMENT_TEAM = 7UFJ7D8V6A;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.9.77; MARKETING_VERSION = 0.9.79;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev; PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app.dev;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -768,12 +768,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = Icons; ASSETCATALOG_COMPILER_APPICON_NAME = Icons;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 34; CURRENT_PROJECT_VERSION = 36;
DEVELOPMENT_TEAM = 7UFJ7D8V6A; DEVELOPMENT_TEAM = 7UFJ7D8V6A;
INFOPLIST_FILE = App/Info.plist; INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.9.77; MARKETING_VERSION = 0.9.79;
PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app; PRODUCT_BUNDLE_IDENTIFIER = com.audiobookshelf.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-app", "name": "audiobookshelf-app",
"version": "0.9.77-beta", "version": "0.9.79-beta",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-app", "name": "audiobookshelf-app",
"version": "0.9.77-beta", "version": "0.9.79-beta",
"dependencies": { "dependencies": {
"@byteowls/capacitor-filesharer": "^6.0.0", "@byteowls/capacitor-filesharer": "^6.0.0",
"@capacitor-community/keep-awake": "^5.0.1", "@capacitor-community/keep-awake": "^5.0.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-app", "name": "audiobookshelf-app",
"version": "0.9.77-beta", "version": "0.9.79-beta",
"author": "advplyr", "author": "advplyr",
"scripts": { "scripts": {
"dev": "nuxt --hostname 0.0.0.0 --port 1337", "dev": "nuxt --hostname 0.0.0.0 --port 1337",
+42 -11
View File
@@ -12,9 +12,9 @@
{{ collectionName }} {{ collectionName }}
</h1> </h1>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn v-if="showPlayButton" :disabled="streaming" color="success" :padding-x="4" small :loading="playerIsStartingForThisMedia" class="flex items-center justify-center h-9 mr-2 w-24" @click="clickPlay"> <ui-btn v-if="showPlayButton" color="success" :padding-x="4" :loading="playerIsStartingForThisMedia" small class="flex items-center justify-center mx-1 w-24" @click="playClick">
<span v-show="!streaming" class="material-icons -ml-2 pr-1 text-white">play_arrow</span> <span class="material-icons">{{ playerIsPlaying ? 'pause' : 'play_arrow' }}</span>
{{ streaming ? $strings.ButtonPlaying : $strings.ButtonPlay }} <span class="px-1 text-sm">{{ playerIsPlaying ? $strings.ButtonPause : $strings.ButtonPlay }}</span>
</ui-btn> </ui-btn>
</div> </div>
@@ -47,6 +47,18 @@ export default {
return redirect('/bookshelf') return redirect('/bookshelf')
} }
// Lookup matching local items and attach to collection items
if (collection.books.length) {
const localLibraryItems = (await app.$db.getLocalLibraryItems('book')) || []
if (localLibraryItems.length) {
collection.books.forEach((collectionItem) => {
const matchingLocalLibraryItem = localLibraryItems.find((lli) => lli.libraryItemId === collectionItem.id)
if (!matchingLocalLibraryItem) return
collectionItem.localLibraryItem = matchingLocalLibraryItem
})
}
}
return { return {
collection collection
} }
@@ -70,13 +82,19 @@ export default {
description() { description() {
return this.collection.description || '' return this.collection.description || ''
}, },
playableBooks() { playableItems() {
return this.bookItems.filter((book) => { return this.bookItems.filter((book) => {
return !book.isMissing && !book.isInvalid && book.media.tracks.length return !book.isMissing && !book.isInvalid && book.media.tracks.length
}) })
}, },
streaming() { playerIsPlaying() {
return !!this.playableBooks.find((b) => this.$store.getters['getIsMediaStreaming'](b.id)) return this.$store.state.playerIsPlaying && this.isOpenInPlayer
},
isOpenInPlayer() {
return !!this.playableItems.find((i) => {
if (i.localLibraryItem && this.$store.getters['getIsMediaStreaming'](i.localLibraryItem.id)) return true
return this.$store.getters['getIsMediaStreaming'](i.id)
})
}, },
playerIsStartingPlayback() { playerIsStartingPlayback() {
// Play has been pressed and waiting for native play response // Play has been pressed and waiting for native play response
@@ -88,21 +106,34 @@ export default {
return mediaId === this.mediaIdStartingPlayback return mediaId === this.mediaIdStartingPlayback
}, },
showPlayButton() { showPlayButton() {
return this.playableBooks.length return this.playableItems.length
} }
}, },
methods: { methods: {
clickPlay() { async playClick() {
if (this.playerIsStartingPlayback) return if (this.playerIsStartingPlayback) return
await this.$hapticsImpact()
var nextBookNotRead = this.playableBooks.find((pb) => { if (this.playerIsPlaying) {
var prog = this.$store.getters['user/getUserMediaProgress'](pb.id) this.$eventBus.$emit('pause-item')
} else {
this.playNextItem()
}
},
playNextItem() {
const nextBookNotRead = this.playableItems.find((pb) => {
const prog = this.$store.getters['user/getUserMediaProgress'](pb.id)
return !prog?.isFinished return !prog?.isFinished
}) })
if (nextBookNotRead) { if (nextBookNotRead) {
this.mediaIdStartingPlayback = nextBookNotRead.id this.mediaIdStartingPlayback = nextBookNotRead.id
this.$store.commit('setPlayerIsStartingPlayback', nextBookNotRead.id) this.$store.commit('setPlayerIsStartingPlayback', nextBookNotRead.id)
this.$eventBus.$emit('play-item', { libraryItemId: nextBookNotRead.id })
if (nextBookNotRead.localLibraryItem) {
this.$eventBus.$emit('play-item', { libraryItemId: nextBookNotRead.localLibraryItem.id, serverLibraryItemId: nextBookNotRead.id })
} else {
this.$eventBus.$emit('play-item', { libraryItemId: nextBookNotRead.id })
}
} }
} }
}, },
+12 -4
View File
@@ -68,6 +68,10 @@
<span class="material-icons">more_vert</span> <span class="material-icons">more_vert</span>
</ui-btn> </ui-btn>
</div> </div>
<ui-btn v-else-if="isMissing" color="error" :padding-x="4" small class="mt-4 flex items-center justify-center w-full" @click="clickMissingButton">
<span class="material-icons">error</span>
<span class="px-1 text-base">{{ $strings.LabelMissing }}</span>
</ui-btn>
<div v-if="!isPodcast && progressPercent > 0" class="px-4 py-2 bg-primary text-sm font-semibold rounded-md text-fg mt-4 text-center"> <div v-if="!isPodcast && progressPercent > 0" class="px-4 py-2 bg-primary text-sm font-semibold rounded-md text-fg mt-4 text-center">
<p>{{ $strings.LabelYourProgress }}: {{ Math.round(progressPercent * 100) }}%</p> <p>{{ $strings.LabelYourProgress }}: {{ Math.round(progressPercent * 100) }}%</p>
@@ -135,7 +139,7 @@
</div> </div>
<div v-if="description" class="w-full py-2"> <div v-if="description" class="w-full py-2">
<p ref="description" class="text-sm text-justify whitespace-pre-line font-light" :class="{ 'line-clamp-4': !showFullDescription }" style="hyphens: auto">{{ description }}</p> <div ref="description" class="default-style less-spacing text-sm text-justify whitespace-pre-line font-light" :class="{ 'line-clamp-4': !showFullDescription }" style="hyphens: auto" v-html="description" />
<div v-if="descriptionClamped" class="text-fg text-sm py-2" @click="showFullDescription = !showFullDescription"> <div v-if="descriptionClamped" class="text-fg text-sm py-2" @click="showFullDescription = !showFullDescription">
{{ showFullDescription ? $strings.ButtonReadLess : $strings.ButtonReadMore }} {{ showFullDescription ? $strings.ButtonReadLess : $strings.ButtonReadMore }}
@@ -366,9 +370,6 @@ export default {
user() { user() {
return this.$store.state.user.user return this.$store.state.user.user
}, },
userToken() {
return this.$store.getters['user/getToken']
},
userItemProgress() { userItemProgress() {
if (this.isPodcast) return null if (this.isPodcast) return null
if (this.isLocal) return this.localItemProgress if (this.isLocal) return this.localItemProgress
@@ -489,6 +490,13 @@ export default {
} }
}, },
methods: { methods: {
clickMissingButton() {
Dialog.alert({
title: this.$strings.LabelMissing,
message: this.$strings.MessageItemMissing,
cancelText: this.$strings.ButtonOk
})
},
async coverImageLoaded(fullCoverUrl) { async coverImageLoaded(fullCoverUrl) {
if (!fullCoverUrl) return if (!fullCoverUrl) return
+18 -5
View File
@@ -10,9 +10,9 @@
{{ playlistName }} {{ playlistName }}
</h1> </h1>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn v-if="showPlayButton" :disabled="streaming" color="success" :padding-x="4" :loading="playerIsStartingForThisMedia" small class="flex items-center justify-center text-center h-9 mr-2 w-24" @click="clickPlay"> <ui-btn v-if="showPlayButton" color="success" :padding-x="4" :loading="playerIsStartingForThisMedia" small class="flex items-center justify-center mx-1 w-24" @click="playClick">
<span v-show="!streaming" class="material-icons -ml-2 pr-1 text-white">play_arrow</span> <span class="material-icons">{{ playerIsPlaying ? 'pause' : 'play_arrow' }}</span>
{{ streaming ? $strings.ButtonPlaying : $strings.ButtonPlay }} <span class="px-1 text-sm">{{ playerIsPlaying ? $strings.ButtonPause : $strings.ButtonPlay }}</span>
</ui-btn> </ui-btn>
</div> </div>
@@ -101,7 +101,10 @@ export default {
return libraryItem.media.tracks.length return libraryItem.media.tracks.length
}) })
}, },
streaming() { playerIsPlaying() {
return this.$store.state.playerIsPlaying && this.isOpenInPlayer
},
isOpenInPlayer() {
return !!this.playableItems.find((i) => { return !!this.playableItems.find((i) => {
if (i.localLibraryItem && this.$store.getters['getIsMediaStreaming'](i.localLibraryItem.id, i.localEpisode?.id)) return true if (i.localLibraryItem && this.$store.getters['getIsMediaStreaming'](i.localLibraryItem.id, i.localEpisode?.id)) return true
return this.$store.getters['getIsMediaStreaming'](i.libraryItemId, i.episodeId) return this.$store.getters['getIsMediaStreaming'](i.libraryItemId, i.episodeId)
@@ -126,7 +129,17 @@ export default {
this.selectedEpisode = playlistItem.episode this.selectedEpisode = playlistItem.episode
this.showMoreMenu = true this.showMoreMenu = true
}, },
clickPlay() { async playClick() {
if (this.playerIsStartingPlayback) return
await this.$hapticsImpact()
if (this.playerIsPlaying) {
this.$eventBus.$emit('pause-item')
} else {
this.playNextItem()
}
},
playNextItem() {
const nextItem = this.playableItems.find((i) => { const nextItem = this.playableItems.find((i) => {
const prog = this.$store.getters['user/getUserMediaProgress'](i.libraryItemId, i.episodeId) const prog = this.$store.getters['user/getUserMediaProgress'](i.libraryItemId, i.episodeId)
return !prog?.isFinished return !prog?.isFinished
+3 -3
View File
@@ -10,21 +10,21 @@
<div class="flex text-center justify-center"> <div class="flex text-center justify-center">
<div class="flex p-2"> <div class="flex p-2">
<div class="px-3"> <div class="px-3">
<p class="text-4xl md:text-5xl font-bold">{{ userItemsFinished.length }}</p> <p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(userItemsFinished.length) }}</p>
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsItemsFinished }}</p> <p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsItemsFinished }}</p>
</div> </div>
</div> </div>
<div class="flex p-2"> <div class="flex p-2">
<div class="px-1"> <div class="px-1">
<p class="text-4xl md:text-5xl font-bold">{{ totalDaysListened }}</p> <p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(totalDaysListened) }}</p>
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsDaysListened }}</p> <p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsDaysListened }}</p>
</div> </div>
</div> </div>
<div class="flex p-2"> <div class="flex p-2">
<div class="px-1"> <div class="px-1">
<p class="text-4xl md:text-5xl font-bold">{{ totalMinutesListening }}</p> <p class="text-4xl md:text-5xl font-bold">{{ $formatNumber(totalMinutesListening) }}</p>
<p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsMinutesListening }}</p> <p class="text-xs md:text-sm text-fg-muted">{{ $strings.LabelStatsMinutesListening }}</p>
</div> </div>
</div> </div>
+4
View File
@@ -62,6 +62,10 @@ Vue.prototype.$getString = (key, subs) => {
return Vue.prototype.$strings[key] return Vue.prototype.$strings[key]
} }
Vue.prototype.$formatNumber = (num) => {
return Intl.NumberFormat(Vue.prototype.$languageCodes.current).format(num)
}
var translations = { var translations = {
[defaultCode]: enUsStrings [defaultCode]: enUsStrings
} }
+74 -56
View File
@@ -44,62 +44,80 @@ export const state = () => ({
}) })
export const getters = { export const getters = {
getDownloadItem: state => (libraryItemId, episodeId = null) => { getDownloadItem:
return state.itemDownloads.find(i => { (state) =>
// if (episodeId && !i.episodes.some(e => e.id == episodeId)) return false (libraryItemId, episodeId = null) => {
if (episodeId && i.episodeId !== episodeId) return false return state.itemDownloads.find((i) => {
return i.libraryItemId == libraryItemId // if (episodeId && !i.episodes.some(e => e.id == episodeId)) return false
}) if (episodeId && i.episodeId !== episodeId) return false
}, return i.libraryItemId == libraryItemId
getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder, raw = false) => { })
if (!libraryItem) return placeholder },
const media = libraryItem.media getLibraryItemCoverSrc:
if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder (state, getters, rootState, rootGetters) =>
(libraryItem, placeholder, raw = false) => {
if (!libraryItem) return placeholder
const media = libraryItem.media
if (!media || !media.coverPath || media.coverPath === placeholder) return placeholder
// Absolute URL covers (should no longer be used) // Absolute URL covers (should no longer be used)
if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath if (media.coverPath.startsWith('http:') || media.coverPath.startsWith('https:')) return media.coverPath
const userToken = rootGetters['user/getToken'] const serverAddress = rootGetters['user/getServerAddress']
const serverAddress = rootGetters['user/getServerAddress'] if (!serverAddress) return placeholder
if (!userToken || !serverAddress) return placeholder
const lastUpdate = libraryItem.updatedAt || Date.now() const lastUpdate = libraryItem.updatedAt || Date.now()
if (process.env.NODE_ENV !== 'production') { // Testing if (process.env.NODE_ENV !== 'production') {
// return `http://localhost:3333/api/items/${libraryItem.id}/cover?token=${userToken}&ts=${lastUpdate}` // Testing
} // return `http://localhost:3333/api/items/${libraryItem.id}/cover?ts=${lastUpdate}`
}
const url = new URL(`${serverAddress}/api/items/${libraryItem.id}/cover`) const url = new URL(`${serverAddress}/api/items/${libraryItem.id}/cover`)
return `${url}?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}` const urlQuery = new URLSearchParams()
}, urlQuery.append('ts', lastUpdate)
getLibraryItemCoverSrcById: (state, getters, rootState, rootGetters) => (libraryItemId, placeholder = null) => { if (raw) urlQuery.append('raw', '1')
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg` if (rootGetters.getDoesServerImagesRequireToken) {
if (!libraryItemId) return placeholder urlQuery.append('token', rootGetters['user/getToken'])
const userToken = rootGetters['user/getToken'] }
const serverAddress = rootGetters['user/getServerAddress'] return `${url}?${urlQuery}`
if (!userToken || !serverAddress) return placeholder },
getLibraryItemCoverSrcById:
(state, getters, rootState, rootGetters) =>
(libraryItemId, placeholder = null) => {
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
if (!libraryItemId) return placeholder
const serverAddress = rootGetters['user/getServerAddress']
if (!serverAddress) return placeholder
const url = new URL(`${serverAddress}/api/items/${libraryItemId}/cover`) const url = new URL(`${serverAddress}/api/items/${libraryItemId}/cover`)
return `${url}?token=${userToken}` if (rootGetters.getDoesServerImagesRequireToken) {
}, return `${url}?token=${rootGetters['user/getToken']}`
getLocalMediaProgressById: (state) => (localLibraryItemId, episodeId = null) => { }
return state.localMediaProgress.find(lmp => { return url.toString()
if (episodeId != null && lmp.localEpisodeId != episodeId) return false },
return lmp.localLibraryItemId == localLibraryItemId getLocalMediaProgressById:
}) (state) =>
}, (localLibraryItemId, episodeId = null) => {
getLocalMediaProgressByServerItemId: (state) => (libraryItemId, episodeId = null) => { return state.localMediaProgress.find((lmp) => {
return state.localMediaProgress.find(lmp => { if (episodeId != null && lmp.localEpisodeId != episodeId) return false
if (episodeId != null && lmp.episodeId != episodeId) return false return lmp.localLibraryItemId == localLibraryItemId
return lmp.libraryItemId == libraryItemId })
}) },
}, getLocalMediaProgressByServerItemId:
getJumpForwardIcon: state => (jumpForwardTime) => { (state) =>
const item = state.jumpForwardItems.find(i => i.value == jumpForwardTime) (libraryItemId, episodeId = null) => {
return state.localMediaProgress.find((lmp) => {
if (episodeId != null && lmp.episodeId != episodeId) return false
return lmp.libraryItemId == libraryItemId
})
},
getJumpForwardIcon: (state) => (jumpForwardTime) => {
const item = state.jumpForwardItems.find((i) => i.value == jumpForwardTime)
return item ? item.icon : 'forward_10' return item ? item.icon : 'forward_10'
}, },
getJumpBackwardsIcon: state => (jumpBackwardsTime) => { getJumpBackwardsIcon: (state) => (jumpBackwardsTime) => {
const item = state.jumpBackwardsItems.find(i => i.value == jumpBackwardsTime) const item = state.jumpBackwardsItems.find((i) => i.value == jumpBackwardsTime)
return item ? item.icon : 'replay_10' return item ? item.icon : 'replay_10'
} }
} }
@@ -116,7 +134,7 @@ export const mutations = {
state.isModalOpen = val state.isModalOpen = val
}, },
addUpdateItemDownload(state, downloadItem) { addUpdateItemDownload(state, downloadItem) {
var index = state.itemDownloads.findIndex(i => i.id == downloadItem.id) var index = state.itemDownloads.findIndex((i) => i.id == downloadItem.id)
if (index >= 0) { if (index >= 0) {
state.itemDownloads.splice(index, 1, downloadItem) state.itemDownloads.splice(index, 1, downloadItem)
} else { } else {
@@ -124,7 +142,7 @@ export const mutations = {
} }
}, },
updateDownloadItemPart(state, downloadItemPart) { updateDownloadItemPart(state, downloadItemPart) {
const downloadItem = state.itemDownloads.find(i => i.id == downloadItemPart.downloadItemId) const downloadItem = state.itemDownloads.find((i) => i.id == downloadItemPart.downloadItemId)
if (!downloadItem) { if (!downloadItem) {
console.error('updateDownloadItemPart: Download item not found for itemPart', JSON.stringify(downloadItemPart)) console.error('updateDownloadItemPart: Download item not found for itemPart', JSON.stringify(downloadItemPart))
return return
@@ -132,7 +150,7 @@ export const mutations = {
let totalBytes = 0 let totalBytes = 0
let totalBytesDownloaded = 0 let totalBytesDownloaded = 0
downloadItem.downloadItemParts = downloadItem.downloadItemParts.map(dip => { downloadItem.downloadItemParts = downloadItem.downloadItemParts.map((dip) => {
let newDip = dip.id == downloadItemPart.id ? downloadItemPart : dip let newDip = dip.id == downloadItemPart.id ? downloadItemPart : dip
totalBytes += newDip.completed ? Number(newDip.bytesDownloaded) : Number(newDip.fileSize) totalBytes += newDip.completed ? Number(newDip.bytesDownloaded) : Number(newDip.fileSize)
@@ -149,7 +167,7 @@ export const mutations = {
} }
}, },
removeItemDownload(state, id) { removeItemDownload(state, id) {
state.itemDownloads = state.itemDownloads.filter(i => i.id != id) state.itemDownloads = state.itemDownloads.filter((i) => i.id != id)
}, },
setBookshelfListView(state, val) { setBookshelfListView(state, val) {
state.bookshelfListView = val state.bookshelfListView = val
@@ -164,7 +182,7 @@ export const mutations = {
if (!prog || !prog.id) { if (!prog || !prog.id) {
return return
} }
var index = state.localMediaProgress.findIndex(lmp => lmp.id == prog.id) var index = state.localMediaProgress.findIndex((lmp) => lmp.id == prog.id)
if (index >= 0) { if (index >= 0) {
state.localMediaProgress.splice(index, 1, prog) state.localMediaProgress.splice(index, 1, prog)
} else { } else {
@@ -172,10 +190,10 @@ export const mutations = {
} }
}, },
removeLocalMediaProgress(state, id) { removeLocalMediaProgress(state, id) {
state.localMediaProgress = state.localMediaProgress.filter(lmp => lmp.id != id) state.localMediaProgress = state.localMediaProgress.filter((lmp) => lmp.id != id)
}, },
removeLocalMediaProgressForItem(state, llid) { removeLocalMediaProgressForItem(state, llid) {
state.localMediaProgress = state.localMediaProgress.filter(lmp => lmp.localLibraryItemId !== llid) state.localMediaProgress = state.localMediaProgress.filter((lmp) => lmp.localLibraryItemId !== llid)
}, },
setLastSearch(state, val) { setLastSearch(state, val) {
state.lastSearch = val state.lastSearch = val
@@ -203,4 +221,4 @@ export const mutations = {
state.rssFeedEntity = entity state.rssFeedEntity = entity
state.showRSSFeedOpenCloseModal = true state.showRSSFeedOpenCloseModal = true
} }
} }
+14
View File
@@ -85,6 +85,20 @@ export const getters = {
getCanStreamingUsingCellular: (state) => { getCanStreamingUsingCellular: (state) => {
if (!state.deviceData?.deviceSettings?.streamingUsingCellular) return 'ALWAYS' if (!state.deviceData?.deviceSettings?.streamingUsingCellular) return 'ALWAYS'
return state.deviceData.deviceSettings.streamingUsingCellular || 'ALWAYS' return state.deviceData.deviceSettings.streamingUsingCellular || 'ALWAYS'
},
/**
* Old server versions require a token for images
*
* @param {*} state
* @returns {boolean} True if server version is less than 2.17
*/
getDoesServerImagesRequireToken: (state) => {
const serverVersion = state.serverSettings?.version
if (!serverVersion) return false
const versionParts = serverVersion.split('.')
const majorVersion = parseInt(versionParts[0])
const minorVersion = parseInt(versionParts[1])
return majorVersion < 2 || (majorVersion == 2 && minorVersion < 17)
} }
} }
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "تَوَقَّف", "ButtonPause": "تَوَقَّف",
"ButtonPlay": "تشغيل", "ButtonPlay": "تشغيل",
"ButtonPlayEpisode": "شغل الحلقة", "ButtonPlayEpisode": "شغل الحلقة",
"ButtonPlaying": "مشغل الآن",
"ButtonPlaylists": "قوائم التشغيل", "ButtonPlaylists": "قوائم التشغيل",
"ButtonRead": "اقرأ", "ButtonRead": "اقرأ",
"ButtonReadLess": "قلص", "ButtonReadLess": "قلص",
-1
View File
@@ -29,7 +29,6 @@
"ButtonNextEpisode": "Наступны эпізод", "ButtonNextEpisode": "Наступны эпізод",
"ButtonOpenFeed": "Адкрыць стужку", "ButtonOpenFeed": "Адкрыць стужку",
"ButtonPause": "Паўза", "ButtonPause": "Паўза",
"ButtonPlaying": "Прайграваецца",
"ButtonPlaylists": "Плэйлісты", "ButtonPlaylists": "Плэйлісты",
"ButtonRemoveFromServer": "Выдаліць з сервера", "ButtonRemoveFromServer": "Выдаліць з сервера",
"ButtonSave": "Захаваць", "ButtonSave": "Захаваць",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "বিরতি", "ButtonPause": "বিরতি",
"ButtonPlay": "বাজান", "ButtonPlay": "বাজান",
"ButtonPlayEpisode": "পর্বটি চালান", "ButtonPlayEpisode": "পর্বটি চালান",
"ButtonPlaying": "বাজছে",
"ButtonPlaylists": "প্লেলিস্ট", "ButtonPlaylists": "প্লেলিস্ট",
"ButtonRead": "পড়ুন", "ButtonRead": "পড়ুন",
"ButtonReadLess": "কম পড়ুন", "ButtonReadLess": "কম পড়ুন",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "Pausa", "ButtonPause": "Pausa",
"ButtonPlay": "Reproduir", "ButtonPlay": "Reproduir",
"ButtonPlayEpisode": "Reproduir episodi", "ButtonPlayEpisode": "Reproduir episodi",
"ButtonPlaying": "Reproduint",
"ButtonPlaylists": "Llistes de reproducció", "ButtonPlaylists": "Llistes de reproducció",
"ButtonRead": "Llegir", "ButtonRead": "Llegir",
"ButtonReadLess": "Llig menys", "ButtonReadLess": "Llig menys",
+4 -2
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Spravovat místní soubory", "ButtonManageLocalFiles": "Spravovat místní soubory",
"ButtonNewFolder": "Nová složka", "ButtonNewFolder": "Nová složka",
"ButtonNextEpisode": "Další epizoda", "ButtonNextEpisode": "Další epizoda",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Otevřít kanál", "ButtonOpenFeed": "Otevřít kanál",
"ButtonOverride": "Přepsat", "ButtonOverride": "Přepsat",
"ButtonPause": "Pozastavit", "ButtonPause": "Pozastavit",
"ButtonPlay": "Přehrát", "ButtonPlay": "Přehrát",
"ButtonPlayEpisode": "Přehrát epizodu", "ButtonPlayEpisode": "Přehrát epizodu",
"ButtonPlaying": "Hraje",
"ButtonPlaylists": "Seznamy skladeb", "ButtonPlaylists": "Seznamy skladeb",
"ButtonRead": "Číst", "ButtonRead": "Číst",
"ButtonReadLess": "Číst méně", "ButtonReadLess": "Číst méně",
@@ -54,6 +54,7 @@
"ButtonYes": "Ano", "ButtonYes": "Ano",
"HeaderAccount": "Účet", "HeaderAccount": "Účet",
"HeaderAdvanced": "Pokročilé", "HeaderAdvanced": "Pokročilé",
"HeaderAndroidAutoSettings": "Android Automatické nastavení",
"HeaderAudioTracks": "Zvukové stopy", "HeaderAudioTracks": "Zvukové stopy",
"HeaderChapters": "Kapitoly", "HeaderChapters": "Kapitoly",
"HeaderCollection": "Kolekce", "HeaderCollection": "Kolekce",
@@ -74,6 +75,7 @@
"HeaderPlaybackSettings": "Nastavení přehrávání", "HeaderPlaybackSettings": "Nastavení přehrávání",
"HeaderPlaylist": "Seznam skladeb", "HeaderPlaylist": "Seznam skladeb",
"HeaderPlaylistItems": "Položky seznamu přehrávání", "HeaderPlaylistItems": "Položky seznamu přehrávání",
"HeaderProgressSyncFailed": "Chyba při synchronizaci",
"HeaderRSSFeed": "RSS kanál", "HeaderRSSFeed": "RSS kanál",
"HeaderRSSFeedGeneral": "Detaily RSS", "HeaderRSSFeedGeneral": "Detaily RSS",
"HeaderRSSFeedIsOpen": "Kanál RSS je otevřen", "HeaderRSSFeedIsOpen": "Kanál RSS je otevřen",
@@ -301,7 +303,7 @@
"MessageNoSeries": "Žádné série", "MessageNoSeries": "Žádné série",
"MessageNoUpdatesWereNecessary": "Nebyly nutné žádné aktualizace", "MessageNoUpdatesWereNecessary": "Nebyly nutné žádné aktualizace",
"MessageNoUserPlaylists": "Nemáte žádné seznamy skladeb", "MessageNoUserPlaylists": "Nemáte žádné seznamy skladeb",
"MessagePodcastSearchField": "Zadejte hledaný výraz nebo adresu URL kanálu RSS", "MessagePodcastSearchField": "Zadejte hledaný pojem pro RSS feed URL",
"MessageReportBugsAndContribute": "Nahlašte chyby, vyžádejte si funkce a přispěte na", "MessageReportBugsAndContribute": "Nahlašte chyby, vyžádejte si funkce a přispěte na",
"MessageSeriesAlreadyDownloaded": "Všechny knihy v této sérii jste již stáhli.", "MessageSeriesAlreadyDownloaded": "Všechny knihy v této sérii jste již stáhli.",
"MessageSeriesDownloadConfirm": "Stáhnout chybějící {0} knihu(y) s {1} souborem(y), celkem {2} do složky {3}?", "MessageSeriesDownloadConfirm": "Stáhnout chybějící {0} knihu(y) s {1} souborem(y), celkem {2} do složky {3}?",
+18 -11
View File
@@ -29,16 +29,16 @@
"ButtonManageLocalFiles": "Administrér Lokale Filer", "ButtonManageLocalFiles": "Administrér Lokale Filer",
"ButtonNewFolder": "Ny Folder", "ButtonNewFolder": "Ny Folder",
"ButtonNextEpisode": "Næste Afsnit", "ButtonNextEpisode": "Næste Afsnit",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Åbn feed", "ButtonOpenFeed": "Åbn feed",
"ButtonOverride": "Override", "ButtonOverride": "Overskriv",
"ButtonPause": "Pause", "ButtonPause": "Pause",
"ButtonPlay": "Afspil", "ButtonPlay": "Afspil",
"ButtonPlayEpisode": "Afspil Afsnit", "ButtonPlayEpisode": "Afspil Afsnit",
"ButtonPlaying": "Afspiller",
"ButtonPlaylists": "Afspilningslister", "ButtonPlaylists": "Afspilningslister",
"ButtonRead": "Læs", "ButtonRead": "Læs",
"ButtonReadLess": "Læs Mindre", "ButtonReadLess": "Se mindre",
"ButtonReadMore": "Læs Mere", "ButtonReadMore": "Se mere",
"ButtonRemove": "Fjern", "ButtonRemove": "Fjern",
"ButtonRemoveFromServer": "Fjern fra Server", "ButtonRemoveFromServer": "Fjern fra Server",
"ButtonSave": "Gem", "ButtonSave": "Gem",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Afspilnings indstillinger", "HeaderPlaybackSettings": "Afspilnings indstillinger",
"HeaderPlaylist": "Afspilningsliste", "HeaderPlaylist": "Afspilningsliste",
"HeaderPlaylistItems": "Afspilningsliste Elementer", "HeaderPlaylistItems": "Afspilningsliste Elementer",
"HeaderProgressSyncFailed": "Fremskridt synkronisering fejlede",
"HeaderRSSFeed": "RSS Feed", "HeaderRSSFeed": "RSS Feed",
"HeaderRSSFeedGeneral": "RSS Detaljer", "HeaderRSSFeedGeneral": "RSS Detaljer",
"HeaderRSSFeedIsOpen": "RSS Feed er Åben", "HeaderRSSFeedIsOpen": "RSS Feed er Åben",
@@ -88,7 +89,7 @@
"HeaderUserInterfaceSettings": "Indstillinger for brugergrænseflade", "HeaderUserInterfaceSettings": "Indstillinger for brugergrænseflade",
"HeaderYourStats": "Dine Statistikker", "HeaderYourStats": "Dine Statistikker",
"LabelAddToPlaylist": "Tilføj til Afspilningsliste", "LabelAddToPlaylist": "Tilføj til Afspilningsliste",
"LabelAddedAt": "Tilføjet Kl", "LabelAddedAt": "Tilføjet",
"LabelAddedDate": "Tilføjet {0}", "LabelAddedDate": "Tilføjet {0}",
"LabelAll": "Alle", "LabelAll": "Alle",
"LabelAllowSeekingOnMediaControls": "Tillad positionssøgning på mediemeddelelseskontroller", "LabelAllowSeekingOnMediaControls": "Tillad positionssøgning på mediemeddelelseskontroller",
@@ -140,7 +141,7 @@
"LabelEnd": "Slut", "LabelEnd": "Slut",
"LabelEndOfChapter": "Slutningen af kapitel", "LabelEndOfChapter": "Slutningen af kapitel",
"LabelEndTime": "Sluttidspunkt", "LabelEndTime": "Sluttidspunkt",
"LabelEpisode": "Episode", "LabelEpisode": "Afsnit",
"LabelFeedURL": "Feed URL", "LabelFeedURL": "Feed URL",
"LabelFile": "Fil", "LabelFile": "Fil",
"LabelFileBirthtime": "Oprettelsestidspunkt for fil", "LabelFileBirthtime": "Oprettelsestidspunkt for fil",
@@ -163,6 +164,7 @@
"LabelInternalAppStorage": "Intern Lagerplads", "LabelInternalAppStorage": "Intern Lagerplads",
"LabelJumpBackwardsTime": "Spring tilbage tid", "LabelJumpBackwardsTime": "Spring tilbage tid",
"LabelJumpForwardsTime": "Spring frem tid", "LabelJumpForwardsTime": "Spring frem tid",
"LabelKeepScreenAwake": "Hold skærm aktiv",
"LabelLanguage": "Sprog", "LabelLanguage": "Sprog",
"LabelLayout": "Layout", "LabelLayout": "Layout",
"LabelLayoutAuto": "Automatisk", "LabelLayoutAuto": "Automatisk",
@@ -194,6 +196,8 @@
"LabelNotFinished": "Ikke færdig", "LabelNotFinished": "Ikke færdig",
"LabelNotStarted": "Ikke påbegyndt", "LabelNotStarted": "Ikke påbegyndt",
"LabelNumEpisodes": "{0} episoder", "LabelNumEpisodes": "{0} episoder",
"LabelNumEpisodesIncomplete": "{0} afsnit, {1} ikke færdige",
"LabelNumberOfEpisodes": "# afsnit",
"LabelOff": "Slukket", "LabelOff": "Slukket",
"LabelOn": "Tændt", "LabelOn": "Tændt",
"LabelPassword": "Kodeord", "LabelPassword": "Kodeord",
@@ -203,12 +207,12 @@
"LabelPlaybackSpeed": "Afspilningshastighed", "LabelPlaybackSpeed": "Afspilningshastighed",
"LabelPlaybackTranscode": "Transcode", "LabelPlaybackTranscode": "Transcode",
"LabelPodcast": "Podcast", "LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasts", "LabelPodcasts": "Podcast",
"LabelPreventIndexing": "Forhindrer, at dit feed bliver indekseret af iTunes og Google podcastkataloger", "LabelPreventIndexing": "Forhindrer, at dit feed bliver indekseret af iTunes og Google podcastkataloger",
"LabelProgress": "Fremskridt", "LabelProgress": "Fremskridt",
"LabelPubDate": "Udgivelsesdato", "LabelPubDate": "Udgivelsesdato",
"LabelPublishYear": "Udgivelsesår", "LabelPublishYear": "Udgivelsesår",
"LabelPublishedDate": "Udgivet {0}", "LabelPublishedDate": "Publiceret {0}",
"LabelRSSFeedCustomOwnerEmail": "Brugerdefineret ejerens e-mail", "LabelRSSFeedCustomOwnerEmail": "Brugerdefineret ejerens e-mail",
"LabelRSSFeedCustomOwnerName": "Brugerdefineret ejerens navn", "LabelRSSFeedCustomOwnerName": "Brugerdefineret ejerens navn",
"LabelRSSFeedPreventIndexing": "Forhindrer indeksering", "LabelRSSFeedPreventIndexing": "Forhindrer indeksering",
@@ -262,8 +266,8 @@
"LabelUsername": "Brugernavn", "LabelUsername": "Brugernavn",
"LabelVeryHigh": "Meget Højt", "LabelVeryHigh": "Meget Højt",
"LabelVeryLow": "Meget Lavt", "LabelVeryLow": "Meget Lavt",
"LabelYearReviewHide": "Skjul Gennemgang af Året", "LabelYearReviewHide": "Skjul år i review",
"LabelYearReviewShow": "Se Gennnemgang af Året", "LabelYearReviewShow": "Vis år i review",
"LabelYourBookmarks": "Dine bogmærker", "LabelYourBookmarks": "Dine bogmærker",
"LabelYourProgress": "Din fremgang", "LabelYourProgress": "Din fremgang",
"MessageAndroid10Downloads": "Android 10 og mindre vil bruge intern lagerplads til downloads.", "MessageAndroid10Downloads": "Android 10 og mindre vil bruge intern lagerplads til downloads.",
@@ -307,7 +311,10 @@
"MessageNoSeries": "Ingen serier", "MessageNoSeries": "Ingen serier",
"MessageNoUpdatesWereNecessary": "Ingen opdateringer var nødvendige", "MessageNoUpdatesWereNecessary": "Ingen opdateringer var nødvendige",
"MessageNoUserPlaylists": "Du har ingen afspilningslister", "MessageNoUserPlaylists": "Du har ingen afspilningslister",
"MessagePodcastSearchField": "Indtast søgeterm eller RSS-feed URL", "MessageOldServerConnectionWarning": "Server forbindelseskonfiguration anvender et gammelt bruger ID. Fjern venligst og gentilføj denne server forbindelse.",
"MessageOldServerConnectionWarningHelp": "Du har oprindeligt sat forbindelsen til denne server op før databasemigreringen i 2.3.0, udgivet i juni 2023. En senere serveropdatering vil fjerne muligheden for at logge ind med genne gamle metode. Sørg venligst for at slette den eksisterende serverforbindelse og opret forbindelse igen (ved anvendelse af den samme server adresse og login oplysninger). Hvis du har downloaded noget medie på denne enhed vil dette være nødsaget til at bive downloaded igen efter serversynkronisering.",
"MessagePodcastSearchField": "Indtast søgeterm eller RSS URL",
"MessageProgressSyncFailed": "Det seneste forsøg på indrapportering af dit lyttefremskridt til serveren er fejlet. Fremskridtssynkroniseringsforespørgsler vil forsøges mellem hvert 15 sekund og 1 minut mens medie afspilles.",
"MessageReportBugsAndContribute": "Rapporter fejl, anmod om funktioner og bidrag på", "MessageReportBugsAndContribute": "Rapporter fejl, anmod om funktioner og bidrag på",
"MessageSeriesAlreadyDownloaded": "Du har allerede downloadet alle bøgerne i denne serie.", "MessageSeriesAlreadyDownloaded": "Du har allerede downloadet alle bøgerne i denne serie.",
"MessageSeriesDownloadConfirm": "Download mangler {0} bog/bøger med {1} fil(er), i alt {2} til mappe {3}?", "MessageSeriesDownloadConfirm": "Download mangler {0} bog/bøger med {1} fil(er), i alt {2} til mappe {3}?",
+12 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Verwalte lokale Dateien", "ButtonManageLocalFiles": "Verwalte lokale Dateien",
"ButtonNewFolder": "Neuer Ordner", "ButtonNewFolder": "Neuer Ordner",
"ButtonNextEpisode": "Nächste Episode", "ButtonNextEpisode": "Nächste Episode",
"ButtonOk": "Einverstanden",
"ButtonOpenFeed": "Feed öffnen", "ButtonOpenFeed": "Feed öffnen",
"ButtonOverride": "Überschreiben", "ButtonOverride": "Überschreiben",
"ButtonPause": "Pausieren", "ButtonPause": "Pausieren",
"ButtonPlay": "Abspielen", "ButtonPlay": "Abspielen",
"ButtonPlayEpisode": "Episode abspielen", "ButtonPlayEpisode": "Episode abspielen",
"ButtonPlaying": "Spielt",
"ButtonPlaylists": "Wiedergabelisten", "ButtonPlaylists": "Wiedergabelisten",
"ButtonRead": "Lesen", "ButtonRead": "Lesen",
"ButtonReadLess": "weniger Anzeigen", "ButtonReadLess": "weniger Anzeigen",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Wiedergabe-Einstellungen", "HeaderPlaybackSettings": "Wiedergabe-Einstellungen",
"HeaderPlaylist": "Wiedergabeliste", "HeaderPlaylist": "Wiedergabeliste",
"HeaderPlaylistItems": "Einträge in der Wiedergabeliste", "HeaderPlaylistItems": "Einträge in der Wiedergabeliste",
"HeaderProgressSyncFailed": "Fortschritt konnte nicht synchronisiert werden",
"HeaderRSSFeed": "RSS-Feed", "HeaderRSSFeed": "RSS-Feed",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS-Feed ist geöffnet", "HeaderRSSFeedIsOpen": "RSS-Feed ist geöffnet",
@@ -93,6 +94,8 @@
"LabelAll": "Alle", "LabelAll": "Alle",
"LabelAllowSeekingOnMediaControls": "Erlaube Vor- und Zurückspulen auf dem Medienkontrollelement bei den Benachrichtigungen", "LabelAllowSeekingOnMediaControls": "Erlaube Vor- und Zurückspulen auf dem Medienkontrollelement bei den Benachrichtigungen",
"LabelAlways": "Immer", "LabelAlways": "Immer",
"LabelAndroidAutoBrowseLimitForGrouping": "Alphabetisches Drawdown-Limit",
"LabelAndroidAutoBrowseSeriesSequenceOrder": "Reihenfolge der Bücher der Serie",
"LabelAskConfirmation": "Bestätigung anfordern", "LabelAskConfirmation": "Bestätigung anfordern",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Vorname Nachname)", "LabelAuthorFirstLast": "Autor (Vorname Nachname)",
@@ -160,6 +163,7 @@
"LabelInternalAppStorage": "Interner App Speicher", "LabelInternalAppStorage": "Interner App Speicher",
"LabelJumpBackwardsTime": "Rückspulzeit", "LabelJumpBackwardsTime": "Rückspulzeit",
"LabelJumpForwardsTime": "Vorwärtsspulzeit", "LabelJumpForwardsTime": "Vorwärtsspulzeit",
"LabelKeepScreenAwake": "Bildschirm anlassen",
"LabelLanguage": "Sprache", "LabelLanguage": "Sprache",
"LabelLayout": "Ansicht", "LabelLayout": "Ansicht",
"LabelLayoutAuto": "Auto", "LabelLayoutAuto": "Auto",
@@ -191,6 +195,8 @@
"LabelNotFinished": "Nicht beendet", "LabelNotFinished": "Nicht beendet",
"LabelNotStarted": "Nicht begonnen", "LabelNotStarted": "Nicht begonnen",
"LabelNumEpisodes": "{0} Episoden", "LabelNumEpisodes": "{0} Episoden",
"LabelNumEpisodesIncomplete": "{0} Episoden, {1} unvollständig",
"LabelNumberOfEpisodes": "Anzahl der Episoden",
"LabelOff": "Aus", "LabelOff": "Aus",
"LabelOn": "An", "LabelOn": "An",
"LabelPassword": "Passwort", "LabelPassword": "Passwort",
@@ -219,6 +225,8 @@
"LabelScaleElapsedTimeBySpeed": "Vergangene Zeit anhand der Geschwindigkeit skalieren", "LabelScaleElapsedTimeBySpeed": "Vergangene Zeit anhand der Geschwindigkeit skalieren",
"LabelSeason": "Staffel", "LabelSeason": "Staffel",
"LabelSelectADevice": "Wähle ein Gerät", "LabelSelectADevice": "Wähle ein Gerät",
"LabelSequenceAscending": "Reihenfolge aufsteigend",
"LabelSequenceDescending": "Reihenfolge absteigend",
"LabelSeries": "Serien", "LabelSeries": "Serien",
"LabelServerAddress": "Serveradresse", "LabelServerAddress": "Serveradresse",
"LabelSetEbookAsPrimary": "Als Hauptbuch setzen", "LabelSetEbookAsPrimary": "Als Hauptbuch setzen",
@@ -302,7 +310,10 @@
"MessageNoSeries": "Keine Serie", "MessageNoSeries": "Keine Serie",
"MessageNoUpdatesWereNecessary": "Keine Aktualisierungen waren notwendig", "MessageNoUpdatesWereNecessary": "Keine Aktualisierungen waren notwendig",
"MessageNoUserPlaylists": "Keine Wiedergabelisten vorhanden", "MessageNoUserPlaylists": "Keine Wiedergabelisten vorhanden",
"MessageOldServerConnectionWarning": "Diese Serververbindung nutzt eine alte Nutzer-ID(user ID). Bitte entferne diese Serververbindung und füge sie wieder neu hinzu.",
"MessageOldServerConnectionWarningHelp": "Du hast diese Serververbindung vor der Datenbankmigration in 2.3.0, veröffentlicht Juni 2023, eingerichtet. Ein zukünftiges Serverupdate wird die Möglichkeit sich mit dieser Verbindung anzumelden entfernen. Bitte lösche die existierende Serververbindung und melde dich neu an (mit der gleichen Serveraddresse und Zugangsdaten. Wenn du irgendwelche Medien auf dieses Gerät heruntergeladen hast musst du sie anschließend erneut herunterladen um den Status zu synchronisieren.",
"MessagePodcastSearchField": "Suchbegriff oder RSS-Feed URL eingeben", "MessagePodcastSearchField": "Suchbegriff oder RSS-Feed URL eingeben",
"MessageProgressSyncFailed": "Der letzte Versuch den aktuellen Hörfortschritt an den Server zu melden ist fehlgeschlagen. Die Anfragen den Fortschritt zu synchronisieren wird alle 15 Sekunden bis 1 Minute versucht, während Medien abgespielt werden.",
"MessageReportBugsAndContribute": "Fehler melden, Funktionen anfordern und mitwirken", "MessageReportBugsAndContribute": "Fehler melden, Funktionen anfordern und mitwirken",
"MessageSeriesAlreadyDownloaded": "Du hast bereits alle Bücher in dieser Serie heruntergeladen.", "MessageSeriesAlreadyDownloaded": "Du hast bereits alle Bücher in dieser Serie heruntergeladen.",
"MessageSeriesDownloadConfirm": "Lade {0} Bücher mit {1} Daten, zusammen {2}, in den Ordner {3} herunter?", "MessageSeriesDownloadConfirm": "Lade {0} Bücher mit {1} Daten, zusammen {2}, in den Ordner {3} herunter?",
+10 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Manage Local Files", "ButtonManageLocalFiles": "Manage Local Files",
"ButtonNewFolder": "New Folder", "ButtonNewFolder": "New Folder",
"ButtonNextEpisode": "Next Episode", "ButtonNextEpisode": "Next Episode",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Open Feed", "ButtonOpenFeed": "Open Feed",
"ButtonOverride": "Override", "ButtonOverride": "Override",
"ButtonPause": "Pause", "ButtonPause": "Pause",
"ButtonPlay": "Play", "ButtonPlay": "Play",
"ButtonPlayEpisode": "Play Episode", "ButtonPlayEpisode": "Play Episode",
"ButtonPlaying": "Playing",
"ButtonPlaylists": "Playlists", "ButtonPlaylists": "Playlists",
"ButtonRead": "Read", "ButtonRead": "Read",
"ButtonReadLess": "Read less", "ButtonReadLess": "Read less",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Playback Settings", "HeaderPlaybackSettings": "Playback Settings",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
"HeaderPlaylistItems": "Playlist Items", "HeaderPlaylistItems": "Playlist Items",
"HeaderProgressSyncFailed": "Progress Sync Failed",
"HeaderRSSFeed": "RSS Feed", "HeaderRSSFeed": "RSS Feed",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed is Open", "HeaderRSSFeedIsOpen": "RSS Feed is Open",
@@ -178,6 +179,7 @@
"LabelLow": "Low", "LabelLow": "Low",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMedium": "Medium", "LabelMedium": "Medium",
"LabelMissing": "Missing",
"LabelMore": "More", "LabelMore": "More",
"LabelMoreInfo": "More Info", "LabelMoreInfo": "More Info",
"LabelName": "Name", "LabelName": "Name",
@@ -195,6 +197,8 @@
"LabelNotFinished": "Not Finished", "LabelNotFinished": "Not Finished",
"LabelNotStarted": "Not Started", "LabelNotStarted": "Not Started",
"LabelNumEpisodes": "{0} episodes", "LabelNumEpisodes": "{0} episodes",
"LabelNumEpisodesIncomplete": "{0} episodes, {1} incomplete",
"LabelNumberOfEpisodes": "# of Episodes",
"LabelOff": "Off", "LabelOff": "Off",
"LabelOn": "On", "LabelOn": "On",
"LabelPassword": "Password", "LabelPassword": "Password",
@@ -274,6 +278,7 @@
"MessageBookshelfEmpty": "Bookshelf empty", "MessageBookshelfEmpty": "Bookshelf empty",
"MessageConfirmDeleteLocalEpisode": "Remove local episode \"{0}\" from your device? The file on the server will be unaffected.", "MessageConfirmDeleteLocalEpisode": "Remove local episode \"{0}\" from your device? The file on the server will be unaffected.",
"MessageConfirmDeleteLocalFiles": "Remove local files of this item from your device? The files on the server and your progress will be unaffected.", "MessageConfirmDeleteLocalFiles": "Remove local files of this item from your device? The files on the server and your progress will be unaffected.",
"MessageConfirmDisableAutoTimer": "Are you sure you want to disable the auto timer for the rest of today? The timer will be re-enabled at the end of this auto-sleep timer period, or if you restart the app.",
"MessageConfirmDiscardProgress": "Are you sure you want to reset your progress?", "MessageConfirmDiscardProgress": "Are you sure you want to reset your progress?",
"MessageConfirmDownloadUsingCellular": "You are about to download using cellular data. This may include carrier data charges. Do you wish to continue?", "MessageConfirmDownloadUsingCellular": "You are about to download using cellular data. This may include carrier data charges. Do you wish to continue?",
"MessageConfirmMarkAsFinished": "Are you sure you want to mark this item as finished?", "MessageConfirmMarkAsFinished": "Are you sure you want to mark this item as finished?",
@@ -288,6 +293,7 @@
"MessageFetching": "Fetching...", "MessageFetching": "Fetching...",
"MessageFollowTheProjectOnGithub": "Follow the project on Github", "MessageFollowTheProjectOnGithub": "Follow the project on Github",
"MessageItemDownloadCompleteFailedToCreate": "Item download complete but failed to create library item", "MessageItemDownloadCompleteFailedToCreate": "Item download complete but failed to create library item",
"MessageItemMissing": "Item is missing and must be fixed on the server. Typically an item is marked as missing because the file paths are not accessible.",
"MessageLoading": "Loading...", "MessageLoading": "Loading...",
"MessageLoadingServerData": "Loading server data...", "MessageLoadingServerData": "Loading server data...",
"MessageMarkAsFinished": "Mark as Finished", "MessageMarkAsFinished": "Mark as Finished",
@@ -308,7 +314,10 @@
"MessageNoSeries": "No series", "MessageNoSeries": "No series",
"MessageNoUpdatesWereNecessary": "No updates were necessary", "MessageNoUpdatesWereNecessary": "No updates were necessary",
"MessageNoUserPlaylists": "You have no playlists", "MessageNoUserPlaylists": "You have no playlists",
"MessageOldServerConnectionWarning": "Server connection config is using an old user ID. Please delete and re-add this server connection.",
"MessageOldServerConnectionWarningHelp": "You originally set up the connection to this server prior to the database migration in 2.3.0, released June 2023. A future server update will remove the ability to sign in with this old connection. Please delete the existing server connection and connect again (using the same server address and credentials). If you have any downloaded media on this device, the media will need to be downloaded again to sync with the server.",
"MessagePodcastSearchField": "Enter search term or RSS feed URL", "MessagePodcastSearchField": "Enter search term or RSS feed URL",
"MessageProgressSyncFailed": "The most recent attempt to report your listening progress to the server has failed. Progress sync requests will continue to be attempted every 15 seconds to 1 minute while media is playing.",
"MessageReportBugsAndContribute": "Report bugs, request features, and contribute on", "MessageReportBugsAndContribute": "Report bugs, request features, and contribute on",
"MessageSeriesAlreadyDownloaded": "You have already downloaded all books in this series.", "MessageSeriesAlreadyDownloaded": "You have already downloaded all books in this series.",
"MessageSeriesDownloadConfirm": "Download missing {0} book(s) with {1} file(s), totaling {2} to folder {3}?", "MessageSeriesDownloadConfirm": "Download missing {0} book(s) with {1} file(s), totaling {2} to folder {3}?",
+15 -2
View File
@@ -1,5 +1,5 @@
{ {
"ButtonAdd": "Agregaro", "ButtonAdd": "Agregar",
"ButtonAddNewServer": "Agregar nuevo servidor", "ButtonAddNewServer": "Agregar nuevo servidor",
"ButtonAuthors": "Autores", "ButtonAuthors": "Autores",
"ButtonBack": "Atrás", "ButtonBack": "Atrás",
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Gestionar archivos locales", "ButtonManageLocalFiles": "Gestionar archivos locales",
"ButtonNewFolder": "Nueva carpeta", "ButtonNewFolder": "Nueva carpeta",
"ButtonNextEpisode": "Próximo episodio", "ButtonNextEpisode": "Próximo episodio",
"ButtonOk": "Bueno",
"ButtonOpenFeed": "Abrir fuente", "ButtonOpenFeed": "Abrir fuente",
"ButtonOverride": "Sustituir", "ButtonOverride": "Sustituir",
"ButtonPause": "Pausar", "ButtonPause": "Pausar",
"ButtonPlay": "Reproducir", "ButtonPlay": "Reproducir",
"ButtonPlayEpisode": "Reproducir episodio", "ButtonPlayEpisode": "Reproducir episodio",
"ButtonPlaying": "Reproduciendo",
"ButtonPlaylists": "Listas de reproducción", "ButtonPlaylists": "Listas de reproducción",
"ButtonRead": "Leer", "ButtonRead": "Leer",
"ButtonReadLess": "Leer menos", "ButtonReadLess": "Leer menos",
@@ -54,6 +54,7 @@
"ButtonYes": "Sí", "ButtonYes": "Sí",
"HeaderAccount": "Cuenta", "HeaderAccount": "Cuenta",
"HeaderAdvanced": "Avanzado", "HeaderAdvanced": "Avanzado",
"HeaderAndroidAutoSettings": "Configuración de Android Auto",
"HeaderAudioTracks": "Pistas de audio", "HeaderAudioTracks": "Pistas de audio",
"HeaderChapters": "Capítulos", "HeaderChapters": "Capítulos",
"HeaderCollection": "Colección", "HeaderCollection": "Colección",
@@ -74,6 +75,7 @@
"HeaderPlaybackSettings": "Ajustes de reproducción", "HeaderPlaybackSettings": "Ajustes de reproducción",
"HeaderPlaylist": "Lista de reproducción", "HeaderPlaylist": "Lista de reproducción",
"HeaderPlaylistItems": "Elementos de lista de reproducción", "HeaderPlaylistItems": "Elementos de lista de reproducción",
"HeaderProgressSyncFailed": "Falló la sincronización del progreso",
"HeaderRSSFeed": "Fuente RSS", "HeaderRSSFeed": "Fuente RSS",
"HeaderRSSFeedGeneral": "Detalles RSS", "HeaderRSSFeedGeneral": "Detalles RSS",
"HeaderRSSFeedIsOpen": "Fuente RSS está abierta", "HeaderRSSFeedIsOpen": "Fuente RSS está abierta",
@@ -92,6 +94,9 @@
"LabelAll": "Todos", "LabelAll": "Todos",
"LabelAllowSeekingOnMediaControls": "Permitir la búsqueda de posición en los controles de notificación de medios", "LabelAllowSeekingOnMediaControls": "Permitir la búsqueda de posición en los controles de notificación de medios",
"LabelAlways": "Siempre", "LabelAlways": "Siempre",
"LabelAndroidAutoBrowseLimitForGrouping": "Limite del despliegue alfabético",
"LabelAndroidAutoBrowseLimitForGroupingHelp": "No utilice el despliegue alfabético cuando haya menos de esta cantidad de elementos para mostrar",
"LabelAndroidAutoBrowseSeriesSequenceOrder": "Orden de libros de Series",
"LabelAskConfirmation": "Pedir confirmación", "LabelAskConfirmation": "Pedir confirmación",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (Nombre Apellido)", "LabelAuthorFirstLast": "Autor (Nombre Apellido)",
@@ -159,6 +164,7 @@
"LabelInternalAppStorage": "Almacenamiento interno de aplicaciones", "LabelInternalAppStorage": "Almacenamiento interno de aplicaciones",
"LabelJumpBackwardsTime": "Saltar atrás en el tiempo", "LabelJumpBackwardsTime": "Saltar atrás en el tiempo",
"LabelJumpForwardsTime": "Salto adelante en el tiempo", "LabelJumpForwardsTime": "Salto adelante en el tiempo",
"LabelKeepScreenAwake": "Mantener la pantalla encendida",
"LabelLanguage": "Idioma", "LabelLanguage": "Idioma",
"LabelLayout": "Diseño", "LabelLayout": "Diseño",
"LabelLayoutAuto": "Automático", "LabelLayoutAuto": "Automático",
@@ -190,6 +196,8 @@
"LabelNotFinished": "No terminado", "LabelNotFinished": "No terminado",
"LabelNotStarted": "Sin iniciar", "LabelNotStarted": "Sin iniciar",
"LabelNumEpisodes": "{0} episodios", "LabelNumEpisodes": "{0} episodios",
"LabelNumEpisodesIncomplete": "{0} episodios, {1} incompletos",
"LabelNumberOfEpisodes": "# de Episodios",
"LabelOff": "Apagado", "LabelOff": "Apagado",
"LabelOn": "Encendido", "LabelOn": "Encendido",
"LabelPassword": "Contraseña", "LabelPassword": "Contraseña",
@@ -218,6 +226,8 @@
"LabelScaleElapsedTimeBySpeed": "Escala el tiempo transcurrido según la velocidad", "LabelScaleElapsedTimeBySpeed": "Escala el tiempo transcurrido según la velocidad",
"LabelSeason": "Temporada", "LabelSeason": "Temporada",
"LabelSelectADevice": "Selecciona un dispositivo", "LabelSelectADevice": "Selecciona un dispositivo",
"LabelSequenceAscending": "Secuencia Ascendente",
"LabelSequenceDescending": "Secuencia Descendente",
"LabelSeries": "Series", "LabelSeries": "Series",
"LabelServerAddress": "Dirección del servidor", "LabelServerAddress": "Dirección del servidor",
"LabelSetEbookAsPrimary": "Establecer como primario", "LabelSetEbookAsPrimary": "Establecer como primario",
@@ -301,7 +311,10 @@
"MessageNoSeries": "Ninguna serie", "MessageNoSeries": "Ninguna serie",
"MessageNoUpdatesWereNecessary": "No fue necesario actualizar", "MessageNoUpdatesWereNecessary": "No fue necesario actualizar",
"MessageNoUserPlaylists": "No tienes ninguna lista de reproducción", "MessageNoUserPlaylists": "No tienes ninguna lista de reproducción",
"MessageOldServerConnectionWarning": "La configuración de la conexión al servidor está utilizando un ID de usuario antiguo. Por favor, elimine y vuelva a añadir esta conexión al servidor.",
"MessageOldServerConnectionWarningHelp": "Usted configuró originalmente la conexión a este servidor antes de la migración de la base de datos en la versión 2.3.0, publicada en junio de 2023. Una futura actualización del servidor eliminará la posibilidad de iniciar sesión con esta conexión antigua. Por favor, elimine la conexión existente al servidor y conéctese de nuevo (utilizando la misma dirección del servidor y las mismas credenciales). Si tiene algún medio descargado en este dispositivo, será necesario descargarlo de nuevo para sincronizarlo con el servidor.",
"MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS", "MessagePodcastSearchField": "Introduzca el término de búsqueda o la URL de la fuente RSS",
"MessageProgressSyncFailed": "El último intento de informar al servidor sobre el progreso de la escucha ha fallado. Las solicitudes de sincronización de progreso seguirán intentándose cada 15 segundos a 1 minuto mientras se reproduce el contenido multimedia.",
"MessageReportBugsAndContribute": "Reporte erres, solicite funciones y contribuya en", "MessageReportBugsAndContribute": "Reporte erres, solicite funciones y contribuya en",
"MessageSeriesAlreadyDownloaded": "Ya has descargado todos los libros de esta serie.", "MessageSeriesAlreadyDownloaded": "Ya has descargado todos los libros de esta serie.",
"MessageSeriesDownloadConfirm": "¿Descargar {0} libro(s) faltante(s) con {1} archivo(s), totalizando {2} a la carpeta {3}?", "MessageSeriesDownloadConfirm": "¿Descargar {0} libro(s) faltante(s) con {1} archivo(s), totalizando {2} a la carpeta {3}?",
+19 -1
View File
@@ -34,9 +34,10 @@
"ButtonPause": "Pysäytä", "ButtonPause": "Pysäytä",
"ButtonPlay": "Toista", "ButtonPlay": "Toista",
"ButtonPlayEpisode": "Toista jakso", "ButtonPlayEpisode": "Toista jakso",
"ButtonPlaying": "Toistetaan",
"ButtonPlaylists": "Soittolistat", "ButtonPlaylists": "Soittolistat",
"ButtonRead": "Lue", "ButtonRead": "Lue",
"ButtonReadLess": "Lue vähemmän",
"ButtonReadMore": "Lue enemmän",
"ButtonRemove": "Poista", "ButtonRemove": "Poista",
"ButtonRemoveFromServer": "Poista palvelimelta", "ButtonRemoveFromServer": "Poista palvelimelta",
"ButtonSave": "Tallenna", "ButtonSave": "Tallenna",
@@ -52,6 +53,7 @@
"ButtonYes": "Kyllä", "ButtonYes": "Kyllä",
"HeaderAccount": "Tili", "HeaderAccount": "Tili",
"HeaderAdvanced": "Edistynyt", "HeaderAdvanced": "Edistynyt",
"HeaderAndroidAutoSettings": "Android Auto -asetukset",
"HeaderAudioTracks": "Ääniraidat", "HeaderAudioTracks": "Ääniraidat",
"HeaderChapters": "Luvut", "HeaderChapters": "Luvut",
"HeaderCollection": "Kokoelma", "HeaderCollection": "Kokoelma",
@@ -86,6 +88,7 @@
"HeaderYourStats": "Tilastosi", "HeaderYourStats": "Tilastosi",
"LabelAddToPlaylist": "Lisää soittolistaan", "LabelAddToPlaylist": "Lisää soittolistaan",
"LabelAddedAt": "Lisätty listalle", "LabelAddedAt": "Lisätty listalle",
"LabelAddedDate": "Lisätty {0}",
"LabelAll": "Kaikki", "LabelAll": "Kaikki",
"LabelAllowSeekingOnMediaControls": "Salli kelaaminen ilmoituksen säätimillä", "LabelAllowSeekingOnMediaControls": "Salli kelaaminen ilmoituksen säätimillä",
"LabelAlways": "Aina", "LabelAlways": "Aina",
@@ -128,8 +131,10 @@
"LabelEbook": "E-kirja", "LabelEbook": "E-kirja",
"LabelEbooks": "E-kirjat", "LabelEbooks": "E-kirjat",
"LabelEnable": "Ota käyttöön", "LabelEnable": "Ota käyttöön",
"LabelEnableMp3IndexSeeking": "Ota mp3-hakemistohaku käyttöön",
"LabelEnd": "Loppu", "LabelEnd": "Loppu",
"LabelEndOfChapter": "Luvun loppu", "LabelEndOfChapter": "Luvun loppu",
"LabelEndTime": "Päättymisaika",
"LabelEpisode": "Jakso", "LabelEpisode": "Jakso",
"LabelFeedURL": "Syötteen URL", "LabelFeedURL": "Syötteen URL",
"LabelFile": "Tiedosto", "LabelFile": "Tiedosto",
@@ -138,6 +143,8 @@
"LabelFilename": "Tiedostonimi", "LabelFilename": "Tiedostonimi",
"LabelFinished": "Valmis", "LabelFinished": "Valmis",
"LabelFolder": "Kansio", "LabelFolder": "Kansio",
"LabelFontBoldness": "Kirjasintyyppien lihavointi",
"LabelFontScale": "Kirjasintyyppien skaalautuminen",
"LabelGenre": "Lajityyppi", "LabelGenre": "Lajityyppi",
"LabelGenres": "Lajityypit", "LabelGenres": "Lajityypit",
"LabelHapticFeedback": "Tuntopalaute", "LabelHapticFeedback": "Tuntopalaute",
@@ -145,14 +152,18 @@
"LabelHost": "Isäntä", "LabelHost": "Isäntä",
"LabelInProgress": "Kesken", "LabelInProgress": "Kesken",
"LabelIncomplete": "Keskeneräinen", "LabelIncomplete": "Keskeneräinen",
"LabelInternalAppStorage": "Sovelluksen sisäinen tallennustila",
"LabelJumpBackwardsTime": "Hyppää taaksepäin ajassa", "LabelJumpBackwardsTime": "Hyppää taaksepäin ajassa",
"LabelJumpForwardsTime": "Hyppää eteenpäin ajassa", "LabelJumpForwardsTime": "Hyppää eteenpäin ajassa",
"LabelLanguage": "Kieli", "LabelLanguage": "Kieli",
"LabelLayout": "Asettelu",
"LabelLayoutSinglePage": "Yksi sivu",
"LabelLight": "Vaalea", "LabelLight": "Vaalea",
"LabelLineSpacing": "Riviväli", "LabelLineSpacing": "Riviväli",
"LabelListenAgain": "Kuuntele uudelleen", "LabelListenAgain": "Kuuntele uudelleen",
"LabelLocalBooks": "Paikalliset kirjat", "LabelLocalBooks": "Paikalliset kirjat",
"LabelLocalPodcasts": "Paikalliset podcastit", "LabelLocalPodcasts": "Paikalliset podcastit",
"LabelLockOrientation": "Lukitse suunta",
"LabelLockPlayer": "Lukitse soitin", "LabelLockPlayer": "Lukitse soitin",
"LabelLow": "Matala", "LabelLow": "Matala",
"LabelMediaType": "Mediatyyppi", "LabelMediaType": "Mediatyyppi",
@@ -163,11 +174,15 @@
"LabelNarrator": "Lukija", "LabelNarrator": "Lukija",
"LabelNarrators": "Lukijat", "LabelNarrators": "Lukijat",
"LabelNavigateWithVolume": "Navigoi äänenvoimakkuus-painikkeilla", "LabelNavigateWithVolume": "Navigoi äänenvoimakkuus-painikkeilla",
"LabelNavigateWithVolumeMirrored": "Peilattu",
"LabelNavigateWithVolumeWhilePlaying": "Salli siirtyminen äänenvoimakkuuspainikkeilla toiston aikana",
"LabelNever": "Ei koskaan", "LabelNever": "Ei koskaan",
"LabelNewestAuthors": "Uusimmat kirjailijat", "LabelNewestAuthors": "Uusimmat kirjailijat",
"LabelNewestEpisodes": "Uusimmat jaksot", "LabelNewestEpisodes": "Uusimmat jaksot",
"LabelNo": "Ei", "LabelNo": "Ei",
"LabelNotFinished": "Ei valmis",
"LabelNotStarted": "Ei aloitettu", "LabelNotStarted": "Ei aloitettu",
"LabelNumEpisodes": "{0} jaksoa",
"LabelOff": "Pois päältä", "LabelOff": "Pois päältä",
"LabelOn": "Päällä", "LabelOn": "Päällä",
"LabelPassword": "Salasana", "LabelPassword": "Salasana",
@@ -176,7 +191,10 @@
"LabelPlaybackSpeed": "Toistonopeus", "LabelPlaybackSpeed": "Toistonopeus",
"LabelPodcast": "Podcast", "LabelPodcast": "Podcast",
"LabelPodcasts": "Podcastit", "LabelPodcasts": "Podcastit",
"LabelProgress": "Edistyminen",
"LabelPubDate": "Julkaisupäivä",
"LabelPublishYear": "Julkaisuvuosi", "LabelPublishYear": "Julkaisuvuosi",
"LabelPublishedDate": "Julkaistu {0}",
"LabelRSSFeedPreventIndexing": "Estä indeksointi", "LabelRSSFeedPreventIndexing": "Estä indeksointi",
"LabelRandomly": "Satunnaisesti", "LabelRandomly": "Satunnaisesti",
"LabelRead": "Lue", "LabelRead": "Lue",
+17 -4
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Gérer les fichiers locaux", "ButtonManageLocalFiles": "Gérer les fichiers locaux",
"ButtonNewFolder": "Nouveau dossier", "ButtonNewFolder": "Nouveau dossier",
"ButtonNextEpisode": "Prochain épisode", "ButtonNextEpisode": "Prochain épisode",
"ButtonOk": "D'accord",
"ButtonOpenFeed": "Ouvrir le flux", "ButtonOpenFeed": "Ouvrir le flux",
"ButtonOverride": "Remplacer", "ButtonOverride": "Remplacer",
"ButtonPause": "Pause", "ButtonPause": "Pause",
"ButtonPlay": "Lire", "ButtonPlay": "Lire",
"ButtonPlayEpisode": "Lire l’épisode", "ButtonPlayEpisode": "Lire l’épisode",
"ButtonPlaying": "En lecture",
"ButtonPlaylists": "Listes de lecture", "ButtonPlaylists": "Listes de lecture",
"ButtonRead": "Lire", "ButtonRead": "Lire",
"ButtonReadLess": "Lire moins", "ButtonReadLess": "Lire moins",
@@ -54,6 +54,7 @@
"ButtonYes": "Oui", "ButtonYes": "Oui",
"HeaderAccount": "Compte", "HeaderAccount": "Compte",
"HeaderAdvanced": "Avancé", "HeaderAdvanced": "Avancé",
"HeaderAndroidAutoSettings": "Paramètres automatiques Android",
"HeaderAudioTracks": "Pistes audio", "HeaderAudioTracks": "Pistes audio",
"HeaderChapters": "Chapitres", "HeaderChapters": "Chapitres",
"HeaderCollection": "Collection", "HeaderCollection": "Collection",
@@ -74,6 +75,7 @@
"HeaderPlaybackSettings": "Paramètres de lecture", "HeaderPlaybackSettings": "Paramètres de lecture",
"HeaderPlaylist": "Liste de lecture", "HeaderPlaylist": "Liste de lecture",
"HeaderPlaylistItems": "Éléments de la liste de lecture", "HeaderPlaylistItems": "Éléments de la liste de lecture",
"HeaderProgressSyncFailed": "Échec de la synchronisation de l'avancement",
"HeaderRSSFeed": "Flux RSS", "HeaderRSSFeed": "Flux RSS",
"HeaderRSSFeedGeneral": "Détails du flux RSS", "HeaderRSSFeedGeneral": "Détails du flux RSS",
"HeaderRSSFeedIsOpen": "Le flux RSS est actif", "HeaderRSSFeedIsOpen": "Le flux RSS est actif",
@@ -92,6 +94,9 @@
"LabelAll": "Tout", "LabelAll": "Tout",
"LabelAllowSeekingOnMediaControls": "Autoriser la recherche de position depuis la notification du lecteur multimédia", "LabelAllowSeekingOnMediaControls": "Autoriser la recherche de position depuis la notification du lecteur multimédia",
"LabelAlways": "Toujours", "LabelAlways": "Toujours",
"LabelAndroidAutoBrowseLimitForGrouping": "Limite de retrait alphabétique",
"LabelAndroidAutoBrowseLimitForGroupingHelp": "Ne pas utiliser le retrait alphabétique lorsqu'il y a moins que cette quantité d'éléments à afficher",
"LabelAndroidAutoBrowseSeriesSequenceOrder": "Ordre des livres en séries",
"LabelAskConfirmation": "Demander une confirmation", "LabelAskConfirmation": "Demander une confirmation",
"LabelAuthor": "Auteur", "LabelAuthor": "Auteur",
"LabelAuthorFirstLast": "Auteur (Prénom Nom)", "LabelAuthorFirstLast": "Auteur (Prénom Nom)",
@@ -159,6 +164,7 @@
"LabelInternalAppStorage": "Stockage Interne de l'application", "LabelInternalAppStorage": "Stockage Interne de l'application",
"LabelJumpBackwardsTime": "Durée du saut arrière", "LabelJumpBackwardsTime": "Durée du saut arrière",
"LabelJumpForwardsTime": "Durée du saut avant", "LabelJumpForwardsTime": "Durée du saut avant",
"LabelKeepScreenAwake": "Gardez l'écran allumé",
"LabelLanguage": "Langue", "LabelLanguage": "Langue",
"LabelLayout": "Mise en page", "LabelLayout": "Mise en page",
"LabelLayoutAuto": "Automatique", "LabelLayoutAuto": "Automatique",
@@ -190,6 +196,8 @@
"LabelNotFinished": "Non terminé", "LabelNotFinished": "Non terminé",
"LabelNotStarted": "Pas commencé", "LabelNotStarted": "Pas commencé",
"LabelNumEpisodes": "{0} épisodes", "LabelNumEpisodes": "{0} épisodes",
"LabelNumEpisodesIncomplete": "{0} épisodes, {1} incomplets",
"LabelNumberOfEpisodes": "Nombre d'épisodes",
"LabelOff": "Éteint", "LabelOff": "Éteint",
"LabelOn": "Activé", "LabelOn": "Activé",
"LabelPassword": "Mot de passe", "LabelPassword": "Mot de passe",
@@ -218,6 +226,8 @@
"LabelScaleElapsedTimeBySpeed": "Traduire le temps restant en fonction de la vitesse de lecture", "LabelScaleElapsedTimeBySpeed": "Traduire le temps restant en fonction de la vitesse de lecture",
"LabelSeason": "Saison", "LabelSeason": "Saison",
"LabelSelectADevice": "Sélectionner un Appareil", "LabelSelectADevice": "Sélectionner un Appareil",
"LabelSequenceAscending": "Séquence ascendante",
"LabelSequenceDescending": "Séquence descendante",
"LabelSeries": "Séries", "LabelSeries": "Séries",
"LabelServerAddress": "Adresse du serveur", "LabelServerAddress": "Adresse du serveur",
"LabelSetEbookAsPrimary": "Définir comme principale", "LabelSetEbookAsPrimary": "Définir comme principale",
@@ -284,11 +294,11 @@
"MessageLoading": "Chargement…", "MessageLoading": "Chargement…",
"MessageLoadingServerData": "Chargement des données du serveur...", "MessageLoadingServerData": "Chargement des données du serveur...",
"MessageMarkAsFinished": "Marquer comme terminé", "MessageMarkAsFinished": "Marquer comme terminé",
"MessageMediaLinkedToADifferentServer": "L'élément est lié à un serveur Audiobookshelf sur une autre adresse ({0}). La progression sera synchroniser lors de la connexion au serveur à cette adresse.", "MessageMediaLinkedToADifferentServer": "L'élément est lié à un serveur Audiobookshelf sur une autre adresse ({0}). La progression sera synchronisée lors de la connexion au serveur à cette adresse.",
"MessageMediaLinkedToADifferentUser": "L'élément est lié a ce serveur, mais a ete téléchargé par un autre utilisateur. La progression ne sera synchronisé que pour l'utilisateur qui l'a téléchargé..", "MessageMediaLinkedToADifferentUser": "L'élément est lié à ce serveur mais a été téléchargé par un autre utilisateur. La progression ne sera pas synchronisée que pour l'utilisateur qui l'a téléchargé..",
"MessageMediaLinkedToServer": "Lié au serveur {0}", "MessageMediaLinkedToServer": "Lié au serveur {0}",
"MessageMediaLinkedToThisServer": "L'élément téléchargé est lié à a ce serveur", "MessageMediaLinkedToThisServer": "L'élément téléchargé est lié à a ce serveur",
"MessageMediaNotLinkedToServer": "L'élément n'est lié à aucun serveur. La progression ne sera pas synchronisé.", "MessageMediaNotLinkedToServer": "L'élément n'est lié à aucun serveur. La progression ne sera pas synchronisée.",
"MessageNoBookmarks": "Aucun favoris", "MessageNoBookmarks": "Aucun favoris",
"MessageNoChapters": "Aucun chapitre", "MessageNoChapters": "Aucun chapitre",
"MessageNoCollections": "Aucune collection", "MessageNoCollections": "Aucune collection",
@@ -301,7 +311,10 @@
"MessageNoSeries": "Aucune série", "MessageNoSeries": "Aucune série",
"MessageNoUpdatesWereNecessary": "Aucune mise à jour n’était nécessaire", "MessageNoUpdatesWereNecessary": "Aucune mise à jour n’était nécessaire",
"MessageNoUserPlaylists": "Vous navez aucune liste de lecture", "MessageNoUserPlaylists": "Vous navez aucune liste de lecture",
"MessageOldServerConnectionWarning": "La configuration de connexion du serveur utilise un ancien identifiant utilisateur. Veuillez supprimer et ajouter cette connexion serveur.",
"MessageOldServerConnectionWarningHelp": "Vous avez initialement créé la connexion à ce serveur avant la migration de la base de données dans 2.3.0, publié en juin 2023. Une mise à jour future du serveur supprimera la possibilité de signer avec cette ancienne connexion. Veuillez supprimer la connexion existante du serveur et se connecter à nouveau (en utilisant la même adresse de serveur et les mêmes identifiants). Si vous avez des médias téléchargés sur cet appareil, les médias devront être téléchargés à nouveau pour synchroniser avec le serveur.",
"MessagePodcastSearchField": "Saisir un terme de recherche ou l'URL d'un flux RSS", "MessagePodcastSearchField": "Saisir un terme de recherche ou l'URL d'un flux RSS",
"MessageProgressSyncFailed": "La dernière tentative de rapporter vos progrès d'écoute sur le serveur a échoué. Les demandes de synchronisation continueront d'être tentées toutes les 15 secondes à 1 minute pendant que les médias sont lus.",
"MessageReportBugsAndContribute": "Signalez des anomalies, demandez des fonctionnalités et contribuez sur", "MessageReportBugsAndContribute": "Signalez des anomalies, demandez des fonctionnalités et contribuez sur",
"MessageSeriesAlreadyDownloaded": "Vous avez déjà téléchargé tous les livres de cette série.", "MessageSeriesAlreadyDownloaded": "Vous avez déjà téléchargé tous les livres de cette série.",
"MessageSeriesDownloadConfirm": "Télécharger le(s) {0} livre(s) manquant(s) avec {1} fichier(s), totalisant {2} vers le dossier {3}?", "MessageSeriesDownloadConfirm": "Télécharger le(s) {0} livre(s) manquant(s) avec {1} fichier(s), totalisant {2} vers le dossier {3}?",
-1
View File
@@ -13,7 +13,6 @@
"ButtonLibrary": "પુસ્તકાલય", "ButtonLibrary": "પુસ્તકાલય",
"ButtonOpenFeed": "ફીડ ખોલો", "ButtonOpenFeed": "ફીડ ખોલો",
"ButtonPlay": "ચલાવો", "ButtonPlay": "ચલાવો",
"ButtonPlaying": "ચલાવી રહ્યું છે",
"ButtonPlaylists": "પ્લેલિસ્ટ", "ButtonPlaylists": "પ્લેલિસ્ટ",
"ButtonRead": "વાંચો", "ButtonRead": "વાંચો",
"ButtonRemove": "કાઢી નાખો", "ButtonRemove": "કાઢી નાખો",
-1
View File
@@ -27,7 +27,6 @@
"ButtonLibrary": "ספרייה", "ButtonLibrary": "ספרייה",
"ButtonPlay": "נגן", "ButtonPlay": "נגן",
"ButtonPlayEpisode": "נגן פרק", "ButtonPlayEpisode": "נגן פרק",
"ButtonPlaying": "מנגן",
"ButtonPlaylists": "רשימת השמעה", "ButtonPlaylists": "רשימת השמעה",
"HeaderOpenRSSFeed": "פתח ערוץ RSS", "HeaderOpenRSSFeed": "פתח ערוץ RSS",
"LabelAddedDate": "נוסף ב-{0}" "LabelAddedDate": "נוסף ב-{0}"
-1
View File
@@ -13,7 +13,6 @@
"ButtonLibrary": "पुस्तकालय", "ButtonLibrary": "पुस्तकालय",
"ButtonOpenFeed": "फ़ीड खोलें", "ButtonOpenFeed": "फ़ीड खोलें",
"ButtonPlay": "चलाएँ", "ButtonPlay": "चलाएँ",
"ButtonPlaying": "चल रही है",
"ButtonPlaylists": "प्लेलिस्ट्स", "ButtonPlaylists": "प्लेलिस्ट्स",
"ButtonRead": "पढ़ लिया", "ButtonRead": "पढ़ लिया",
"ButtonRemove": "हटाएं", "ButtonRemove": "हटाएं",
+8 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Upravljanje lokalnim datotekama", "ButtonManageLocalFiles": "Upravljanje lokalnim datotekama",
"ButtonNewFolder": "Nova mapa", "ButtonNewFolder": "Nova mapa",
"ButtonNextEpisode": "Sljedeći nastavak", "ButtonNextEpisode": "Sljedeći nastavak",
"ButtonOk": "U redu",
"ButtonOpenFeed": "Otvori izvor", "ButtonOpenFeed": "Otvori izvor",
"ButtonOverride": "Zanemari", "ButtonOverride": "Zanemari",
"ButtonPause": "Pauziraj", "ButtonPause": "Pauziraj",
"ButtonPlay": "Reproduciraj", "ButtonPlay": "Reproduciraj",
"ButtonPlayEpisode": "Reproduciraj nastavak", "ButtonPlayEpisode": "Reproduciraj nastavak",
"ButtonPlaying": "Izvodi se",
"ButtonPlaylists": "Popisi za izvođenje", "ButtonPlaylists": "Popisi za izvođenje",
"ButtonRead": "Pročitaj", "ButtonRead": "Pročitaj",
"ButtonReadLess": "Pročitaj manje", "ButtonReadLess": "Pročitaj manje",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Postavke izvođenja", "HeaderPlaybackSettings": "Postavke izvođenja",
"HeaderPlaylist": "Popis za izvođenje", "HeaderPlaylist": "Popis za izvođenje",
"HeaderPlaylistItems": "Stavke popisa za izvođenje", "HeaderPlaylistItems": "Stavke popisa za izvođenje",
"HeaderProgressSyncFailed": "Sinkronizacija napretka nije uspjela",
"HeaderRSSFeed": "RSS izvor", "HeaderRSSFeed": "RSS izvor",
"HeaderRSSFeedGeneral": "RSS pojedinosti", "HeaderRSSFeedGeneral": "RSS pojedinosti",
"HeaderRSSFeedIsOpen": "RSS izvor je otvoren", "HeaderRSSFeedIsOpen": "RSS izvor je otvoren",
@@ -163,6 +164,7 @@
"LabelInternalAppStorage": "Unutarnja pohrana aplikacije", "LabelInternalAppStorage": "Unutarnja pohrana aplikacije",
"LabelJumpBackwardsTime": "Trajanje skoka unatrag", "LabelJumpBackwardsTime": "Trajanje skoka unatrag",
"LabelJumpForwardsTime": "Trajanje skoka unaprijed", "LabelJumpForwardsTime": "Trajanje skoka unaprijed",
"LabelKeepScreenAwake": "Drži zaslon budnim",
"LabelLanguage": "Jezik", "LabelLanguage": "Jezik",
"LabelLayout": "Prikaz", "LabelLayout": "Prikaz",
"LabelLayoutAuto": "Automatski", "LabelLayoutAuto": "Automatski",
@@ -194,6 +196,8 @@
"LabelNotFinished": "Nije dovršeno", "LabelNotFinished": "Nije dovršeno",
"LabelNotStarted": "Nije započeto", "LabelNotStarted": "Nije započeto",
"LabelNumEpisodes": "{0} nastavaka", "LabelNumEpisodes": "{0} nastavaka",
"LabelNumEpisodesIncomplete": "{0} nastavaka, {1} nedovršeno",
"LabelNumberOfEpisodes": "broj nastavaka",
"LabelOff": "Isključeno", "LabelOff": "Isključeno",
"LabelOn": "Uključeno", "LabelOn": "Uključeno",
"LabelPassword": "Zaporka", "LabelPassword": "Zaporka",
@@ -307,7 +311,10 @@
"MessageNoSeries": "Nema serijala", "MessageNoSeries": "Nema serijala",
"MessageNoUpdatesWereNecessary": "Ažuriranje nije bilo potrebno", "MessageNoUpdatesWereNecessary": "Ažuriranje nije bilo potrebno",
"MessageNoUserPlaylists": "Nemate popisa za izvođenje", "MessageNoUserPlaylists": "Nemate popisa za izvođenje",
"MessageOldServerConnectionWarning": "Veza s poslužiteljem koristi se starim ID-jem korisnika. Molimo izbrišite i ponovno dodajte ovu vezu s poslužiteljem.",
"MessageOldServerConnectionWarningHelp": "Vezu s ovim poslužiteljem postavili ste prije migracije baze podataka u inačici 2.3.0 objavljenoj u lipnju 2023. Nadolazeće ažuriranje poslužitelja onemogućit će prijavu korištenjem ove stare veze. Molimo izbrišite postojeću vezu s poslužiteljem i ponovno se povežite (korištenjem iste adrese poslužitelja i korisničkih podataka). Ukoliko imate preuzetih medijskih datoteka na ovom uređaju, morat ćete ih iznova preuzeti da bi se sinkronizirali s poslužiteljem.",
"MessagePodcastSearchField": "Upišite izraz za pretraživanje ili URL RSS izvora", "MessagePodcastSearchField": "Upišite izraz za pretraživanje ili URL RSS izvora",
"MessageProgressSyncFailed": "Zadnji pokušaj slanja napretka slušanja poslužitelju nije uspio. Nastavit ćemo s pokušajima slanja napretka svakih 15 do 60 sekundi dok god traje izvođenje medijske datoteke.",
"MessageReportBugsAndContribute": "Prijavite pogreške, zatražite značajke i doprinesite na", "MessageReportBugsAndContribute": "Prijavite pogreške, zatražite značajke i doprinesite na",
"MessageSeriesAlreadyDownloaded": "Već ste preuzeli sve knjige iz ovog serijala.", "MessageSeriesAlreadyDownloaded": "Već ste preuzeli sve knjige iz ovog serijala.",
"MessageSeriesDownloadConfirm": "Želite li preuzeti {0} knjiga koje nedostaju s {1} datoteka, ukupno {2} u mapu {3}?", "MessageSeriesDownloadConfirm": "Želite li preuzeti {0} knjiga koje nedostaju s {1} datoteka, ukupno {2} u mapu {3}?",
+9 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Helyi fájlok kezelése", "ButtonManageLocalFiles": "Helyi fájlok kezelése",
"ButtonNewFolder": "Új mappa", "ButtonNewFolder": "Új mappa",
"ButtonNextEpisode": "Következő epizód", "ButtonNextEpisode": "Következő epizód",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Hírcsatorna megnyitása", "ButtonOpenFeed": "Hírcsatorna megnyitása",
"ButtonOverride": "Felülírás", "ButtonOverride": "Felülírás",
"ButtonPause": "Szünet", "ButtonPause": "Szünet",
"ButtonPlay": "Lejátszás", "ButtonPlay": "Lejátszás",
"ButtonPlayEpisode": "Epizód lejátszása", "ButtonPlayEpisode": "Epizód lejátszása",
"ButtonPlaying": "Lejátszás folyamatban",
"ButtonPlaylists": "Lejátszási listák", "ButtonPlaylists": "Lejátszási listák",
"ButtonRead": "Olvasás", "ButtonRead": "Olvasás",
"ButtonReadLess": "Mutass kevesebbet", "ButtonReadLess": "Mutass kevesebbet",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Lejátszási beállítások", "HeaderPlaybackSettings": "Lejátszási beállítások",
"HeaderPlaylist": "Lejátszási lista", "HeaderPlaylist": "Lejátszási lista",
"HeaderPlaylistItems": "Lejátszási lista elemek", "HeaderPlaylistItems": "Lejátszási lista elemek",
"HeaderProgressSyncFailed": "Folyamat szinkronizálása nem sikerült",
"HeaderRSSFeed": "RSS Hírcsatorna", "HeaderRSSFeed": "RSS Hírcsatorna",
"HeaderRSSFeedGeneral": "RSS részletek", "HeaderRSSFeedGeneral": "RSS részletek",
"HeaderRSSFeedIsOpen": "RSS hírcsatorna nyitva van", "HeaderRSSFeedIsOpen": "RSS hírcsatorna nyitva van",
@@ -93,6 +94,7 @@
"LabelAll": "Összes", "LabelAll": "Összes",
"LabelAllowSeekingOnMediaControls": "Pozíció keresés engedélyezése a média értesítési vezérlőkön", "LabelAllowSeekingOnMediaControls": "Pozíció keresés engedélyezése a média értesítési vezérlőkön",
"LabelAlways": "Mindig", "LabelAlways": "Mindig",
"LabelAndroidAutoBrowseLimitForGrouping": "Ábécé szerinti lehívási korlát",
"LabelAndroidAutoBrowseSeriesSequenceOrder": "A sorozat könyveinek sorrendje", "LabelAndroidAutoBrowseSeriesSequenceOrder": "A sorozat könyveinek sorrendje",
"LabelAskConfirmation": "Kérjen megerősítést", "LabelAskConfirmation": "Kérjen megerősítést",
"LabelAuthor": "Szerző", "LabelAuthor": "Szerző",
@@ -161,6 +163,7 @@
"LabelInternalAppStorage": "Belső alkalmazástároló", "LabelInternalAppStorage": "Belső alkalmazástároló",
"LabelJumpBackwardsTime": "Visszaugrás ideje", "LabelJumpBackwardsTime": "Visszaugrás ideje",
"LabelJumpForwardsTime": "Előreugrás ideje", "LabelJumpForwardsTime": "Előreugrás ideje",
"LabelKeepScreenAwake": "Tartsa ébren a képernyőt",
"LabelLanguage": "Nyelv", "LabelLanguage": "Nyelv",
"LabelLayout": "Elrendezés", "LabelLayout": "Elrendezés",
"LabelLayoutAuto": "Automatikus", "LabelLayoutAuto": "Automatikus",
@@ -192,6 +195,8 @@
"LabelNotFinished": "Nem befejezett", "LabelNotFinished": "Nem befejezett",
"LabelNotStarted": "Nem kezdődött el", "LabelNotStarted": "Nem kezdődött el",
"LabelNumEpisodes": "{0} epizód", "LabelNumEpisodes": "{0} epizód",
"LabelNumEpisodesIncomplete": "{0} epizód, {1} befejezetlen",
"LabelNumberOfEpisodes": "Epizódok száma",
"LabelOff": "Kikapcsolva", "LabelOff": "Kikapcsolva",
"LabelOn": "Bekapcsolva", "LabelOn": "Bekapcsolva",
"LabelPassword": "Jelszó", "LabelPassword": "Jelszó",
@@ -305,7 +310,10 @@
"MessageNoSeries": "Nincsenek sorozatok", "MessageNoSeries": "Nincsenek sorozatok",
"MessageNoUpdatesWereNecessary": "Nem volt szükséges frissítés", "MessageNoUpdatesWereNecessary": "Nem volt szükséges frissítés",
"MessageNoUserPlaylists": "Nincsenek lejátszási listái", "MessageNoUserPlaylists": "Nincsenek lejátszási listái",
"MessageOldServerConnectionWarning": "A kiszolgáló kapcsolat beállításai egy régi felhasználói azonosítót használnak. Kérjük, törölje és adja hozzá újra ezt a szerverkapcsolatot.",
"MessageOldServerConnectionWarningHelp": "Eredetileg a 2023 júniusában megjelent 2.3.0-s verziójú adatbázis-migráció előtt állította be a kapcsolatot ehhez a kiszolgálóhoz. Egy jövőbeli kiszolgálófrissítéssel megszűnik a lehetőség, hogy ezzel a régi kapcsolattal jelentkezzen be. Kérjük, törölje a meglévő szerverkapcsolatot, és csatlakozzon újra (ugyanazzal a szervercímmel és hitelesítő adatokkal). Ha ezen az eszközön bármilyen letöltött média van, a szerverrel való szinkronizáláshoz a médiát újra le kell tölteni.",
"MessagePodcastSearchField": "Adja meg a keresési kifejezést vagy az RSS hírcsatorna URL-címét", "MessagePodcastSearchField": "Adja meg a keresési kifejezést vagy az RSS hírcsatorna URL-címét",
"MessageProgressSyncFailed": "A legutóbbi kísérlet, hogy jelentse a hallgatás folyamatát a szervernek, meghiúsult. A folyamatban lévő szinkronizálási kérelmek továbbra is 15 másodperctől 1 percig terjednek, miközben a média lejátssza.",
"MessageReportBugsAndContribute": "Hibák jelentése, funkciók kérése és hozzájárulás itt", "MessageReportBugsAndContribute": "Hibák jelentése, funkciók kérése és hozzájárulás itt",
"MessageSeriesAlreadyDownloaded": "Ön már letöltötte az összes könyvet a sorozatból.", "MessageSeriesAlreadyDownloaded": "Ön már letöltötte az összes könyvet a sorozatból.",
"MessageSeriesDownloadConfirm": "Hiányzó {0} könyv(ek) letöltése {1} fájl(ok)kal, összesen {2} mappába {3}?", "MessageSeriesDownloadConfirm": "Hiányzó {0} könyv(ek) letöltése {1} fájl(ok)kal, összesen {2} mappába {3}?",
+5 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Gestisci file locali", "ButtonManageLocalFiles": "Gestisci file locali",
"ButtonNewFolder": "Nuova cartella", "ButtonNewFolder": "Nuova cartella",
"ButtonNextEpisode": "Prossimo episodio", "ButtonNextEpisode": "Prossimo episodio",
"ButtonOk": "D'accordo",
"ButtonOpenFeed": "Apri il flusso", "ButtonOpenFeed": "Apri il flusso",
"ButtonOverride": "Oltrepassa", "ButtonOverride": "Oltrepassa",
"ButtonPause": "Pausa", "ButtonPause": "Pausa",
"ButtonPlay": "Riproduci", "ButtonPlay": "Riproduci",
"ButtonPlayEpisode": "Riproduci episodio", "ButtonPlayEpisode": "Riproduci episodio",
"ButtonPlaying": "In riproduzione",
"ButtonPlaylists": "Playlist", "ButtonPlaylists": "Playlist",
"ButtonRead": "Leggi", "ButtonRead": "Leggi",
"ButtonReadLess": "Riduci", "ButtonReadLess": "Riduci",
@@ -180,6 +180,8 @@
"LabelNarrators": "Narratori", "LabelNarrators": "Narratori",
"LabelNavigateWithVolume": "Navigare con i tasti del volume", "LabelNavigateWithVolume": "Navigare con i tasti del volume",
"LabelNavigateWithVolumeMirrored": "Invertito", "LabelNavigateWithVolumeMirrored": "Invertito",
"LabelNavigateWithVolumeWhilePlayingDisabled": "Diattivato",
"LabelNavigateWithVolumeWhilePlayingEnabled": "Attivato",
"LabelNever": "Mai", "LabelNever": "Mai",
"LabelNewestAuthors": "Nuovi autori", "LabelNewestAuthors": "Nuovi autori",
"LabelNewestEpisodes": "Nuovi episodi", "LabelNewestEpisodes": "Nuovi episodi",
@@ -187,6 +189,8 @@
"LabelNotFinished": "Da completare", "LabelNotFinished": "Da completare",
"LabelNotStarted": "Non iniziato", "LabelNotStarted": "Non iniziato",
"LabelNumEpisodes": "{0} episodi", "LabelNumEpisodes": "{0} episodi",
"LabelNumEpisodesIncomplete": "{0} episodi, {1} incompleti",
"LabelNumberOfEpisodes": "Numero di episodi",
"LabelOff": "Disattivato", "LabelOff": "Disattivato",
"LabelOn": "Attivo", "LabelOn": "Attivo",
"LabelPassword": "Password", "LabelPassword": "Password",
+1
View File
@@ -0,0 +1 @@
{}
-1
View File
@@ -28,7 +28,6 @@
"ButtonPause": "Pauzė", "ButtonPause": "Pauzė",
"ButtonPlay": "Groti", "ButtonPlay": "Groti",
"ButtonPlayEpisode": "Groti episodą", "ButtonPlayEpisode": "Groti episodą",
"ButtonPlaying": "Grojama",
"ButtonPlaylists": "Grojaraščiai", "ButtonPlaylists": "Grojaraščiai",
"ButtonRead": "Skaityti", "ButtonRead": "Skaityti",
"ButtonReadLess": "Skaityti mažiau", "ButtonReadLess": "Skaityti mažiau",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "Pauze", "ButtonPause": "Pauze",
"ButtonPlay": "Afspelen", "ButtonPlay": "Afspelen",
"ButtonPlayEpisode": "Aflevering afspelen", "ButtonPlayEpisode": "Aflevering afspelen",
"ButtonPlaying": "Speelt",
"ButtonPlaylists": "Afspeellijsten", "ButtonPlaylists": "Afspeellijsten",
"ButtonRead": "Lees", "ButtonRead": "Lees",
"ButtonReadLess": "Minder lezen", "ButtonReadLess": "Minder lezen",
+2 -1
View File
@@ -25,11 +25,12 @@
"ButtonManageLocalFiles": "Administrer Lokale Filer", "ButtonManageLocalFiles": "Administrer Lokale Filer",
"ButtonNewFolder": "Ny mappe", "ButtonNewFolder": "Ny mappe",
"ButtonNextEpisode": "Neste episode", "ButtonNextEpisode": "Neste episode",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Åpne Feed", "ButtonOpenFeed": "Åpne Feed",
"ButtonOverride": "Overstyr", "ButtonOverride": "Overstyr",
"ButtonPause": "Pause",
"ButtonPlay": "Spill av", "ButtonPlay": "Spill av",
"ButtonPlayEpisode": "Spill episode", "ButtonPlayEpisode": "Spill episode",
"ButtonPlaying": "Spiller av",
"ButtonPlaylists": "Spillelister", "ButtonPlaylists": "Spillelister",
"ButtonRead": "Les", "ButtonRead": "Les",
"ButtonRemove": "Fjern", "ButtonRemove": "Fjern",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "Wstrzymaj", "ButtonPause": "Wstrzymaj",
"ButtonPlay": "Odtwarzaj", "ButtonPlay": "Odtwarzaj",
"ButtonPlayEpisode": "Odtwórz odcinek", "ButtonPlayEpisode": "Odtwórz odcinek",
"ButtonPlaying": "Odtwarzane",
"ButtonPlaylists": "Listy odtwarzania", "ButtonPlaylists": "Listy odtwarzania",
"ButtonRead": "Czytaj", "ButtonRead": "Czytaj",
"ButtonReadLess": "Czytaj mniej", "ButtonReadLess": "Czytaj mniej",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "Pausar", "ButtonPause": "Pausar",
"ButtonPlay": "Reproduzir", "ButtonPlay": "Reproduzir",
"ButtonPlayEpisode": "Reproduzir Episódio", "ButtonPlayEpisode": "Reproduzir Episódio",
"ButtonPlaying": "Reproduzindo",
"ButtonPlaylists": "Lista de Reprodução", "ButtonPlaylists": "Lista de Reprodução",
"ButtonRead": "Ler", "ButtonRead": "Ler",
"ButtonReadLess": "Ler menos", "ButtonReadLess": "Ler menos",
+14 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Управление локальными файлами", "ButtonManageLocalFiles": "Управление локальными файлами",
"ButtonNewFolder": "Новая папка", "ButtonNewFolder": "Новая папка",
"ButtonNextEpisode": "Следующий эпизод", "ButtonNextEpisode": "Следующий эпизод",
"ButtonOk": "Ок",
"ButtonOpenFeed": "Открыть канал", "ButtonOpenFeed": "Открыть канал",
"ButtonOverride": "Переопределить", "ButtonOverride": "Переопределить",
"ButtonPause": "Пауза", "ButtonPause": "Пауза",
"ButtonPlay": "Слушать", "ButtonPlay": "Слушать",
"ButtonPlayEpisode": "Воспроизвести эпизод", "ButtonPlayEpisode": "Воспроизвести эпизод",
"ButtonPlaying": "Проигрывается",
"ButtonPlaylists": "Плейлисты", "ButtonPlaylists": "Плейлисты",
"ButtonRead": "Читать", "ButtonRead": "Читать",
"ButtonReadLess": "Читать меньше", "ButtonReadLess": "Читать меньше",
@@ -54,6 +54,7 @@
"ButtonYes": "Да", "ButtonYes": "Да",
"HeaderAccount": "Учетная запись", "HeaderAccount": "Учетная запись",
"HeaderAdvanced": "Дополнительно", "HeaderAdvanced": "Дополнительно",
"HeaderAndroidAutoSettings": "Автоматические настройки Android",
"HeaderAudioTracks": "Аудио треки", "HeaderAudioTracks": "Аудио треки",
"HeaderChapters": "Главы", "HeaderChapters": "Главы",
"HeaderCollection": "Коллекция", "HeaderCollection": "Коллекция",
@@ -74,6 +75,7 @@
"HeaderPlaybackSettings": "Настройки воспроизведения", "HeaderPlaybackSettings": "Настройки воспроизведения",
"HeaderPlaylist": "Плейлист", "HeaderPlaylist": "Плейлист",
"HeaderPlaylistItems": "Элементы списка воспроизведения", "HeaderPlaylistItems": "Элементы списка воспроизведения",
"HeaderProgressSyncFailed": "Синхронизация прогресса не удалась",
"HeaderRSSFeed": "RSS-канал", "HeaderRSSFeed": "RSS-канал",
"HeaderRSSFeedGeneral": "Сведения о RSS", "HeaderRSSFeedGeneral": "Сведения о RSS",
"HeaderRSSFeedIsOpen": "RSS-канал открыт", "HeaderRSSFeedIsOpen": "RSS-канал открыт",
@@ -92,6 +94,9 @@
"LabelAll": "Все", "LabelAll": "Все",
"LabelAllowSeekingOnMediaControls": "Разрешить перемотку элементами управления мультимедиа", "LabelAllowSeekingOnMediaControls": "Разрешить перемотку элементами управления мультимедиа",
"LabelAlways": "Всегда", "LabelAlways": "Всегда",
"LabelAndroidAutoBrowseLimitForGrouping": "Ограничение на алфавитный порядок",
"LabelAndroidAutoBrowseLimitForGroupingHelp": "Не используйте алфавитный порядок, если количество отображаемых элементов меньше указанного",
"LabelAndroidAutoBrowseSeriesSequenceOrder": "Заказ на серию книг",
"LabelAskConfirmation": "Запросить подтверждение", "LabelAskConfirmation": "Запросить подтверждение",
"LabelAuthor": "Автор", "LabelAuthor": "Автор",
"LabelAuthorFirstLast": "Автор (Имя Фамилия)", "LabelAuthorFirstLast": "Автор (Имя Фамилия)",
@@ -159,6 +164,7 @@
"LabelInternalAppStorage": "Внутреннее хранилище приложений", "LabelInternalAppStorage": "Внутреннее хранилище приложений",
"LabelJumpBackwardsTime": "Перемотка назад", "LabelJumpBackwardsTime": "Перемотка назад",
"LabelJumpForwardsTime": "Перемотка вперед", "LabelJumpForwardsTime": "Перемотка вперед",
"LabelKeepScreenAwake": "Не отключать экран",
"LabelLanguage": "Язык", "LabelLanguage": "Язык",
"LabelLayout": "Макет", "LabelLayout": "Макет",
"LabelLayoutAuto": "Авто", "LabelLayoutAuto": "Авто",
@@ -190,6 +196,8 @@
"LabelNotFinished": "Не завершено", "LabelNotFinished": "Не завершено",
"LabelNotStarted": "Не запущено", "LabelNotStarted": "Не запущено",
"LabelNumEpisodes": "{0} эпизодов", "LabelNumEpisodes": "{0} эпизодов",
"LabelNumEpisodesIncomplete": "{0} эпизодов, {1} не завершено",
"LabelNumberOfEpisodes": "# из эпизодов",
"LabelOff": "Выключить", "LabelOff": "Выключить",
"LabelOn": "Включён", "LabelOn": "Включён",
"LabelPassword": "Пароль", "LabelPassword": "Пароль",
@@ -218,6 +226,8 @@
"LabelScaleElapsedTimeBySpeed": "Масштабирование затраченного времени по скорости", "LabelScaleElapsedTimeBySpeed": "Масштабирование затраченного времени по скорости",
"LabelSeason": "Сезон", "LabelSeason": "Сезон",
"LabelSelectADevice": "Выбор девайса", "LabelSelectADevice": "Выбор девайса",
"LabelSequenceAscending": "Последовательность по возрастанию",
"LabelSequenceDescending": "Последовательность по убыванию",
"LabelSeries": "Серия", "LabelSeries": "Серия",
"LabelServerAddress": "Адрес сервера", "LabelServerAddress": "Адрес сервера",
"LabelSetEbookAsPrimary": "Установить как основную", "LabelSetEbookAsPrimary": "Установить как основную",
@@ -301,7 +311,10 @@
"MessageNoSeries": "Нет серии", "MessageNoSeries": "Нет серии",
"MessageNoUpdatesWereNecessary": "Обновления не требовались", "MessageNoUpdatesWereNecessary": "Обновления не требовались",
"MessageNoUserPlaylists": "У вас нет плейлистов", "MessageNoUserPlaylists": "У вас нет плейлистов",
"MessageOldServerConnectionWarning": "Конфигурация подключения к серверу использует старый идентификатор пользователя. Удалите и повторно добавьте это подключение к серверу.",
"MessageOldServerConnectionWarningHelp": "Первоначально вы настроили подключение к этому серверу до миграции базы данных в версии 2.3.0, выпущенной в июне 2023 года. Будущее обновление сервера уберет возможность входа с помощью этого старого подключения. Удалите существующее подключение к серверу и подключитесь снова (используя тот же адрес сервера и учетные данные). Если на этом устройстве есть загруженные медиафайлы, их необходимо будет загрузить снова для синхронизации с сервером.",
"MessagePodcastSearchField": "Введите поисковый запрос или URL-адрес RSS-канала", "MessagePodcastSearchField": "Введите поисковый запрос или URL-адрес RSS-канала",
"MessageProgressSyncFailed": "Последняя попытка сообщить о вашем прогрессе прослушивания на сервер не удалась. Запросы на синхронизацию прогресса будут продолжаться каждые 15 секунд в течении 1 минуты во время воспроизведения медиа.",
"MessageReportBugsAndContribute": "Сообщайте об ошибках, запрашивайте функции и вносите свой вклад на", "MessageReportBugsAndContribute": "Сообщайте об ошибках, запрашивайте функции и вносите свой вклад на",
"MessageSeriesAlreadyDownloaded": "Вы уже скачали все книги из этой серии.", "MessageSeriesAlreadyDownloaded": "Вы уже скачали все книги из этой серии.",
"MessageSeriesDownloadConfirm": "Загрузить недостающие {0} книг с {1} файлов общим количеством {2} в папку {3}?", "MessageSeriesDownloadConfirm": "Загрузить недостающие {0} книг с {1} файлов общим количеством {2} в папку {3}?",
+8 -1
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Upravljanje lokalnih datotek", "ButtonManageLocalFiles": "Upravljanje lokalnih datotek",
"ButtonNewFolder": "Nova mapa", "ButtonNewFolder": "Nova mapa",
"ButtonNextEpisode": "Naslednja epizoda", "ButtonNextEpisode": "Naslednja epizoda",
"ButtonOk": "V redu",
"ButtonOpenFeed": "Odpri vir", "ButtonOpenFeed": "Odpri vir",
"ButtonOverride": "Preglasi", "ButtonOverride": "Preglasi",
"ButtonPause": "Premor", "ButtonPause": "Premor",
"ButtonPlay": "Predvajaj", "ButtonPlay": "Predvajaj",
"ButtonPlayEpisode": "Predvajan epizodo", "ButtonPlayEpisode": "Predvajan epizodo",
"ButtonPlaying": "Predvajam",
"ButtonPlaylists": "Seznami predvajanj", "ButtonPlaylists": "Seznami predvajanj",
"ButtonRead": "Preberi", "ButtonRead": "Preberi",
"ButtonReadLess": "Preberi manj", "ButtonReadLess": "Preberi manj",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Nastavitve predvajanja", "HeaderPlaybackSettings": "Nastavitve predvajanja",
"HeaderPlaylist": "Seznam predvajanja", "HeaderPlaylist": "Seznam predvajanja",
"HeaderPlaylistItems": "Elementi seznama predvajanja", "HeaderPlaylistItems": "Elementi seznama predvajanja",
"HeaderProgressSyncFailed": "Sinhronizacija napredka ni uspela",
"HeaderRSSFeed": "RSS vir", "HeaderRSSFeed": "RSS vir",
"HeaderRSSFeedGeneral": "RSS podrobnosti", "HeaderRSSFeedGeneral": "RSS podrobnosti",
"HeaderRSSFeedIsOpen": "Vir RSS je odprt", "HeaderRSSFeedIsOpen": "Vir RSS je odprt",
@@ -163,6 +164,7 @@
"LabelInternalAppStorage": "Notranja shramba aplikacij", "LabelInternalAppStorage": "Notranja shramba aplikacij",
"LabelJumpBackwardsTime": "Skoči čas nazaj", "LabelJumpBackwardsTime": "Skoči čas nazaj",
"LabelJumpForwardsTime": "Preskoči čas naprej", "LabelJumpForwardsTime": "Preskoči čas naprej",
"LabelKeepScreenAwake": "Ohranjanje zaslona v stanju budnosti",
"LabelLanguage": "Jezik", "LabelLanguage": "Jezik",
"LabelLayout": "Postavitev", "LabelLayout": "Postavitev",
"LabelLayoutAuto": "Auto", "LabelLayoutAuto": "Auto",
@@ -194,6 +196,8 @@
"LabelNotFinished": "Ni dokončano", "LabelNotFinished": "Ni dokončano",
"LabelNotStarted": "Ni zagnano", "LabelNotStarted": "Ni zagnano",
"LabelNumEpisodes": "{0} epizod", "LabelNumEpisodes": "{0} epizod",
"LabelNumEpisodesIncomplete": "{0} epizod, {1} nedokončanih",
"LabelNumberOfEpisodes": "# epizod",
"LabelOff": "Izključeno", "LabelOff": "Izključeno",
"LabelOn": "Vključeno", "LabelOn": "Vključeno",
"LabelPassword": "Geslo", "LabelPassword": "Geslo",
@@ -307,7 +311,10 @@
"MessageNoSeries": "Ni serij", "MessageNoSeries": "Ni serij",
"MessageNoUpdatesWereNecessary": "Posodobitve niso bile potrebne", "MessageNoUpdatesWereNecessary": "Posodobitve niso bile potrebne",
"MessageNoUserPlaylists": "Nimate seznamov predvajanja", "MessageNoUserPlaylists": "Nimate seznamov predvajanja",
"MessageOldServerConnectionWarning": "Nastavitev povezave s strežnikom uporablja stari ID uporabnika. Izbrišite in znova dodajte to povezavo s strežnikom.",
"MessageOldServerConnectionWarningHelp": "Povezavo s tem strežnikom ste prvotno nastavili pred selitvijo baze podatkov v različici 2.3.0, izdani junija 2023. Prihodnja posodobitev strežnika bo odstranila možnost prijave s to staro povezavo. Izbrišite obstoječo povezavo s strežnikom in se znova povežite (z istim naslovom strežnika in poverilnicami). Če imate v tej napravi prenesen medij, ga boste morali znova prenesti za sinhronizacijo s strežnikom.",
"MessagePodcastSearchField": "Vnesite iskalni izraz ali URL vira RSS", "MessagePodcastSearchField": "Vnesite iskalni izraz ali URL vira RSS",
"MessageProgressSyncFailed": "Zadnji poskus poročanja strežniku o napredku poslušanja ni uspel. Zahteve za sinhronizacijo napredka se bodo med predvajanjem predstavnosti še naprej poskušale izvajati vsakih 15 sekund do 1 minuto.",
"MessageReportBugsAndContribute": "Prijavite hrošče, zahtevajte nove funkcije in prispevajte še naprej", "MessageReportBugsAndContribute": "Prijavite hrošče, zahtevajte nove funkcije in prispevajte še naprej",
"MessageSeriesAlreadyDownloaded": "Prenesli ste že vse knjige iz te serije.", "MessageSeriesAlreadyDownloaded": "Prenesli ste že vse knjige iz te serije.",
"MessageSeriesDownloadConfirm": "Prenesi manjkajoče knjige ({0}) z {1} datotekami, skupno vseh {2}, v mapo {3}?", "MessageSeriesDownloadConfirm": "Prenesi manjkajoče knjige ({0}) z {1} datotekami, skupno vseh {2}, v mapo {3}?",
+32 -28
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Hantera Lokal Filer", "ButtonManageLocalFiles": "Hantera Lokal Filer",
"ButtonNewFolder": "Ny Katalog", "ButtonNewFolder": "Ny Katalog",
"ButtonNextEpisode": "Ny Episod", "ButtonNextEpisode": "Ny Episod",
"ButtonOk": "OK",
"ButtonOpenFeed": "Öppna flöde", "ButtonOpenFeed": "Öppna flöde",
"ButtonOverride": "Åsidosätt", "ButtonOverride": "Åsidosätt",
"ButtonPause": "Pausa", "ButtonPause": "Pausa",
"ButtonPlay": "Spela", "ButtonPlay": "Spela",
"ButtonPlayEpisode": "Spela Episod", "ButtonPlayEpisode": "Spela Episod",
"ButtonPlaying": "Spelar",
"ButtonPlaylists": "Spellistor", "ButtonPlaylists": "Spellistor",
"ButtonRead": "Läs", "ButtonRead": "Läs",
"ButtonRemove": "Ta bort", "ButtonRemove": "Ta bort",
@@ -55,7 +55,7 @@
"HeaderAudioTracks": "Ljudspår", "HeaderAudioTracks": "Ljudspår",
"HeaderChapters": "Kapitel", "HeaderChapters": "Kapitel",
"HeaderCollection": "Samling", "HeaderCollection": "Samling",
"HeaderCollectionItems": "Samlingselement", "HeaderCollectionItems": "Böcker i samlingen",
"HeaderConnectionStatus": "Anslutnings Status", "HeaderConnectionStatus": "Anslutnings Status",
"HeaderDataSettings": "Data Inställningar", "HeaderDataSettings": "Data Inställningar",
"HeaderDetails": "Detaljer", "HeaderDetails": "Detaljer",
@@ -63,7 +63,7 @@
"HeaderEbookFiles": "E-boksfiler", "HeaderEbookFiles": "E-boksfiler",
"HeaderEpisodes": "Avsnitt", "HeaderEpisodes": "Avsnitt",
"HeaderEreaderSettings": "E-boksinställningar", "HeaderEreaderSettings": "E-boksinställningar",
"HeaderLatestEpisodes": "Senaste avsnitt", "HeaderLatestEpisodes": "Senaste avsnitten",
"HeaderLibraries": "Bibliotek", "HeaderLibraries": "Bibliotek",
"HeaderLocalFolders": "Lokala Kataloger", "HeaderLocalFolders": "Lokala Kataloger",
"HeaderLocalLibraryItems": "Lokala Bibliotek Filer", "HeaderLocalLibraryItems": "Lokala Bibliotek Filer",
@@ -71,21 +71,22 @@
"HeaderOpenRSSFeed": "Öppna RSS-flöde", "HeaderOpenRSSFeed": "Öppna RSS-flöde",
"HeaderPlaybackSettings": "Uppspelningsinställningar", "HeaderPlaybackSettings": "Uppspelningsinställningar",
"HeaderPlaylist": "Spellista", "HeaderPlaylist": "Spellista",
"HeaderPlaylistItems": "Spellistobjekt", "HeaderPlaylistItems": "Böcker i spellistan",
"HeaderRSSFeed": "RSS flöde", "HeaderRSSFeed": "RSS flöde",
"HeaderRSSFeedGeneral": "RSS-information", "HeaderRSSFeedGeneral": "RSS-information",
"HeaderRSSFeedIsOpen": "RSS-flödet är öppet", "HeaderRSSFeedIsOpen": "RSS-flödet är öppet",
"HeaderSelectDownloadLocation": "Välj Nedladdnings Plats", "HeaderSelectDownloadLocation": "Välj Nedladdnings Plats",
"HeaderSettings": "Inställningar", "HeaderSettings": "Inställningar",
"HeaderSleepTimer": "Sovtidtagare", "HeaderSleepTimer": "Timer för att sova",
"HeaderSleepTimerSettings": "Sovtimer Inställningar", "HeaderSleepTimerSettings": "Sovtimer Inställningar",
"HeaderStatsMinutesListeningChart": "Minuters lyssning (senaste 7 dagar)", "HeaderStatsMinutesListeningChart": "Minuters lyssning (senaste 7 dagarna)",
"HeaderStatsRecentSessions": "Senaste sessioner", "HeaderStatsRecentSessions": "Senaste tillfällena",
"HeaderTableOfContents": "Innehållsförteckning", "HeaderTableOfContents": "Innehållsförteckning",
"HeaderUserInterfaceSettings": "Användargränssnittsinställningar", "HeaderUserInterfaceSettings": "Användargränssnittsinställningar",
"HeaderYourStats": "Dina statistik", "HeaderYourStats": "Dina statistik",
"LabelAddToPlaylist": "Lägg till i Spellista", "LabelAddToPlaylist": "Lägg till i en spellista",
"LabelAddedAt": "Tillagd vid", "LabelAddedAt": "Tillagd vid",
"LabelAddedDate": "Adderad {0}",
"LabelAll": "Alla", "LabelAll": "Alla",
"LabelAllowSeekingOnMediaControls": "Tillåt positionssökning på medieaviseringskontroller", "LabelAllowSeekingOnMediaControls": "Tillåt positionssökning på medieaviseringskontroller",
"LabelAlways": "Alltid", "LabelAlways": "Alltid",
@@ -104,12 +105,12 @@
"LabelChapterTrack": "Kapitel Spår", "LabelChapterTrack": "Kapitel Spår",
"LabelChapters": "Kapitel", "LabelChapters": "Kapitel",
"LabelClosePlayer": "Stäng spelaren", "LabelClosePlayer": "Stäng spelaren",
"LabelCollapseSeries": "Fäll ihop serie", "LabelCollapseSeries": "Komprimera serier",
"LabelComplete": "Komplett", "LabelComplete": "Komplett",
"LabelContinueBooks": "Fortsätt Böcker", "LabelContinueBooks": "Fortsätt Böcker",
"LabelContinueEpisodes": "Fortsätt Episoder", "LabelContinueEpisodes": "Fortsätt Episoder",
"LabelContinueListening": "Fortsätt Lyssna", "LabelContinueListening": "Fortsätt att lyssna",
"LabelContinueReading": "Fortsätt Läsa", "LabelContinueReading": "Fortsätt att läsa",
"LabelContinueSeries": "Forsätt Serie", "LabelContinueSeries": "Forsätt Serie",
"LabelCustomTime": "Anpassad tid", "LabelCustomTime": "Anpassad tid",
"LabelDescription": "Beskrivning", "LabelDescription": "Beskrivning",
@@ -120,13 +121,13 @@
"LabelDisableShakeToResetHelp": "Om du skakar enheten medan timern är igång eller inom 2 minuter efter att timern har löpt ut återställs insomningstimern. Aktivera den här inställningen för att inaktivera skakning för att återställa.", "LabelDisableShakeToResetHelp": "Om du skakar enheten medan timern är igång eller inom 2 minuter efter att timern har löpt ut återställs insomningstimern. Aktivera den här inställningen för att inaktivera skakning för att återställa.",
"LabelDisableVibrateOnReset": "Inaktivera vibration vid återställning", "LabelDisableVibrateOnReset": "Inaktivera vibration vid återställning",
"LabelDisableVibrateOnResetHelp": "När insomningstimern återställs kommer din enhet att vibrera. Aktivera den här inställningen för att inte vibrera när insomningstimern återställs.", "LabelDisableVibrateOnResetHelp": "När insomningstimern återställs kommer din enhet att vibrera. Aktivera den här inställningen för att inte vibrera när insomningstimern återställs.",
"LabelDiscover": "Upptäck", "LabelDiscover": "Några förslag",
"LabelDownload": "Ladda ner", "LabelDownload": "Ladda ner",
"LabelDownloadUsingCellular": "Ladda ner med mobildata", "LabelDownloadUsingCellular": "Ladda ner med mobildata",
"LabelDownloaded": "Nedladdat", "LabelDownloaded": "Nedladdat",
"LabelDuration": "Varaktighet", "LabelDuration": "Varaktighet",
"LabelEbook": "E-bok", "LabelEbook": "E-bok",
"LabelEbooks": "Eböcker", "LabelEbooks": "E-böcker",
"LabelEnable": "Aktivera", "LabelEnable": "Aktivera",
"LabelEnableMp3IndexSeeking": "Aktivera mp3 index sökning", "LabelEnableMp3IndexSeeking": "Aktivera mp3 index sökning",
"LabelEnableMp3IndexSeekingHelp": "Den här inställningen bör endast aktiveras om du har mp3-filer som inte söker korrekt. Felaktig sökning beror med största sannolikhet på MP3-filer med variabel birate (VBR). Den här inställningen tvingar fram indexsökning, där en tid-till-byte-mappning byggs upp när filen läses. I vissa fall med stora MP3-filer blir det en fördröjning vid sökning mot slutet av filen.", "LabelEnableMp3IndexSeekingHelp": "Den här inställningen bör endast aktiveras om du har mp3-filer som inte söker korrekt. Felaktig sökning beror med största sannolikhet på MP3-filer med variabel birate (VBR). Den här inställningen tvingar fram indexsökning, där en tid-till-byte-mappning byggs upp när filen läses. I vissa fall med stora MP3-filer blir det en fördröjning vid sökning mot slutet av filen.",
@@ -136,8 +137,8 @@
"LabelEpisode": "Avsnitt", "LabelEpisode": "Avsnitt",
"LabelFeedURL": "Flödes-URL", "LabelFeedURL": "Flödes-URL",
"LabelFile": "Fil", "LabelFile": "Fil",
"LabelFileBirthtime": "Födelse-tidpunkt för fil", "LabelFileBirthtime": "Tidpunkt, filen skapades",
"LabelFileModified": "Fil ändrad", "LabelFileModified": "Tidpunkt, filen ändrades",
"LabelFilename": "Filnamn", "LabelFilename": "Filnamn",
"LabelFinished": "Avslutad", "LabelFinished": "Avslutad",
"LabelFolder": "Mapp", "LabelFolder": "Mapp",
@@ -146,8 +147,8 @@
"LabelGenre": "Genre", "LabelGenre": "Genre",
"LabelGenres": "Genrer", "LabelGenres": "Genrer",
"LabelHapticFeedback": "Haptisk feedback", "LabelHapticFeedback": "Haptisk feedback",
"LabelHasEbook": "Har E-bok", "LabelHasEbook": "Har e-bok",
"LabelHasSupplementaryEbook": "Har komplimenterande E-bok", "LabelHasSupplementaryEbook": "Har kompletterande e-bok",
"LabelHeavy": "Tung", "LabelHeavy": "Tung",
"LabelHigh": "Hög", "LabelHigh": "Hög",
"LabelHost": "Värd", "LabelHost": "Värd",
@@ -178,11 +179,11 @@
"LabelNavigateWithVolume": "Navigera med volymknapparna", "LabelNavigateWithVolume": "Navigera med volymknapparna",
"LabelNavigateWithVolumeMirrored": "Speglad", "LabelNavigateWithVolumeMirrored": "Speglad",
"LabelNever": "Aldrig", "LabelNever": "Aldrig",
"LabelNewestAuthors": "Senast tillagda författare", "LabelNewestAuthors": "Senaste författarna",
"LabelNewestEpisodes": "Senast tillagda avsnitt", "LabelNewestEpisodes": "Senast tillagda avsnitt",
"LabelNo": "Nej", "LabelNo": "Nej",
"LabelNotFinished": "Ej avslutad", "LabelNotFinished": "Ej avslutad",
"LabelNotStarted": "Inte påbörjad", "LabelNotStarted": "Ej påbörjad",
"LabelOff": "Av", "LabelOff": "Av",
"LabelOn": "På", "LabelOn": "På",
"LabelPassword": "Lösenord", "LabelPassword": "Lösenord",
@@ -204,7 +205,7 @@
"LabelRandomly": "Slumpartat", "LabelRandomly": "Slumpartat",
"LabelRead": "Läst", "LabelRead": "Läst",
"LabelReadAgain": "Läs igen", "LabelReadAgain": "Läs igen",
"LabelRecentSeries": "Senaste serier", "LabelRecentSeries": "Nyaste serierna",
"LabelRecentlyAdded": "Nyligen tillagd", "LabelRecentlyAdded": "Nyligen tillagd",
"LabelRemoveFromPlaylist": "Ta bort från spellista", "LabelRemoveFromPlaylist": "Ta bort från spellista",
"LabelScaleElapsedTimeBySpeed": "Skaländra uppspelningsposition efter uppspelningshastighet.", "LabelScaleElapsedTimeBySpeed": "Skaländra uppspelningsposition efter uppspelningshastighet.",
@@ -217,17 +218,17 @@
"LabelShakeSensitivity": "Skakkänslighet", "LabelShakeSensitivity": "Skakkänslighet",
"LabelShowAll": "Visa alla", "LabelShowAll": "Visa alla",
"LabelSize": "Storlek", "LabelSize": "Storlek",
"LabelSleepTimer": "Sleeptimer", "LabelSleepTimer": "Sovtimer",
"LabelStart": "Starta", "LabelStart": "Start",
"LabelStartTime": "Starttid", "LabelStartTime": "Starttid",
"LabelStatsBestDay": "Bästa dag", "LabelStatsBestDay": "Bästa dag",
"LabelStatsDailyAverage": "Dagligt genomsnitt", "LabelStatsDailyAverage": "Dagligt genomsnitt",
"LabelStatsDays": "Dagar", "LabelStatsDays": "Dagar",
"LabelStatsDaysListened": "Dagar lyssnade", "LabelStatsDaysListened": "dagars lyssnande",
"LabelStatsInARow": "i rad", "LabelStatsInARow": "i rad",
"LabelStatsItemsFinished": "Objekt avslutade", "LabelStatsItemsFinished": "böcker avslutade",
"LabelStatsMinutes": "minuter", "LabelStatsMinutes": "minuter",
"LabelStatsMinutesListening": "Minuter av lyssnande", "LabelStatsMinutesListening": "minuters lyssnande",
"LabelStatsWeekListening": "Veckans lyssnande", "LabelStatsWeekListening": "Veckans lyssnande",
"LabelStreamingUsingCellular": "Strömma över mobildata", "LabelStreamingUsingCellular": "Strömma över mobildata",
"LabelTag": "Tagg", "LabelTag": "Tagg",
@@ -241,12 +242,15 @@
"LabelTotalTrack": "Total Spår", "LabelTotalTrack": "Total Spår",
"LabelTracks": "Spår", "LabelTracks": "Spår",
"LabelType": "Typ", "LabelType": "Typ",
"LabelUnknown": "Okänd",
"LabelUnlockPlayer": "Lås upp spelare", "LabelUnlockPlayer": "Lås upp spelare",
"LabelUseBookshelfView": "Använd bokhyllevyn", "LabelUseBookshelfView": "Använd bokhyllevyn",
"LabelUser": "Användare", "LabelUser": "Användare",
"LabelUsername": "Användarnamn", "LabelUsername": "Användarnamn",
"LabelVeryHigh": "Väldigt hög", "LabelVeryHigh": "Väldigt hög",
"LabelVeryLow": "Väldigt låg", "LabelVeryLow": "Väldigt låg",
"LabelYearReviewHide": "Dölj årets sammanställning",
"LabelYearReviewShow": "Visa årets sammanställning",
"LabelYourBookmarks": "Dina bokmärken", "LabelYourBookmarks": "Dina bokmärken",
"LabelYourProgress": "Din framsteg", "LabelYourProgress": "Din framsteg",
"MessageAndroid10Downloads": "Android 10 och lägre använder intern applagring för nedladdningar.", "MessageAndroid10Downloads": "Android 10 och lägre använder intern applagring för nedladdningar.",
@@ -282,7 +286,7 @@
"MessageNoChapters": "Inga kapitel", "MessageNoChapters": "Inga kapitel",
"MessageNoItems": "Inga objekt", "MessageNoItems": "Inga objekt",
"MessageNoItemsFound": "Inga objekt hittades", "MessageNoItemsFound": "Inga objekt hittades",
"MessageNoListeningSessions": "Inga lyssningssessioner", "MessageNoListeningSessions": "Inga lyssningstillfällen",
"MessageNoMediaFolders": "Inga Mediamappar", "MessageNoMediaFolders": "Inga Mediamappar",
"MessageNoNetworkConnection": "Ingen nätverksanslutning", "MessageNoNetworkConnection": "Ingen nätverksanslutning",
"MessageNoPodcastsFound": "Inga podcasts hittade", "MessageNoPodcastsFound": "Inga podcasts hittade",
@@ -298,8 +302,8 @@
"ToastBookmarkRemoveFailed": "Det gick inte att ta bort bokmärket", "ToastBookmarkRemoveFailed": "Det gick inte att ta bort bokmärket",
"ToastBookmarkUpdateFailed": "Det gick inte att uppdatera bokmärket", "ToastBookmarkUpdateFailed": "Det gick inte att uppdatera bokmärket",
"ToastDownloadNotAllowedOnCellular": "Nedladdning tillåts inte över mobildata", "ToastDownloadNotAllowedOnCellular": "Nedladdning tillåts inte över mobildata",
"ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera som färdig", "ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera den som avslutad",
"ToastItemMarkedAsNotFinishedFailed": "Misslyckades med att markera som ej färdig", "ToastItemMarkedAsNotFinishedFailed": "Misslyckades med att markera den som ej avslutad",
"ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan", "ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
"ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten", "ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten",
"ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt", "ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",
+10 -2
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "Керування локальними файлами", "ButtonManageLocalFiles": "Керування локальними файлами",
"ButtonNewFolder": "Нова тека", "ButtonNewFolder": "Нова тека",
"ButtonNextEpisode": "Наступний епізод", "ButtonNextEpisode": "Наступний епізод",
"ButtonOk": "Добре",
"ButtonOpenFeed": "Відкрити стрічку", "ButtonOpenFeed": "Відкрити стрічку",
"ButtonOverride": "Перевизначити", "ButtonOverride": "Перевизначити",
"ButtonPause": "Призупинити", "ButtonPause": "Призупинити",
"ButtonPlay": "Слухати", "ButtonPlay": "Слухати",
"ButtonPlayEpisode": "Слухати епізод", "ButtonPlayEpisode": "Слухати епізод",
"ButtonPlaying": "Відтворюється",
"ButtonPlaylists": "Списки відтворення", "ButtonPlaylists": "Списки відтворення",
"ButtonRead": "Читати", "ButtonRead": "Читати",
"ButtonReadLess": "Читати менше", "ButtonReadLess": "Читати менше",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "Налаштування відтворення", "HeaderPlaybackSettings": "Налаштування відтворення",
"HeaderPlaylist": "Список відтворення", "HeaderPlaylist": "Список відтворення",
"HeaderPlaylistItems": "Елементи списку відтворення", "HeaderPlaylistItems": "Елементи списку відтворення",
"HeaderProgressSyncFailed": "Помилка синхронізації прогресу",
"HeaderRSSFeed": "RSS-канал", "HeaderRSSFeed": "RSS-канал",
"HeaderRSSFeedGeneral": "Деталі RSS", "HeaderRSSFeedGeneral": "Деталі RSS",
"HeaderRSSFeedIsOpen": "RSS-канал відкрито", "HeaderRSSFeedIsOpen": "RSS-канал відкрито",
@@ -163,6 +164,7 @@
"LabelInternalAppStorage": "Внутрішня пам'ять додатку", "LabelInternalAppStorage": "Внутрішня пам'ять додатку",
"LabelJumpBackwardsTime": "Час відмотування назад", "LabelJumpBackwardsTime": "Час відмотування назад",
"LabelJumpForwardsTime": "Час перемотування вперед", "LabelJumpForwardsTime": "Час перемотування вперед",
"LabelKeepScreenAwake": "Тримайте екран активним",
"LabelLanguage": "Мова", "LabelLanguage": "Мова",
"LabelLayout": "Вигляд", "LabelLayout": "Вигляд",
"LabelLayoutAuto": "Авто", "LabelLayoutAuto": "Авто",
@@ -194,6 +196,8 @@
"LabelNotFinished": "Незавершені", "LabelNotFinished": "Незавершені",
"LabelNotStarted": "Непочаті", "LabelNotStarted": "Непочаті",
"LabelNumEpisodes": "{0} епізодів", "LabelNumEpisodes": "{0} епізодів",
"LabelNumEpisodesIncomplete": "{0} серій, {1} не завершено",
"LabelNumberOfEpisodes": "Кількість серій",
"LabelOff": "Вимкнути", "LabelOff": "Вимкнути",
"LabelOn": "Увімкнено", "LabelOn": "Увімкнено",
"LabelPassword": "Пароль", "LabelPassword": "Пароль",
@@ -233,7 +237,7 @@
"LabelSize": "Розмір", "LabelSize": "Розмір",
"LabelSleepTimer": "Таймер вимкнення", "LabelSleepTimer": "Таймер вимкнення",
"LabelStart": "Початок", "LabelStart": "Початок",
"LabelStartTime": "Час початку", "LabelStartTime": "Час Початку",
"LabelStatsBestDay": "Найкращий день", "LabelStatsBestDay": "Найкращий день",
"LabelStatsDailyAverage": "В середньому за добу", "LabelStatsDailyAverage": "В середньому за добу",
"LabelStatsDays": "Днів", "LabelStatsDays": "Днів",
@@ -273,6 +277,7 @@
"MessageBookshelfEmpty": "Полиця порожня", "MessageBookshelfEmpty": "Полиця порожня",
"MessageConfirmDeleteLocalEpisode": "Видалити локальний епізод \"{0}\" з вашого пристрою? Файл лишиться на сервері.", "MessageConfirmDeleteLocalEpisode": "Видалити локальний епізод \"{0}\" з вашого пристрою? Файл лишиться на сервері.",
"MessageConfirmDeleteLocalFiles": "Видалити локальні файли цього елемента з вашого пристрою? Файли лишаться на сервері.", "MessageConfirmDeleteLocalFiles": "Видалити локальні файли цього елемента з вашого пристрою? Файли лишаться на сервері.",
"MessageConfirmDisableAutoTimer": "Ви впевнені, що бажаєте вимкнути автоматичний таймер до кінця сьогоднішнього дня? Таймер буде знову ввімкнено в кінці цього періоду автоматичного переходу в режим сну або якщо ви перезапустите програму.",
"MessageConfirmDiscardProgress": "Ви дійсно бажаєте скинути ваш прогрес?", "MessageConfirmDiscardProgress": "Ви дійсно бажаєте скинути ваш прогрес?",
"MessageConfirmDownloadUsingCellular": "Ви збираєтеся завантажувати через мобільний інтернет. Оператор може брати кошти. Бажаєте продовжити?", "MessageConfirmDownloadUsingCellular": "Ви збираєтеся завантажувати через мобільний інтернет. Оператор може брати кошти. Бажаєте продовжити?",
"MessageConfirmMarkAsFinished": "Ви дійсно бажаєте позначити цей елемент завершеним?", "MessageConfirmMarkAsFinished": "Ви дійсно бажаєте позначити цей елемент завершеним?",
@@ -307,7 +312,10 @@
"MessageNoSeries": "Серії відсутні", "MessageNoSeries": "Серії відсутні",
"MessageNoUpdatesWereNecessary": "Оновлень не потрібно", "MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
"MessageNoUserPlaylists": "У вас немає списків відтворення", "MessageNoUserPlaylists": "У вас немає списків відтворення",
"MessageOldServerConnectionWarning": "Конфігурація підключення до сервера використовує старий ідентифікатор користувача. Видаліть і додайте це підключення до сервера заново.",
"MessageOldServerConnectionWarningHelp": "Ви спочатку налаштували з’єднання з цим сервером перед міграцією бази даних у версії 2.3.0, випущеній у червні 2023 року. Майбутнє оновлення сервера скасує можливість входу за допомогою цього старого з’єднання. Будь ласка, видаліть існуюче підключення до сервера та підключіться знову (використовуючи ту саму адресу сервера та облікові дані). Якщо на цьому пристрої є будь-які завантажені медіафайли, їх потрібно буде завантажити ще раз, щоб синхронізувати із сервером.",
"MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки", "MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки",
"MessageProgressSyncFailed": "Остання спроба повідомити про прогрес прослуховування на сервер не вдалася. Під час відтворення мультимедійних файлів кожні 15 секунд – 1 хвилину надсилатимуться запити на синхронізацію.",
"MessageReportBugsAndContribute": "Повідомляйте про помилки, пропонуйте функції та долучайтеся на", "MessageReportBugsAndContribute": "Повідомляйте про помилки, пропонуйте функції та долучайтеся на",
"MessageSeriesAlreadyDownloaded": "Ви вже завантажили всі книги в цій серії.", "MessageSeriesAlreadyDownloaded": "Ви вже завантажили всі книги в цій серії.",
"MessageSeriesDownloadConfirm": "Завантажити відсутні {0} книгу(ок) з {1} файл(ів), загалом {2}, до папки {3}?", "MessageSeriesDownloadConfirm": "Завантажити відсутні {0} книгу(ок) з {1} файл(ів), загалом {2}, до папки {3}?",
-1
View File
@@ -32,7 +32,6 @@
"ButtonOverride": "Bỏ Qua", "ButtonOverride": "Bỏ Qua",
"ButtonPause": "Tạm Dừng", "ButtonPause": "Tạm Dừng",
"ButtonPlay": "Phát", "ButtonPlay": "Phát",
"ButtonPlaying": "Đang Phát",
"ButtonPlaylists": "Danh Sách Phát", "ButtonPlaylists": "Danh Sách Phát",
"ButtonRead": "Đọc", "ButtonRead": "Đọc",
"ButtonRemove": "Xóa", "ButtonRemove": "Xóa",
+10 -3
View File
@@ -29,12 +29,12 @@
"ButtonManageLocalFiles": "管理本地文件", "ButtonManageLocalFiles": "管理本地文件",
"ButtonNewFolder": "新建文件夹", "ButtonNewFolder": "新建文件夹",
"ButtonNextEpisode": "下一集", "ButtonNextEpisode": "下一集",
"ButtonOk": "确定",
"ButtonOpenFeed": "打开源", "ButtonOpenFeed": "打开源",
"ButtonOverride": "覆盖", "ButtonOverride": "覆盖",
"ButtonPause": "暂停", "ButtonPause": "暂停",
"ButtonPlay": "播放", "ButtonPlay": "播放",
"ButtonPlayEpisode": "播放剧集", "ButtonPlayEpisode": "播放剧集",
"ButtonPlaying": "正在播放",
"ButtonPlaylists": "播放列表", "ButtonPlaylists": "播放列表",
"ButtonRead": "读取", "ButtonRead": "读取",
"ButtonReadLess": "阅读较少", "ButtonReadLess": "阅读较少",
@@ -75,6 +75,7 @@
"HeaderPlaybackSettings": "播放设置", "HeaderPlaybackSettings": "播放设置",
"HeaderPlaylist": "播放列表", "HeaderPlaylist": "播放列表",
"HeaderPlaylistItems": "播放列表项目", "HeaderPlaylistItems": "播放列表项目",
"HeaderProgressSyncFailed": "进度同步失败",
"HeaderRSSFeed": "RSS 源", "HeaderRSSFeed": "RSS 源",
"HeaderRSSFeedGeneral": "RSS 源概述", "HeaderRSSFeedGeneral": "RSS 源概述",
"HeaderRSSFeedIsOpen": "RSS 源已打开", "HeaderRSSFeedIsOpen": "RSS 源已打开",
@@ -82,7 +83,7 @@
"HeaderSettings": "设置", "HeaderSettings": "设置",
"HeaderSleepTimer": "睡眠计时", "HeaderSleepTimer": "睡眠计时",
"HeaderSleepTimerSettings": "睡眠计时器设置", "HeaderSleepTimerSettings": "睡眠计时器设置",
"HeaderStatsMinutesListeningChart": "收听分钟数(最近7天)", "HeaderStatsMinutesListeningChart": "收听分钟数 (最近7天)",
"HeaderStatsRecentSessions": "历史会话", "HeaderStatsRecentSessions": "历史会话",
"HeaderTableOfContents": "目录", "HeaderTableOfContents": "目录",
"HeaderUserInterfaceSettings": "用户界面设置", "HeaderUserInterfaceSettings": "用户界面设置",
@@ -163,6 +164,7 @@
"LabelInternalAppStorage": "应用内部存储", "LabelInternalAppStorage": "应用内部存储",
"LabelJumpBackwardsTime": "快退时间", "LabelJumpBackwardsTime": "快退时间",
"LabelJumpForwardsTime": "快进时间", "LabelJumpForwardsTime": "快进时间",
"LabelKeepScreenAwake": "保持屏幕唤醒",
"LabelLanguage": "语言", "LabelLanguage": "语言",
"LabelLayout": "布局", "LabelLayout": "布局",
"LabelLayoutAuto": "自动", "LabelLayoutAuto": "自动",
@@ -194,6 +196,8 @@
"LabelNotFinished": "未听完", "LabelNotFinished": "未听完",
"LabelNotStarted": "未开始", "LabelNotStarted": "未开始",
"LabelNumEpisodes": "{0} 个剧集", "LabelNumEpisodes": "{0} 个剧集",
"LabelNumEpisodesIncomplete": "共 {0} 集, {1} 集未完成",
"LabelNumberOfEpisodes": "# 集数",
"LabelOff": "关闭", "LabelOff": "关闭",
"LabelOn": "打开", "LabelOn": "打开",
"LabelPassword": "密码", "LabelPassword": "密码",
@@ -269,7 +273,7 @@
"MessageAndroid10Downloads": "Android 10 及以下版本将使用内部应用程序存储进行下载.", "MessageAndroid10Downloads": "Android 10 及以下版本将使用内部应用程序存储进行下载.",
"MessageAttemptingServerConnection": "正在尝试连接服务器...", "MessageAttemptingServerConnection": "正在尝试连接服务器...",
"MessageAudiobookshelfServerNotConnected": "Audiobookshelf 服务器未连接", "MessageAudiobookshelfServerNotConnected": "Audiobookshelf 服务器未连接",
"MessageAudiobookshelfServerRequired": "<strong>重要</strong>此應用程式設計為與您或您認識的人所主機的 Audiobookshelf 服器配合使用。此應用程式不提供任何內容。", "MessageAudiobookshelfServerRequired": "<strong>重要提示!</strong>此应用旨在与你或你认识的人托管的 Audiobookshelf 服器配合使用. 此应用不提供任何内容.",
"MessageBookshelfEmpty": "书架是空的", "MessageBookshelfEmpty": "书架是空的",
"MessageConfirmDeleteLocalEpisode": "要从设备中删除本地剧集 \"{0}\" 吗? 服务器上的文件将不受影响.", "MessageConfirmDeleteLocalEpisode": "要从设备中删除本地剧集 \"{0}\" 吗? 服务器上的文件将不受影响.",
"MessageConfirmDeleteLocalFiles": "要从设备中删除此项目的本地文件吗? 服务器上的文件和你的进度将不受影响.", "MessageConfirmDeleteLocalFiles": "要从设备中删除此项目的本地文件吗? 服务器上的文件和你的进度将不受影响.",
@@ -307,7 +311,10 @@
"MessageNoSeries": "没有系列", "MessageNoSeries": "没有系列",
"MessageNoUpdatesWereNecessary": "无需更新", "MessageNoUpdatesWereNecessary": "无需更新",
"MessageNoUserPlaylists": "你没有播放列表", "MessageNoUserPlaylists": "你没有播放列表",
"MessageOldServerConnectionWarning": "服务器连接配置正在使用旧的用户 ID. 请删除并重新添加此服务器连接.",
"MessageOldServerConnectionWarningHelp": "您最初在 2023 年 6 月发布的 2.3.0 版本中进行数据库迁移之前设置了与此服务器的连接. 未来的服务器更新将取消使用此旧连接登录的功能. 请删除现有的服务器连接并重新连接 (使用相同的服务器地址和凭据). 如果您在此设备上有任何下载的媒体, 则需要再次下载该媒体才能与服务器同步.",
"MessagePodcastSearchField": "输入搜索词或 RSS 源 URL", "MessagePodcastSearchField": "输入搜索词或 RSS 源 URL",
"MessageProgressSyncFailed": "向服务器报告收听进度的最新尝试失败. 播放媒体时, 将继续每 15 秒至 1 分钟尝试一次进度同步请求.",
"MessageReportBugsAndContribute": "报告错误、请求功能和贡献在", "MessageReportBugsAndContribute": "报告错误、请求功能和贡献在",
"MessageSeriesAlreadyDownloaded": "你已下载此系列的所有书籍.", "MessageSeriesAlreadyDownloaded": "你已下载此系列的所有书籍.",
"MessageSeriesDownloadConfirm": "将缺失的 {0} 本图书和 {1} 个文件 (共 {2} 个) 下载至文件夹 {3}?", "MessageSeriesDownloadConfirm": "将缺失的 {0} 本图书和 {1} 个文件 (共 {2} 个) 下载至文件夹 {3}?",
-1
View File
@@ -34,7 +34,6 @@
"ButtonPause": "暫停", "ButtonPause": "暫停",
"ButtonPlay": "播放", "ButtonPlay": "播放",
"ButtonPlayEpisode": "播放劇集", "ButtonPlayEpisode": "播放劇集",
"ButtonPlaying": "正在播放",
"ButtonPlaylists": "播放列表", "ButtonPlaylists": "播放列表",
"ButtonRead": "讀取", "ButtonRead": "讀取",
"ButtonRemove": "移除", "ButtonRemove": "移除",