Compare commits

...

457 Commits

Author SHA1 Message Date
advplyr 086954fb9c Version bump v2.6.0 2023-11-27 17:41:47 -06:00
advplyr f243ad14e0 Add help link to oidc guide 2023-11-27 17:10:31 -06:00
advplyr 2e5822b7c8 Merge pull request #2305 from mikiher/nfo-metadata
Add NFO metadata source
2023-11-26 14:49:04 -06:00
advplyr 3d468339b3 Update parse nfo metadata test for description 2023-11-26 14:41:19 -06:00
advplyr b4c14fc78d Parse NFO comma separated strings remove empty strings 2023-11-26 14:38:25 -06:00
advplyr d9584174ff Parse NFO trim final parsed description 2023-11-26 14:33:35 -06:00
advplyr 36e00e8d6a Merge master 2023-11-26 13:54:06 -06:00
advplyr 5e69b54eb0 Reverse order of metadata precedence in UI, add translations 2023-11-26 13:45:43 -06:00
advplyr 5a8c60a8bc Merge pull request #2343 from mikiher/caching
Simple API Caching for /libraries* requests
2023-11-26 12:33:54 -06:00
mikiher 3ff41f2b43 Cache HTTP headers and status 2023-11-25 23:49:56 +02:00
advplyr 17cab0d3a8 Merge pull request #2351 from JBlond/master
de translation follow up
2023-11-25 12:18:08 -06:00
JBlond 0fac9e367d de translation follow up
for 2e06ae01a1
2023-11-25 19:10:26 +01:00
advplyr bf0bcf8967 Merge pull request #2336 from JBlond/master
de language translation follow up
2023-11-25 11:31:59 -06:00
advplyr 2e06ae01a1 Merge pull request #2326 from lkiesow/hide-dev-logs
Allow enabling dev logs
2023-11-25 10:36:50 -06:00
mikiher 288a32cc1e Merge branch 'caching' of https://github.com/mikiher/audiobookshelf into caching 2023-11-25 08:14:54 +02:00
mikiher 26fc3a1966 Remove currently unused time measurement utils 2023-11-25 08:14:45 +02:00
advplyr 9d257ebecd Update:Home page shelf bulk items added socket event only adds new items to the recently added shelf instead of refreshing all shelves #2323 2023-11-24 15:36:42 -06:00
advplyr 1a046a9bcb Merge branch 'master' into caching 2023-11-24 14:38:27 -06:00
advplyr 7a9c869ac5 Ignore sequelize hooks when updating user lastSeen on socket authentication 2023-11-24 14:27:32 -06:00
advplyr 572fb0993c Rename ApiCacheManager to add .js file extension 2023-11-24 14:20:14 -06:00
advplyr 9beee3ed65 Fix:Change password api endpoint 2023-11-23 15:14:49 -06:00
mikiher ab19e25586 Remove unnecessary timing measurements 2023-11-23 09:56:37 +02:00
mikiher 07d7d16418 Use a single router.get for API cache middleware 2023-11-23 09:55:55 +02:00
mikiher 5e1e748c71 Add ApiCacheManager unit test 2023-11-23 09:53:52 +02:00
advplyr 6651ad0d45 Update:Added translation strings for OIDC auth 2023-11-22 12:55:01 -06:00
advplyr 288beae874 Update:OIDC auth auto launch setting description to include manual override path 2023-11-22 12:38:11 -06:00
advplyr 32ce771911 Allow cors while in development 2023-11-22 12:37:18 -06:00
mikiher d944ecaa21 Merge branch 'caching' of https://github.com/mikiher/audiobookshelf into caching 2023-11-22 19:10:29 +02:00
mikiher 5aeb6ade72 Merge branch 'caching' of https://github.com/mikiher/audiobookshelf into caching 2023-11-22 19:00:11 +02:00
mikiher 107b4b83c1 Add cache middleware to most /libraries get requests 2023-11-22 18:40:42 +02:00
JBlond 0d61e29ecf de language translation follow up for 27497451d9 2023-11-21 20:30:48 +01:00
mikiher 781d4f570f Add test for parseNfoMetadata 2023-11-21 09:12:37 +02:00
mikiher a4d4f1bc2e Merge branch 'advplyr:master' into nfo-metadata 2023-11-21 09:09:12 +02:00
advplyr 048e27f03f Update:Openid auth endpoint sets the mobile flag on session to be used in the callback
Co-authored-by: Denis Arnst <git@sapd.eu>
2023-11-20 15:41:38 -06:00
Lars Kiesow 7b6aa3ba5a Allow enabling dev logs
This patch allows users to enable dev logs on production systems by
setting the `HIDE_DEV_LOGS` environment variable.

Before, you could only use this on a non-production environment. On
production, the logs would be disabled. This patch changes the behavior
and uses the `NODE_ENV` only as default. On production they are disabled
if `HIDE_DEV_LOGS` is undefined but can be enabled by setting
`HIDE_DEV_LOGS=0` on dev, they are enabled if undefined, but can be
disabled by setting `HIDE_DEV_LOGS=1`.
2023-11-19 21:00:54 +01:00
advplyr aa933df525 Update oidc redirect_uri to check x-forwarded-proto header for proxies 2023-11-19 14:00:39 -06:00
advplyr a0f137936d Merge pull request #2325 from lkiesow/milliseconds
Add milliseconds to logging
2023-11-19 13:41:10 -06:00
advplyr dcbfc963c1 Update protocol for redirect_uri in openid strategy to work for reverse proxies 2023-11-19 13:38:09 -06:00
Lars Kiesow 91fa78d740 Add milliseconds to logging
This patch adds milliseconds to the time string used for logging. This
helps when debugging some timing issues and should have no real negative
side effect.
2023-11-19 20:36:04 +01:00
advplyr 89eb857c14 Fix initialize openid auth strategy 2023-11-19 12:57:17 -06:00
advplyr e07d17c472 Merge pull request #1636 from lukeIam/auth_passportjs
Integrate passportjs for muti-strategy authentication and SSO
2023-11-19 11:46:52 -06:00
advplyr 4c2c320b9d Remove global CORS for api endpoints and setup temp CORS check for ebook endpoint 2023-11-19 11:32:48 -06:00
advplyr 56c574c928 Update package-lock 2023-11-19 08:29:58 -06:00
advplyr d2aea86957 Merge pull request #2300 from mikiher/bookfinder-testing-mocha
Bookfinder.js unit testing with mocha
2023-11-18 13:55:18 -06:00
advplyr 80e061115f Add remove semicolons to .vscode settings, update BookFinder.test formatting 2023-11-18 13:41:08 -06:00
mikiher 4299627f5f Add lru-cache dependency 2023-11-17 08:54:16 +02:00
mikiher 6a722102c5 Use ApiCacheManager & timing middleware 2023-11-17 08:49:40 +02:00
mikiher f22f3361d5 Add timing utils 2023-11-17 08:48:09 +02:00
mikiher 4dec8c265d Add ApiCacheManager 2023-11-17 08:47:40 +02:00
mikiher d990e5b909 Add NFO metadata source 2023-11-12 13:30:23 +00:00
advplyr fb48636510 Openid auth failures redirect to login page with error message.
Remove remaining google oauth server settings
2023-11-11 13:10:24 -06:00
advplyr 1ad6722e6d Remove google-oauth passport strategy 2023-11-11 11:29:59 -06:00
advplyr 557ef2ef79 Update /auth/openid endpoints for correct PKCE handling
- Provide error handling for /auth/openid
- Add session.mobile inside /auth/openid
- Proper PKCE handling for /auth/openid/callback
- redirect_uri handling for the token url in /auth/openid/callback

Co-authored-by: Denis Arnst <git@sapd.eu>
2023-11-11 10:52:05 -06:00
advplyr cff2caa07a Update:Rename podcast search page to add #2301 2023-11-10 16:32:14 -06:00
advplyr 237fe84c54 Add new API endpoint for updating auth-settings and update passport auth strategies 2023-11-10 16:11:51 -06:00
advplyr 078cb0855f Merge branch 'master' into auth_passportjs 2023-11-10 07:26:07 -06:00
mikiher ecba67da6d Add Istanbul coverage (nyc) 2023-11-10 10:02:02 +00:00
mikiher ea05e1f559 Remove test/ from .gitigore (now contains unit tests) 2023-11-10 09:58:30 +00:00
advplyr d3a55c8b1a Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-11-09 16:36:37 -06:00
advplyr d6b17678ec Update:Persist soft/hard delete checkbox option #1689 2023-11-09 16:36:28 -06:00
advplyr 33e287a543 Update:Persist show full path option for tables #2285 2023-11-09 16:26:49 -06:00
advplyr 08f045a02b Merge pull request #2299 from burghy86/patch-11
Update it.json
2023-11-09 16:15:16 -06:00
mikiher e8c14dbb58 Test BookFinder.js using mocha 2023-11-09 19:58:51 +00:00
burghy86 bf48eee705 Update it.json
arrange the additional lines.
how the hell did we get to over 700 lines in less than two months?
2023-11-09 15:46:25 +01:00
advplyr 8f4c75ff2b Update:Author card books translation string #2284 2023-11-08 16:28:05 -06:00
advplyr ee75d672e6 Matching user by openid sub, email or username based on server settings. Auto register user. Persist sub on User records 2023-11-08 16:14:57 -06:00
advplyr e140897313 Add match existing user by and auto register settings and UI 2023-11-08 14:45:29 -06:00
mikiher d1671f0ddc Cleanup commented out tests 2023-11-08 16:37:12 +00:00
mikiher 2730486ba5 Add tests for AuthorCandidates and search() in BookFinder 2023-11-08 16:24:08 +00:00
mikiher 49e4515785 Add stripRedudantSpaces 2023-11-08 16:21:20 +00:00
mikiher 819c524f51 Pass audnexus to AuthorCandidates constructor directly 2023-11-08 16:19:24 +00:00
advplyr 70c213ad22 Merge pull request #2291 from brianjaustin/fix/collection-duration
Hide collection duration if 0
2023-11-06 16:21:25 -06:00
advplyr aad6402fdb Update client/components/tables/collection/BookTableRow.vue 2023-11-06 16:18:35 -06:00
advplyr 5ce1cda2d0 Merge pull request #2283 from mikiher/watcher-single-file-update
Fix handling of single media file updates
2023-11-06 16:08:23 -06:00
mikiher ba60fc7581 Add tests for TitleCanidates 2023-11-06 05:33:06 +00:00
Brian Austin 0344e8cf1b Hide collection duration if 0 2023-11-05 19:13:26 -05:00
advplyr f840aa80f8 Add button to populate openid URLs using the issuer URL 2023-11-05 14:11:37 -06:00
advplyr c17540e191 Add app and serverVersion properties to response from /status 2023-11-05 13:06:26 -06:00
advplyr 309ef807ab Update /auth/openid endpoint to work with PKCE from mobile
Co-authored-by: Denis Arnst <git@sapd.eu>
2023-11-05 13:05:16 -06:00
advplyr 61e05e92a8 Add Swedish language option 2023-11-05 13:05:16 -06:00
Gustav Almstrom 1e5d6a5d52 Added swedish translation of strings 2023-11-05 13:05:15 -06:00
advplyr ff831678e8 Merge pull request #2288 from ScuttleSE/master
Added swedish translation of strings
2023-11-05 10:18:45 -06:00
advplyr 910be21e93 Add Swedish language option 2023-11-05 10:16:40 -06:00
mikiher 89055f8655 Remove unnecessary includesAuthorDiff from sorting 2023-11-05 16:14:26 +00:00
Gustav Almstrom b9ccc28baa Added swedish translation of strings 2023-11-05 16:51:45 +01:00
mikiher 5a3d450482 Refactor diff declarations in title candidate sorting 2023-11-05 15:13:42 +00:00
mikiher 047e7a72f2 Make position an internal property of titleCandidates 2023-11-05 14:56:20 +00:00
mikiher 3a9d09ea63 Add jest to dev dependencies 2023-11-05 14:33:56 +00:00
mikiher ee3d3808ef Refactor removing author from title candidate 2023-11-05 14:31:36 +00:00
mikiher 8f5a6b7c95 Move utility functions to module scope 2023-11-05 14:17:26 +00:00
advplyr 840811b464 Replace passport openidconnect plugin with openid-client, add JWKS and logout URL server settings, use email and email_verified instead of username 2023-11-04 15:36:43 -05:00
mikiher 567e1c46db Fix handling of single mefia file updates 2023-11-04 11:06:54 +00:00
advplyr cfe0c2a986 Merge branch 'master' into auth_passportjs 2023-11-03 08:29:05 -05:00
advplyr 68546acf2a Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-11-03 07:08:04 -05:00
advplyr 5220361151 Fix:Podcast episode cron not adding/removing library items correctly #2277 2023-11-03 07:07:58 -05:00
advplyr 076e01dbfe Merge pull request #2276 from Plazec/patch-1
Update cs.json
2023-11-02 14:19:45 -05:00
advplyr f15ed08b6a Merge branch 'master' into auth_passportjs 2023-11-02 13:55:16 -05:00
advplyr 828b96b2d9 Add server settings for changing openid button text and auto launching openid 2023-11-02 13:55:01 -05:00
Plazec 3100437651 Update cs.json
Corrected some translation errors and made the translation more consistent.
2023-11-02 19:44:32 +01:00
advplyr 20880a6bf6 Merge pull request #2274 from radekmuhlfeit2/patch-1
Create cs-CZ.json
2023-11-01 15:48:05 -05:00
advplyr 2eff69fe9f Add czech translation to dropdown 2023-11-01 15:42:54 -05:00
advplyr 5f035db0a9 Rename cs-CZ.json to cs.json 2023-11-01 15:29:58 -05:00
radekmuhlfeit2 e4a7e9d6b5 Create cs-CZ.json
Czech strings.
2023-11-01 20:21:45 +01:00
advplyr ab14b561f5 Merge master 2023-11-01 08:58:48 -05:00
advplyr 5ce4734a70 Merge pull request #2272 from clement-dufour/master
Add support for the old Apple Podcasts iOS app
2023-11-01 07:43:48 -05:00
clement.dufour 1ae2089253 Update:Add cover file extension in RSS feeds 2023-11-01 12:11:24 +01:00
clement.dufour 3c21e9d413 Update:Simpler content URL in RSS feeds 2023-11-01 12:10:44 +01:00
advplyr 9616d99640 Fix:Crash when matching with author names ending in ??? by escaping regex strings #2265 2023-10-30 16:35:41 -05:00
advplyr 2ef11e5ad0 Version bump v2.5.0 2023-10-29 12:58:00 -05:00
advplyr 27497451d9 Add:Ereader device setting to set users that have access #1982 2023-10-29 11:28:34 -05:00
advplyr 94fd3841aa Update:Notification widget shows green dot indicating unseen completed tasks 2023-10-29 09:20:50 -05:00
advplyr 225dcdeafd Fix:RSS feed parser for episode metadata tags that have attributes #1996 2023-10-28 16:11:15 -05:00
advplyr 2c9f2e0d68 Fix podcast episode rss feed search showing all episodes are downloaded 2023-10-28 15:54:19 -05:00
advplyr a9f74ace5a Merge pull request #2255 from MxMarx/added-search-epubs
Search epub text
2023-10-28 14:35:40 -05:00
advplyr 6dc5b58d8e Update TOC to not close when clicking on it 2023-10-28 14:32:11 -05:00
advplyr 88c794e710 Fix:Open RSS feed for series & collections respect prevent indexing option #2047 2023-10-28 13:45:06 -05:00
advplyr 61f2fb28e0 Add:Help icon buttons for libraries, rss feeds and users config pages, table add new buttons updated 2023-10-28 13:27:53 -05:00
advplyr 1df4dca4bb Merge pull request #2246 from MxMarx/expand-cover-images
show a modal with cover images when clicked
2023-10-27 16:55:53 -05:00
advplyr 6278bb8665 Move raw cover preview to a separate global component, fix item page cover overlay show on hover 2023-10-27 16:51:44 -05:00
MxMarx 4229cb7fb6 Added a method to unwrap the chapter list 2023-10-27 00:35:28 -07:00
MxMarx 5778200c8f Make epubs searchable 2023-10-27 00:14:46 -07:00
advplyr 5c1c511718 Merge pull request #2249 from mikiher/watcher-update-api
Add API to update a path on a watched library folder
2023-10-26 16:45:26 -05:00
advplyr f9c4dd2457 Update watcher function calls, add js docs 2023-10-26 16:41:54 -05:00
advplyr 3bccd52196 Merge branch 'master' into watcher-update-api 2023-10-26 16:33:48 -05:00
advplyr 0c23da7b02 Add missing translations 2023-10-26 16:31:47 -05:00
advplyr d577cae393 Merge pull request #2253 from MxMarx/add-epub-font-selector
Option to change the font family in epub viewer
2023-10-26 16:30:29 -05:00
MxMarx 24228b4424 Option to change the font family in epub viewer 2023-10-26 02:15:08 -07:00
advplyr 8dc4490169 Fix:Watcher waits for files to finish transferring before scanning #1362 #2248 2023-10-25 16:53:53 -05:00
advplyr ef1cdf6ad2 Fix:Only show authors with books for users #2250 2023-10-24 17:04:54 -05:00
mikiher e054b9a54c Add API to update a path on a watched library folder 2023-10-24 13:35:43 +00:00
MxMarx 32616aa441 show a modal with cover images when clicked 2023-10-23 20:37:51 -07:00
advplyr 0ee6336b02 Merge pull request #2245 from mikiher/watcher-fixes
Fix incorrect subpath checks in server/watcher.js
2023-10-23 17:28:44 -05:00
advplyr 9a477a9270 Add jsdocs 2023-10-23 17:28:59 -05:00
mikiher 976ae502bb Fix incorrect subpath checks 2023-10-23 21:48:34 +00:00
advplyr c4c12836a4 Fix:Version in bottom left of siderail overlapping buttons #2195 2023-10-22 17:04:45 -05:00
advplyr 5a70c0d7be Fix:Authors page books hide radio button on hover 2023-10-22 16:40:12 -05:00
advplyr 60a80a2996 Update:Remove support for metadata.abs, added script to create metadata.json files if they dont exist 2023-10-22 15:53:05 -05:00
advplyr ce88c6ccc3 Scanner metadata order of precedence description label, link to guide, add translations 2023-10-22 12:58:05 -05:00
advplyr b42edfe7a7 Book duration shown on match page compares minutes #1803 2023-10-22 07:10:52 -05:00
advplyr 0cbcfbd273 Merge pull request #2233 from Hallo951/master
Update de.json
2023-10-21 17:04:04 -05:00
Hallo951 8ecec93e67 Update de.json 2023-10-21 22:33:31 +02:00
advplyr 49403771c9 Update:Quick match all for library to use task instead of toast, remove scan socket events 2023-10-21 13:53:00 -05:00
advplyr 50215dab9a Hide library modal tools tab for new libraries 2023-10-21 13:00:41 -05:00
advplyr 58b9a42c84 Add:Scan button on libraries table 2023-10-21 12:56:35 -05:00
advplyr d7264f8c22 Update watcher scanner to show task notification 2023-10-21 12:25:45 -05:00
advplyr bef6549805 Update:Replace library scan toast with task manager #1279 2023-10-20 17:46:18 -05:00
advplyr 6f65350269 Update:JSDocs for task manager 2023-10-20 16:39:32 -05:00
advplyr 5644a40a03 Update:Add missing tranlations #2217 2023-10-20 16:08:57 -05:00
advplyr 920ddf43d7 Remove unused old model functions 2023-10-19 17:20:12 -05:00
advplyr 4a5f534a65 Update:Description width of item page to match width of tables 2023-10-19 16:30:33 -05:00
advplyr 24031f12db Merge pull request #2229 from JBlond/master
Translate new string for DE language.
2023-10-19 16:17:09 -05:00
JBlond 22361d785d Translate new string for DE language. 2023-10-19 15:22:00 +02:00
advplyr 8c5ce6149f Fix:Aspect ratio of authors image on authors landing page #2227 2023-10-18 17:10:53 -05:00
advplyr 516b0b4464 Fix:Book scanner set item as missing if no media files are found #2226 2023-10-18 17:02:15 -05:00
advplyr d22052c612 Update UI for library tools tab 2023-10-18 16:47:56 -05:00
advplyr b4ce5342c0 Add:Tools tab on library modal, api endpoint to remove all metadata files from library item folders 2023-10-17 17:46:43 -05:00
advplyr 0d5792405f Fix:Podcast episodes store RSS feed guid so they can be matched if the RSS feed changes the episode URL #2207 2023-10-16 17:47:44 -05:00
advplyr 48a590df4a Fix:Authors page description shows line breaks #2218 2023-10-16 17:08:50 -05:00
advplyr c264332994 Fix:Scanner detecting library item folder renames #1161 2023-10-15 12:55:22 -05:00
advplyr cdd740015c Add:Danish translations 2023-10-15 08:23:22 -05:00
advplyr 07ad81969c Update:Scanner recognizes asin in book folder names #1852 2023-10-14 15:04:16 -05:00
advplyr dcdd4bb20b Update:HLS router request validation, smooth out transcode reset logic 2023-10-14 12:50:48 -05:00
advplyr c98fac30b6 Update:Validate image URI content-type before writing image file 2023-10-14 10:52:56 -05:00
advplyr 1f8372f5e5 Merge pull request #2215 from springsunx/master
Update zh-cn.json
2023-10-14 09:37:49 -05:00
SunX 616ecf77b0 Update zh-cn.json
Update zh-cn.json
2023-10-14 20:30:27 +08:00
advplyr 656c81a1fa Update:Remove image path input from author modal, add API endpoints for uploading and removing author image 2023-10-13 17:37:37 -05:00
advplyr 290a377ef9 Update:Remove local cover path input & replace with url from web input, include SSRF request filter 2023-10-13 16:33:47 -05:00
advplyr 05731c9f72 Remove unused css parser lib 2023-10-13 14:10:54 -05:00
advplyr 3108bc5ccc Fix:Server crash when removing last item from a playlist #2211 2023-10-13 13:33:15 -05:00
advplyr e687a3403e Fix:Cleaning up orphan streams on server init #2209 2023-10-11 17:05:56 -05:00
advplyr 753ae3d7dc Fix:Server crash when downloading single file library items #2199 2023-10-10 17:51:52 -05:00
advplyr c9a2fdcb29 Library scanner saves last scan info including metadata precedence. Remove force re-scan 2023-10-09 17:48:21 -05:00
advplyr f84634e978 Fix OPF file scanner series sequence, book scanner check for mismatched audio file found lengths 2023-10-09 17:09:36 -05:00
advplyr 89821b91b0 Podcast scanner refactor/cleanup 2023-10-09 16:41:43 -05:00
advplyr 347b49f564 Update:Remove scanner settings, add library scanner settings tab, add order of precedence 2023-10-08 17:10:43 -05:00
advplyr 5ad9f507ba Merge pull request #2186 from mikiher/Fuzzy-Matching-Continued
Fuzzy matching continued
2023-10-08 10:39:11 -05:00
mikiher f8f555b4b6 Remove some unused code in AuthorCandidates.add 2023-10-07 21:30:37 +00:00
advplyr 786df450e5 Merge branch 'master' into Fuzzy-Matching-Continued 2023-10-07 11:52:04 -05:00
advplyr db9d5c9d43 Add:Support for pasting semicolon separated strings in multi select inputs #1198 2023-10-06 16:52:12 -05:00
advplyr b447cf5c1c Fix:Handle non-ascii characters in global search by not lowercasing in query #2187 2023-10-05 17:00:40 -05:00
mikiher f44b7ed1d0 [enhancement] If no valid authors, use clean author field 2023-10-05 18:41:18 +00:00
mikiher b0b7a0a618 [enhancement] Reduce spurious matches in validateAuthor 2023-10-05 18:27:52 +00:00
mikiher bf9f3895db [enhancement] Treat underscores as title part separators 2023-10-05 17:53:54 +00:00
mikiher f3555a12ce [enhancement] Handle initials in author normalization 2023-10-05 14:50:16 +00:00
mikiher b2acdadcea [enhancement] Added a couple title transformers 2023-10-05 14:29:40 +00:00
mikiher 9eff471afa [enhancement] AuthorCandidates, author validation 2023-10-05 12:05:30 +00:00
mikiher 8979586404 [enhancement] Improve candidate sorting 2023-10-05 10:28:55 +00:00
advplyr bfe514b7d4 Add:Email inputs for users 2023-10-04 17:05:12 -05:00
mikiher 752bfffb11 [enhamcement] Only add title candidate before and after all transforms 2023-10-04 14:53:12 +00:00
mikiher 10f5bc8cbe [cleanup] Make original title/author check with more readable 2023-10-04 05:26:16 +00:00
advplyr 565ff36d4e Merge pull request #2175 from MarshDeer/master
Completed Spanish translation and corrected typo in an English string
2023-10-03 17:18:07 -05:00
advplyr 401bd91204 Add:Show current book duration on match page as compared with book listed #1803 2023-10-03 17:16:49 -05:00
mikiher 5d7c197c89 [fix] Add back toLowerCase to cleanAuthor/Title (required by other uses) 2023-10-03 19:43:37 +00:00
MarshDeer 8e97be8ef4 Spanish translation completed 2023-10-02 19:42:42 -03:00
MarshDeer 733ad52684 Typo correction 2023-10-02 19:42:25 -03:00
advplyr 5ccf0df308 Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-10-02 17:09:19 -05:00
advplyr a3a8937ba3 Fix:Crash when searching for cover without an author #2174 2023-10-02 17:09:12 -05:00
advplyr 2662e8f715 Merge branch 'master' into auth_passportjs 2023-10-02 16:21:47 -05:00
advplyr 28b2005068 Merge pull request #2171 from Alistair1231/master
make force transcode apply to all "ffmpeg error 1"
2023-10-02 08:35:23 -05:00
advplyr 7c9631c1b0 Update server/objects/Stream.js 2023-10-02 08:34:56 -05:00
Alistair1231 4352989242 update comment to include second issue that is adressed by change 2023-10-02 09:30:57 +02:00
Alistair Bahr 73bb73a04a make force transcode apply to all "ffmpeg error 1" 2023-10-02 09:25:34 +02:00
advplyr 20a1d40d99 Fix:Set date properly on local playback sessions #2168 2023-10-01 12:44:52 -05:00
advplyr e10b178565 Fix:Crash on failed scanner find covers #2164 2023-10-01 09:03:01 -05:00
mikiher 46b0b3a6ef [cleanup] Refactor candidates logic to separate class 2023-10-01 08:42:47 +00:00
advplyr f2aed08d51 Version bump v2.4.4 2023-09-30 16:04:06 -05:00
advplyr c2c8cf919e Fix:Bad backup causing other backup files to not be displayed #1961 2023-09-30 16:01:10 -05:00
advplyr 9ebe23e91b Merge pull request #2162 from 92Kev/master
Update nl.json
2023-09-30 15:25:36 -05:00
advplyr 3d96749d38 Fix:Downloading podcasts with watcher causing duplicate episodes #2122 2023-09-30 15:12:37 -05:00
advplyr 1dc369180c Fix:Home page recent series shelf respect hide single book series library setting #2134 2023-09-30 14:32:40 -05:00
advplyr 8d3a326216 Fix:Newest episodes home page shelf #2119 2023-09-30 14:19:10 -05:00
mikiher 1d3ad38187 [cleanup] refactor OpenLib sort into getOpenLibResult 2023-09-30 18:08:03 +00:00
advplyr 1b22205f74 Update:Add libraryItems table index to improve performance #2073 2023-09-30 12:39:16 -05:00
92Kev 826fee4590 Update nl.json
Added Dutch translations where they were missing
2023-09-30 16:42:28 +02:00
advplyr f0929729a3 Fix:Adding new podcast with auto download episodes not setting the schedule #2160 2023-09-29 14:52:04 -05:00
advplyr 98ed2e01cc Fix:Scanner overwriting metadata when metadata file is not stored with items #2155 2023-09-28 17:23:52 -05:00
advplyr ed82a5aa19 Update:Library folder path editable in library edit modal until submit #2150 2023-09-27 17:50:32 -05:00
advplyr d7b2476473 Merge pull request #2146 from JBlond/master
Update German translation strings.
2023-09-26 17:18:18 -05:00
JBlond ee162f468a Adjust Message according to https://de.wikipedia.org/wiki/Durchkopplung#Fremdsprachliche_Begriffe
as suggested by https://github.com/vanto
2023-09-26 09:51:34 +02:00
advplyr 0d5a30b214 Update JWT auth extractors, add state in openid redirect, add back cors for api router 2023-09-25 17:05:58 -05:00
JBlond cb6678fa71 Update German translation strings. 2023-09-25 11:16:57 +02:00
advplyr 10011d3886 Add:Remove option for authors & show authors with 0 books on authors page #2124 2023-09-24 17:06:32 -05:00
advplyr 0367d9ec2a Fix:OPF files creating empty tags and genres #2142 2023-09-24 16:15:42 -05:00
advplyr 26f520ca4a Fix:Listening sessions page showing filtered user for open listening sessions #2136 2023-09-24 15:59:29 -05:00
advplyr e282142d3f Add authentication page in config, add /auth-settings GET endpoint, remove authOpenIDCallbackURL server setting 2023-09-24 15:36:35 -05:00
advplyr 7ba10db7d4 Update login button openid and google urls 2023-09-24 12:39:38 -05:00
advplyr f6de373388 Update /status endpoint to return available auth methods, fix socket auth, update openid to use username instead of email 2023-09-24 12:36:36 -05:00
advplyr 8683fc9fe4 Fix:Show series name when collapsing sub-series #2140 2023-09-23 14:38:30 -05:00
advplyr fd0920c808 Fix:Updating RSS feeds with new episodes #2139 2023-09-23 14:27:13 -05:00
advplyr 9922294507 Fix setting tokenSecret on init 2023-09-23 13:42:28 -05:00
advplyr f42ab45e1b Update passwordless root user check to user user.type instead of user.id 2023-09-23 13:30:28 -05:00
lukeIam 7a131880e5 show/hide of login buttons 2023-09-23 17:02:27 +01:00
advplyr a446fc0f20 Merge pull request #2138 from husjon/add-norwegian_translation
Added Norwegian translation
2023-09-23 09:37:55 -05:00
Jon Erling Hustadnes 202c26acf5 translation progress 2023-09-23 16:31:23 +02:00
Jon Erling Hustadnes f0b2acb4c7 added 'no' to languageCodeMap i18n.js 2023-09-23 16:29:54 +02:00
advplyr 102c90c4e8 Merge pull request #2133 from mfcar/mf/backup
Add more information to the backup page
2023-09-22 16:56:12 -05:00
advplyr 7c484d8e96 Remove commented out backup location 2023-09-22 16:53:59 -05:00
advplyr e9f0f7d1bc Add LabelBackupLocation translation strings 2023-09-22 16:51:35 -05:00
advplyr f37ab53eff Update get all backups api endpoint to return backupLocation, display location above backup settings 2023-09-22 16:49:01 -05:00
advplyr 97b0b98605 Merge pull request #2102 from selfhost-alt/sqlite-query-logging
Add ability to enable DEV logs of Sqlite queries
2023-09-22 16:17:32 -05:00
advplyr 1ab34fa77f Update server/Database.js 2023-09-22 16:14:12 -05:00
advplyr b64ecc7c6f Update server/Database.js 2023-09-22 16:14:00 -05:00
advplyr a11fc214e9 Merge pull request #2099 from mikiher/Fuzzy-Matching
Fuzzy Matching V1
2023-09-22 16:07:17 -05:00
advplyr 61c48602e8 Add jsdocs to BookFinder search functions 2023-09-22 16:03:41 -05:00
Jon Erling Hustadnes 452d59dcf6 copy of en-us.json to no.json 2023-09-22 12:31:38 +02:00
advplyr 5e976c08af Update cover API endpoint to only load necessary data from DB #2073 2023-09-21 16:57:48 -05:00
advplyr f1cce76e2c Merge pull request #2121 from Hallo951/master
Update de.json
2023-09-20 17:32:03 -05:00
advplyr 872fba1103 Merge pull request #2129 from mikiher/URI-encoding-2
Use encodeURIComponent for text inputs in Match.vue
2023-09-20 16:49:18 -05:00
mfcar 944f5950ca File missing 2023-09-20 22:36:30 +01:00
mfcar bfa87a2131 Add a way to see the backup location 2023-09-20 22:33:58 +01:00
lukeIam 0e75c80627 prepare show/hide of login buttons 2023-09-20 19:45:32 +01:00
lukeIam 2c25f64652 Add /auth_methods route 2023-09-20 19:16:08 +01:00
lukeIam 45cf00bd04 fix openid + jwt auth 2023-09-20 19:06:16 +01:00
lukeIam f6113e85c7 cookie lifetime 2023-09-20 18:48:57 +01:00
lukeIam 2c90bba774 small refactorings 2023-09-20 18:37:55 +01:00
lukeIam 51b0750a3f Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-09-20 17:34:29 +01:00
mikiher 6eab985b1e Use encodeURIComponent for text inputs 2023-09-20 11:25:21 +00:00
mikiher 81a9b8d158 Merge branch 'advplyr:master' into Fuzzy-Matching 2023-09-20 13:12:18 +03:00
mfcar 9519f6418d Now, whenever someone requests a backup file, it will automatically suggest a default file name for the downloaded file. 2023-09-19 22:37:57 +01:00
advplyr 9967a5dc66 Fix:Set ebookFormat on scans #2126 2023-09-19 15:42:38 -05:00
Hallo951 9382055bf2 Update de.json 2023-09-19 09:39:46 +02:00
advplyr 604f52762b Merge pull request #2120 from itzexor/x-accel-encode
[server] x-accel: encode all paths to URIs
2023-09-18 17:51:53 -05:00
advplyr ae88a4d20a Fix:Matching a library with no items not removing library scan #2118 2023-09-18 17:38:45 -05:00
advplyr b5a27226cc Fix:Misleading log on cover manager 2023-09-18 16:45:30 -05:00
advplyr 2c71324381 Fix:Book re-scan properly checking if existing coverPath exists #2110 2023-09-18 16:43:43 -05:00
James Ross 207ba7ec8e x-accel: encode all paths to URIs
updates util function  encodeUriPath to use node:url with a file:// path
prefix, and updates all instances x-accel redirection to use this helper
util instead of sending unencoded paths into the header.
2023-09-18 13:08:19 -07:00
advplyr e56b8edc0a Version bump 2.4.3 2023-09-17 16:13:19 -05:00
advplyr 8ab0a0a14d Update personalized shelves logs to dev logs 2023-09-17 16:09:21 -05:00
advplyr 4e01722ba6 Merge pull request #2103 from selfhost-alt/faster-scan-for-empty-series
Scan for empty book series more efficiently
2023-09-17 15:54:33 -05:00
advplyr 87eaacea22 Fix empty podcast and empty book queries when cleaning db on init 2023-09-17 15:53:25 -05:00
advplyr 3ad4f05449 Merge branch 'master' into faster-scan-for-empty-series 2023-09-17 15:47:06 -05:00
advplyr 817be40959 Merge pull request #2101 from selfhost-alt/fix-parse-full-name-typo
Fix typo in fixParsedNameCase
2023-09-17 15:43:25 -05:00
advplyr d18592eaeb Fix:Duplicate series and authors being added on matches and scans #2106 2023-09-17 15:29:39 -05:00
advplyr 0aae672e19 Fix:Scanner purge cover cache when extracting from audio file 2023-09-17 14:53:25 -05:00
lukeIam 0a6cd89090 Allow rest mode login (?isRest=true) 2023-09-17 18:42:42 +01:00
advplyr cfd9a01da7 Fix:Server crash when removing item from playlist #2115 2023-09-17 12:40:13 -05:00
lukeIam 942aa93f57 Fix: local login not possible 2023-09-16 19:45:04 +00:00
lukeIam 763c0f4a3d add missing await 2023-09-16 18:51:29 +00:00
lukeIam 7af3033f8d Fix: ci error - no token sercret 2023-09-16 18:42:48 +00:00
lukeIam 91d8451ab3 Remove log messages 2023-09-16 18:22:23 +00:00
lukeIam 6aaf3f0f02 Fix bug with undefined property 2023-09-16 18:22:11 +00:00
lukeIam 226a774ab9 Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-09-16 18:02:51 +00:00
Selfhost Alt 19cf3bfb9f Fix query to actually return empty series 2023-09-15 13:32:21 -07:00
mikiher 67bbe21513 Make quick-match more conservative 2023-09-15 09:24:19 +00:00
Selfhost Alt b668c6e37a Remove stray quote 2023-09-14 23:04:47 -07:00
Selfhost Alt 71762ef837 Newline before printing query 2023-09-14 23:01:40 -07:00
Selfhost Alt b1524d245e Add ability to enable DEV logs of Sqlite queries 2023-09-14 22:52:43 -07:00
Selfhost Alt 8b39b01269 Scan for empty book series more efficiently 2023-09-14 22:35:33 -07:00
Selfhost Alt f7849d2956 Fix typo in fixParsedNameCase 2023-09-14 22:12:22 -07:00
mikiher ac746f199b Fuzzy Matching V1 2023-09-14 21:32:20 +00:00
lukeIam af4c35069b Use a short-time cookie to remember where to callback to 2023-09-14 18:49:19 +01:00
advplyr fea28351f9 Version bump 2.4.2 2023-09-13 16:48:28 -05:00
advplyr bb124d3274 Merge pull request #2089 from Lionfox2/patch-2
Update de.json
2023-09-13 16:46:39 -05:00
advplyr 6cd1b82ada Merge pull request #2083 from Machou/patch-1
Update fr.json
2023-09-13 16:46:23 -05:00
advplyr c701617fbb Merge pull request #2079 from Nab0y/master
Update Russian localization
2023-09-13 16:46:02 -05:00
lukeIam 405c954b65 Updated + first rough implementation 2023-09-13 16:35:39 +00:00
Lionfox2 5d84c426fe Update de.json
The more suitable translation for "discover" is "Entdecken", same wording as in other media apps like Spotify
2023-09-12 23:30:58 +02:00
advplyr 083ba2fe19 Fix:Podcast download queue page available on refresh #2088 2023-09-12 15:35:14 -05:00
advplyr 1024bc5a75 Fix:Podcast library stat for total size #2072 2023-09-12 13:43:28 -05:00
advplyr 9553c19b33 Fix:Authors dropdown to use filter data instead of API endpoint #2077 2023-09-12 12:33:41 -05:00
Machou 2cbc9a07cb Update fr.json 2023-09-12 18:11:38 +02:00
advplyr ab97a9d613 Fix:Crash when updating book author or series that includes an apostrophe #2070 2023-09-12 10:41:39 -05:00
advplyr f1a7fd0d50 Fix:Podcast library include number of incomplete episodes in home page shelf api request #2081 2023-09-11 17:51:39 -05:00
Dmitry Naboychenko e9d7efbc5c Update russian localization 2023-09-11 21:35:36 +03:00
lukeIam f0f03efe17 Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-09-10 13:11:35 +00:00
advplyr 6e5d334874 Version bump 2.4.1 2023-09-09 15:47:17 -05:00
advplyr 6822628994 Fix:Missing narrators library filter 2023-09-09 15:46:33 -05:00
advplyr 98d9fd8c32 Fix:Get all items api endpoint support providing no limit #2067 2023-09-09 15:01:58 -05:00
advplyr e2cca60853 Fix:Crash on podcast library page sort by title #2069 2023-09-09 14:56:36 -05:00
advplyr e80b313a7b Fix:Server crash when quick match with find covers setting enabled #2068 2023-09-09 08:57:59 -05:00
advplyr b09b95ef24 Fix:Browse folders when adding new library folder crashing server #2065 2023-09-09 07:47:17 -05:00
advplyr aec45d04f7 Version bump 2.4.0 2023-09-08 17:26:21 -05:00
advplyr 87d037cb0a Fix clean database method and version bump 2.3.5 2023-09-08 17:20:39 -05:00
advplyr f6baf06164 Version bump 2.3.4 2023-09-08 16:20:03 -05:00
advplyr 7e75845851 Ignore podcast directory from watcher for additional 5s after downloading new episode 2023-09-08 15:12:39 -05:00
advplyr 2a11932822 Scanner ignore .part files #2063 2023-09-08 14:50:59 -05:00
advplyr 80fee92037 Update "disable watcher" server setting to display as "enable watcher" #2055 2023-09-08 14:28:21 -05:00
advplyr d0c02a801a Update open rss feed prevent indexing - dont include block tags when not preventing indexing 2023-09-08 14:03:12 -05:00
advplyr 9e13c64408 Handle sorting when collapsing by series and filtering by series on library page 2023-09-08 13:42:19 -05:00
advplyr 826963bf00 Add api route for changing sorting prefixes, update default sorting prefixes to include a 2023-09-08 12:32:30 -05:00
advplyr 39b6ede1e9 Add support for hide from continue listening 2023-09-08 11:20:22 -05:00
advplyr 066d853156 Add support for hide from continue listening on new home page shelves route 2023-09-07 17:49:35 -05:00
advplyr efae529fac Add cover finder to new book scanner 2023-09-06 17:48:50 -05:00
advplyr 934c0b9093 Fix watcher scanner detecting existing items 2023-09-06 15:43:59 -05:00
advplyr f02992dd4d Remove the setting of file permissions #2057 2023-09-06 07:12:11 -05:00
advplyr 10011bd6a3 Add startup function to remove invalid records from DB 2023-09-05 17:58:13 -05:00
advplyr a44ee913c4 Fix crash on get recent series home page shelf endpoint 2023-09-05 16:10:46 -05:00
advplyr adccccbd7a Remove index creation from migration file 2023-09-05 15:36:19 -05:00
advplyr 05b1b2be36 Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-09-05 15:07:49 -05:00
advplyr 7cc35a2cbe Remove indexes for columns that didnt exist in 2.3.3 2023-09-05 15:07:41 -05:00
advplyr 8d479b6e34 Merge pull request #2054 from JBlond/master
Follow-up update for German strings
2023-09-05 08:23:04 -05:00
JBlond 74d300f048 Follow up update for German string to 469167df66.
Plus addtional string translation
2023-09-05 11:36:41 +02:00
advplyr 1dd1fe8994 Update match all books to load items from DB, remove library items loading to memory on init 2023-09-04 16:33:55 -05:00
advplyr 03115e5e53 Replace old items filter/sort api endpoint with new, handle collapse sub-series 2023-09-04 15:26:07 -05:00
advplyr b1c07834be Remove force re-scan and old scanner logic 2023-09-04 13:59:37 -05:00
advplyr b9da3fa30e Add new podcast scanner and remove old scanner 2023-09-04 11:50:55 -05:00
advplyr 42ff3d8314 Add new library item scanner 2023-09-03 17:51:58 -05:00
advplyr e63aab95d8 Update new library scanner to handle metadata file changes 2023-09-03 15:14:58 -05:00
advplyr 9123dcb365 Remove series search api endpoint, update authors and series to load from db 2023-09-03 10:49:02 -05:00
advplyr 7567e91878 Update get library item api endpoint to remove unnecessary authors include query param 2023-09-03 10:04:14 -05:00
advplyr 1b1bdea3c8 Remove authors search api endpoint 2023-09-03 09:54:23 -05:00
advplyr 2df95c1712 Updates for new book scanner 2023-09-02 17:49:28 -05:00
advplyr 4ad1cd2968 Fix:Batch API endpoints crash on reset library filter data 2023-09-02 10:46:47 -05:00
advplyr 0ecfdab463 Update new library scanner for scanning in new books 2023-09-01 18:01:17 -05:00
advplyr 75276f5a44 Fix:Server crash when updating cover to a directory #2007 2023-08-30 18:05:52 -05:00
advplyr 4585d2816b Fix:Comic reader not detecting file sort order when number is more than 5-digit #2036 2023-08-29 15:47:34 -05:00
advplyr f8f94f2a6d Update new library scanner to check for cover images and ebooks 2023-08-28 17:50:21 -05:00
advplyr 2c8448d147 Updates to new library scanner and adding jsdoc types 2023-08-27 17:19:57 -05:00
advplyr ea1d051cfb Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-08-26 16:33:34 -05:00
advplyr a38e43213d Fix:Server crash when deleting library item #2031 2023-08-26 16:33:27 -05:00
advplyr 6cac8fcd6e Merge pull request #2030 from bluecmd/debian-tar-owner
Fix system file ownership for Debian package
2023-08-25 16:19:26 -05:00
Christian Svensson 8e65c78869 Fix system file ownership for Debian package
Extract ffmpeg and tone but ignore the ownership information from the tar archive. This will ensure that those files are owned by root, not the UIDs/GIDs the tar files happen to contain.
2023-08-25 18:14:17 +02:00
advplyr a3899b68e1 Merge branch 'master' of https://github.com/advplyr/audiobookshelf 2023-08-24 17:55:35 -05:00
advplyr 1187f91063 Update jsdoc defs for models 2023-08-24 17:55:29 -05:00
advplyr 7c288a5ff9 Merge pull request #2027 from realmain/docker-compose
Added podcasts volume to docker compose
2023-08-24 15:22:24 -05:00
advplyr e0dae44c7d Update:Show published year on library page when sorting books by published year #2017 2023-08-23 18:01:58 -05:00
realmain 754498958d Added podcasts volume 2023-08-23 15:55:07 -07:00
advplyr ec15978e26 Merge pull request #2026 from shawnphoffman/shawn/rss-feeds
Add config page for all RSS feeds
2023-08-22 16:42:31 -05:00
advplyr 469167df66 Update get all feeds route to be admin-only, map translation strings 2023-08-22 16:37:22 -05:00
advplyr e7c43a3f32 Merge pull request #2009 from JBlond/master
Update German strings
2023-08-22 16:08:47 -05:00
Shawn Hoffman 24989e73ae Merge branch 'master' into shawn/rss-feeds 2023-08-22 10:30:16 -07:00
Shawn Hoffman 13427b9f70 Add RSS feeds config page 2023-08-22 10:11:10 -07:00
Mario adafefecd4 Merge branch 'advplyr:master' into master 2023-08-22 11:39:13 +02:00
advplyr 6f96b069b5 Fix search query 2023-08-21 16:33:16 -05:00
advplyr 6c1b4e3a36 Update db model references 2023-08-20 13:34:03 -05:00
advplyr 21343ffbd1 Update numIssues on filter data, fix watcher scanning in new items 2023-08-20 13:16:53 -05:00
advplyr 4f94deefa0 Fix remove items with issues API route & remove old endpoints 2023-08-19 17:12:24 -05:00
advplyr 332078e6c1 Update library stats API route to load from db 2023-08-19 16:53:33 -05:00
advplyr ff0d6326d3 Update OPML api route to load podcasts from db 2023-08-19 15:19:27 -05:00
advplyr 8d451217a3 Update recent-episodes API route to load from db 2023-08-19 14:49:06 -05:00
advplyr f21d69339f Update search query to use user permissions 2023-08-19 14:11:34 -05:00
advplyr c77cead9ae Update search endpoints to search db directly 2023-08-19 13:59:22 -05:00
advplyr b334d40998 Update library routes to middlewareNew 2023-08-18 17:12:15 -05:00
advplyr 4e4a976050 Update get library series api endpoint to load from db 2023-08-18 17:08:34 -05:00
advplyr 9d7d4c6902 Update filterData for authors/series when added/removed 2023-08-18 14:40:36 -05:00
advplyr 7222171c5b Update checking empty series to load from Db 2023-08-17 17:58:57 -05:00
advplyr 361732a463 Update get User API endpoint to load media progress from db 2023-08-17 17:26:12 -05:00
advplyr 1ebe8a6f4c Update scanner to load library items from db 2023-08-16 18:08:00 -05:00
advplyr a98942a361 Add jsdoc types to remaining models 2023-08-16 16:38:48 -05:00
advplyr 0bc89cd40f Fix collapse series and sort by title without ignore prefix 2023-08-16 15:24:56 -05:00
advplyr 2ae86ab5bb Fix Library undefined sequelize 2023-08-16 14:49:06 -05:00
advplyr c707bcf0f6 Add jsdoc types for models 2023-08-15 18:03:43 -05:00
JBlond 10040ba9fa Update German strings as follow up of 09eefae808 2023-08-15 15:38:27 +02:00
advplyr 7afda1295b Update Author model to define types 2023-08-14 18:22:38 -05:00
advplyr 6d6e8613cf Update library API endpoints to load library items from db 2023-08-13 17:45:53 -05:00
advplyr 3651fffbee Update library filter data to load from db and cache, update rss feed routes to load library items from db 2023-08-13 15:10:26 -05:00
advplyr 8d03b23f46 Update MiscController api routes to load library items from db 2023-08-13 13:10:34 -05:00
advplyr fc44c801f2 Update playlist API endpoints to load library items from DB 2023-08-13 11:22:38 -05:00
advplyr 6056c14926 Update podcast controller to load library items from db 2023-08-12 17:29:08 -05:00
advplyr f465193b9c Update User.toJSONForPublic to remove mostRecent key and session key only includes the PlaybackSession 2023-08-12 16:11:58 -05:00
advplyr 09c9c28028 Remove test API endpoint for albums 2023-08-12 15:54:59 -05:00
advplyr f1130eb63a Update MeController api endpoints to load library items from DB 2023-08-12 15:52:09 -05:00
advplyr db80cec168 Update collection API routes to load libraryItems from DB 2023-08-12 15:01:27 -05:00
lukeIam dd9a3858d7 Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-08-12 16:44:44 +02:00
advplyr 38029d1202 Update library collections api endpoint to use libraryItems from db 2023-08-11 17:49:06 -05:00
advplyr aac2879652 Fix library query sort by title, add indexes for books and libraryItems 2023-08-10 17:46:27 -05:00
advplyr 8c9fc3ddb5 Fix discover home page shelf query, add indexes for libraryItems and mediaProgresses table 2023-08-09 17:48:31 -05:00
advplyr 33e04d0cbb Update home page queries merging listen/read shelves, limit recent shelves to 60 days out 2023-08-07 17:59:04 -05:00
advplyr fbb5fd41fb Merge pull request #1994 from NiclasHaderer/fix-backup-server-crash
Fix: server crash when uploading invalid backup file
2023-08-07 17:17:57 -05:00
advplyr 43a5296dd7 Update server/managers/BackupManager.js 2023-08-07 17:14:47 -05:00
advplyr 345ff1aa66 Update author API endpoints to load library items from DB 2023-08-06 15:06:45 -05:00
advplyr 56e3449db6 Remove media progress for podcast episodes when episode is removed 2023-08-06 14:18:51 -05:00
advplyr 1372c24535 Update queries to account for user permissions 2023-08-06 13:36:58 -05:00
Niclas Haderer 409c5f7b75 fix: the server does not crash any more when an invalid backup file is uploaded 2023-08-06 10:05:53 +02:00
advplyr 83d0db0607 Fix getting default library id for user 2023-08-05 16:37:26 -05:00
advplyr 91b6c4412d Add remaining personalized shelf queries for podcasts 2023-08-05 15:28:16 -05:00
advplyr 09eefae808 Add remaining personalized shelf queries, update book libraries home page to use new API endpoint 2023-08-05 14:01:16 -05:00
advplyr 80b3bfea51 Add recent series home page shelf query 2023-08-04 18:07:55 -05:00
advplyr 516298b5b2 Update continue series shelf to include rss feed 2023-08-04 17:26:43 -05:00
advplyr 8edab98163 Update continue series shelf queries 2023-08-04 17:24:06 -05:00
advplyr 58da095bcf Update query for continue series shelf 2023-08-03 18:14:25 -05:00
advplyr b9633691f4 Add new personalized home page shelves API endpoint 2023-08-02 18:29:28 -05:00
advplyr 7ec1d8ee5f Fix socket authority check for valid client 2023-08-01 16:34:01 -05:00
advplyr 83a1374e79 Merge pull request #1985 from tomazed/translation-fr
fr translation update
2023-08-01 16:23:28 -05:00
Tomazed 5ef00bac92 fr translation update 2023-08-01 11:51:15 +02:00
advplyr 95c4b3862b Include library item podcast queries 2023-07-31 17:59:51 -05:00
advplyr eeaf012cdc Update new library item API endpoint to handle collapse series 2023-07-30 17:51:44 -05:00
advplyr 11120a3765 Update version specific db migration check 2023-07-30 11:09:49 -05:00
advplyr 4d0acb30ba Update bookSeries & bookAuthors table to include createdAt timestamp 2023-07-29 17:25:11 -05:00
advplyr 4dbe8d29d9 Update db migration for duration, size, lastFirst, and ignore prefix columns 2023-07-28 18:03:31 -05:00
advplyr 0ca4ff4fca Update readme 2023-07-27 18:17:29 -05:00
advplyr 8be1651c6b Fix:Sync local media progress when library item not found #1971 2023-07-26 18:08:55 -05:00
advplyr af2db86d1a Merge pull request #1965 from petras-sukys/l10n/lt
Added Lithuanian translation
2023-07-25 15:03:07 -05:00
Petras Šukys 57c834f88d Added EOL at EOF 2023-07-25 22:20:13 +03:00
Petras Šukys 65fdebde20 Added language entry for Lithuanian (Lietuvių) 2023-07-25 22:16:13 +03:00
Petras Šukys b58e42ebf3 Lithuanian translation, part 5 2023-07-25 22:11:12 +03:00
Petras Šukys b2d45f598b Merge branch 'master' into l10n/lt 2023-07-25 08:03:19 +03:00
Petras Šukys 09c4e690c6 Lithuanian translation, part 4 2023-07-25 07:57:51 +03:00
Petras Šukys 67ba481dca Lithuanian translation, part 3 2023-07-24 22:49:44 +03:00
advplyr 710a62c2af Update:Load playlists only when needed & remove podcast episode from playlist when deleted 2023-07-23 09:42:57 -05:00
advplyr 5a9eed0a5a Update:Only load collections when needed 2023-07-22 16:18:55 -05:00
advplyr 354e16e462 Update:Only load Users when needed 2023-07-22 15:32:20 -05:00
advplyr 1d974375a0 Update:Only load libraries from db when needed 2023-07-22 14:25:20 -05:00
advplyr 1c40af3eef Update:Sequelize transactionType to IMMEDIATE to fix SQLITE_BUSY #1910 2023-07-22 11:30:29 -05:00
advplyr daa8c4cd67 Update:Remove sort index from podcast episodes 2023-07-22 09:24:46 -05:00
advplyr d5da4441cd Fix:Set podcast episode audio file index to 1 on scans 2023-07-22 09:05:43 -05:00
advplyr 80aea0c82d Fix:Save metadata files when updating library items #1952 2023-07-22 07:50:47 -05:00
Petras Šukys 14836eeb0d Lithuanian translation, part 2 2023-07-22 12:00:29 +03:00
Petras Šukys 85e9883d3e Lithuanian translation, part 1 2023-07-22 11:53:37 +03:00
Petras Šukys 80ca73e491 Copied en-us language file to lt 2023-07-22 10:52:06 +03:00
advplyr 22323f606d Fix:RSS feed covers #1948 2023-07-21 16:59:00 -05:00
advplyr 01b65eb678 Fix:Initialize Feed entityUpdatedAt to prevent updated RSS feed every request 2023-07-21 16:18:58 -05:00
advplyr d1d94c37a7 Update:Remove --max-old-space-size from Dockerfile 2023-07-20 17:00:08 -05:00
advplyr 838a24c8a5 Update:Remove healthcheck from Dockerfile 2023-07-20 16:59:46 -05:00
advplyr 3f380b0839 Fix:Parsing authors from meta tags removes duplicates #1932 2023-07-20 16:55:49 -05:00
advplyr 7fdf1a1d7f Merge pull request #1946 from rasmuslos/master
Fix byte conversion
2023-07-20 15:55:16 -05:00
Rasmus Krämer 38596d017f Fix byte conversion 2023-07-19 23:59:00 +02:00
lukeIam 95e6fef3d1 Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-05-27 10:56:05 +02:00
advplyr 4359ca28df Fix XAccel issue 2023-04-29 16:05:05 -05:00
advplyr 8b685436de Merge 2023-04-29 15:49:04 -05:00
advplyr 8d0064763c Merge branch 'master' into auth_passportjs 2023-04-16 10:08:17 -05:00
advplyr 7010a13648 Fixes for passport local and allow empty password 2023-04-16 10:08:13 -05:00
lukeIam 812395b21b Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-04-14 20:27:43 +02:00
lukeIam 62b0940766 Added passport-openidconnect implementation 2023-04-14 20:26:29 +02:00
lukeIam 08676a675a Fix: small problem with this context in Auth.js 2023-03-24 18:31:58 +01:00
lukeIam be53b31712 Merge remote-tracking branch 'origin/master' into auth_passportjs 2023-03-24 18:23:08 +01:00
lukeIam e1ddb95250 Inital passportjs integration 2023-03-24 18:21:25 +01:00
254 changed files with 28547 additions and 11013 deletions
+3 -1
View File
@@ -7,11 +7,13 @@
/podcasts/ /podcasts/
/media/ /media/
/metadata/ /metadata/
test/
/client/.nuxt/ /client/.nuxt/
/client/dist/ /client/dist/
/dist/ /dist/
/deploy/ /deploy/
/coverage/
/.nyc_output/
sw.* sw.*
.DS_STORE .DS_STORE
.idea/*
+2 -1
View File
@@ -16,5 +16,6 @@
}, },
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.detectIndentation": true, "editor.detectIndentation": true,
"editor.tabSize": 2 "editor.tabSize": 2,
"javascript.format.semicolons": "remove"
} }
+1 -7
View File
@@ -29,12 +29,6 @@ RUN npm ci --only=production
RUN apk del make python3 g++ RUN apk del make python3 g++
ENV NODE_OPTIONS=--max-old-space-size=4096
EXPOSE 80 EXPOSE 80
HEALTHCHECK \
--interval=30s \
--timeout=3s \
--start-period=10s \
CMD curl -f http://127.0.0.1/healthcheck || exit 1
CMD ["node", "index.js"] CMD ["node", "index.js"]
+2 -2
View File
@@ -60,13 +60,13 @@ install_ffmpeg() {
fi fi
$WGET $WGET
tar xvf ffmpeg-git-amd64-static.tar.xz --strip-components=1 tar xvf ffmpeg-git-amd64-static.tar.xz --strip-components=1 --no-same-owner
rm ffmpeg-git-amd64-static.tar.xz rm ffmpeg-git-amd64-static.tar.xz
# Temp downloading tone library to the ffmpeg dir # Temp downloading tone library to the ffmpeg dir
echo "Getting tone.." echo "Getting tone.."
$WGET_TONE $WGET_TONE
tar xvf tone-0.1.5-linux-x64.tar.gz --strip-components=1 tar xvf tone-0.1.5-linux-x64.tar.gz --strip-components=1 --no-same-owner
rm tone-0.1.5-linux-x64.tar.gz rm tone-0.1.5-linux-x64.tar.gz
echo "Good to go on Ffmpeg (& tone)... hopefully" echo "Good to go on Ffmpeg (& tone)... hopefully"
+20
View File
@@ -258,4 +258,24 @@ Bookshelf Label
.no-bars .Vue-Toastification__container.top-right { .no-bars .Vue-Toastification__container.top-right {
padding-top: 8px; padding-top: 8px;
}
.abs-btn::before {
content: '';
position: absolute;
border-radius: 6px;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0);
transition: all 0.1s ease-in-out;
}
.abs-btn:hover:not(:disabled)::before {
background-color: rgba(255, 255, 255, 0.1);
}
.abs-btn:disabled::before {
background-color: rgba(0, 0, 0, 0.2);
} }
+7 -5
View File
@@ -186,7 +186,7 @@ export default {
methods: { methods: {
requestBatchQuickEmbed() { requestBatchQuickEmbed() {
const payload = { const payload = {
message: 'Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?', message: this.$strings.MessageConfirmQuickEmbed,
callback: (confirmed) => { callback: (confirmed) => {
if (confirmed) { if (confirmed) {
this.$axios this.$axios
@@ -219,7 +219,7 @@ export default {
}, },
async batchRescan() { async batchRescan() {
const payload = { const payload = {
message: `Are you sure you want to re-scan ${this.selectedMediaItems.length} items?`, message: this.$getString('MessageConfirmReScanLibraryItems', [this.selectedMediaItems.length]),
callback: (confirmed) => { callback: (confirmed) => {
if (confirmed) { if (confirmed) {
this.$axios this.$axios
@@ -316,13 +316,15 @@ export default {
}, },
batchDeleteClick() { batchDeleteClick() {
const payload = { const payload = {
message: `This will delete ${this.numMediaItemsSelected} library items from the database and your file system. Are you sure?`, message: this.$getString('MessageConfirmDeleteLibraryItems', [this.numMediaItemsSelected]),
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.', checkboxLabel: this.$strings.LabelDeleteFromFileSystemCheckbox,
yesButtonText: this.$strings.ButtonDelete, yesButtonText: this.$strings.ButtonDelete,
yesButtonColor: 'error', yesButtonColor: 'error',
checkboxDefaultValue: true, checkboxDefaultValue: !Number(localStorage.getItem('softDeleteDefault') || 0),
callback: (confirmed, hardDelete) => { callback: (confirmed, hardDelete) => {
if (confirmed) { if (confirmed) {
localStorage.setItem('softDeleteDefault', hardDelete ? 0 : 1)
this.$store.commit('setProcessingBatch', true) this.$store.commit('setProcessingBatch', true)
this.$axios this.$axios
+12 -5
View File
@@ -68,6 +68,9 @@ export default {
currentLibraryId() { currentLibraryId() {
return this.$store.state.libraries.currentLibraryId return this.$store.state.libraries.currentLibraryId
}, },
currentLibraryMediaType() {
return this.$store.getters['libraries/getCurrentLibraryMediaType']
},
libraryName() { libraryName() {
return this.$store.getters['libraries/getCurrentLibraryName'] return this.$store.getters['libraries/getCurrentLibraryName']
}, },
@@ -335,9 +338,15 @@ export default {
libraryItemsAdded(libraryItems) { libraryItemsAdded(libraryItems) {
console.log('libraryItems added', libraryItems) console.log('libraryItems added', libraryItems)
const isThisLibrary = !libraryItems.some((li) => li.libraryId !== this.currentLibraryId) const recentlyAddedShelf = this.shelves.find((shelf) => shelf.id === 'recently-added')
if (!this.search && isThisLibrary) { if (!recentlyAddedShelf) return
this.fetchCategories()
// Add new library item to the recently added shelf
for (const libraryItem of libraryItems) {
if (libraryItem.libraryId === this.currentLibraryId && !recentlyAddedShelf.entities.some((ent) => ent.id === libraryItem.id)) {
// Add to front of array
recentlyAddedShelf.entities.unshift(libraryItem)
}
} }
}, },
libraryItemsUpdated(items) { libraryItemsUpdated(items) {
@@ -346,8 +355,6 @@ export default {
}) })
}, },
episodeAdded(episodeWithLibraryItem) { episodeAdded(episodeWithLibraryItem) {
console.log('Podcast episode added', episodeWithLibraryItem)
const isThisLibrary = episodeWithLibraryItem.libraryItem?.libraryId === this.currentLibraryId const isThisLibrary = episodeWithLibraryItem.libraryItem?.libraryId === this.currentLibraryId
if (!this.search && isThisLibrary) { if (!this.search && isThisLibrary) {
this.fetchCategories() this.fetchCategories()
+1 -1
View File
@@ -36,7 +36,7 @@
</svg> </svg>
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'"> <nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="flex-grow h-full flex justify-center items-center" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
<p class="text-sm">{{ $strings.ButtonSearch }}</p> <p class="text-sm">{{ $strings.ButtonAdd }}</p>
</nuxt-link> </nuxt-link>
</div> </div>
<div id="toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-40 flex items-center justify-end md:justify-start px-2 md:px-8"> <div id="toolbar" class="absolute top-10 md:top-0 left-0 w-full h-10 md:h-full z-40 flex items-center justify-end md:justify-start px-2 md:px-8">
+13 -3
View File
@@ -14,10 +14,10 @@
</div> </div>
<div class="w-44 h-12 px-4 border-t bg-bg border-black border-opacity-20 fixed left-0 flex flex-col justify-center" :class="wrapperClass" :style="{ bottom: streamLibraryItem ? '160px' : '0px' }"> <div class="w-44 h-12 px-4 border-t bg-bg border-black border-opacity-20 fixed left-0 flex flex-col justify-center" :class="wrapperClass" :style="{ bottom: streamLibraryItem ? '160px' : '0px' }">
<div class="flex justify-between"> <div class="flex items-center justify-between">
<p class="underline font-mono text-sm" @click="clickChangelog">v{{ $config.version }}</p> <button type="button" class="underline font-mono text-sm" @click="clickChangelog">v{{ $config.version }}</button>
<p class="font-mono text-xs text-gray-300 italic">{{ Source }}</p> <p class="text-xs text-gray-300 italic">{{ Source }}</p>
</div> </div>
<a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ latestVersion }}</a> <a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xs">Latest: {{ latestVersion }}</a>
</div> </div>
@@ -99,6 +99,16 @@ export default {
id: 'config-item-metadata-utils', id: 'config-item-metadata-utils',
title: this.$strings.HeaderItemMetadataUtils, title: this.$strings.HeaderItemMetadataUtils,
path: '/config/item-metadata-utils' path: '/config/item-metadata-utils'
},
{
id: 'config-rss-feeds',
title: this.$strings.HeaderRSSFeeds,
path: '/config/rss-feeds'
},
{
id: 'config-authentication',
title: this.$strings.HeaderAuthentication,
path: '/config/authentication'
} }
] ]
+6 -1
View File
@@ -313,7 +313,7 @@ export default {
this.currentSFQueryString = this.buildSearchParams() this.currentSFQueryString = this.buildSearchParams()
} }
const entityPath = this.entityName === 'series-books' ? 'items' : this.entityName let entityPath = this.entityName === 'series-books' ? 'items' : this.entityName
const sfQueryString = this.currentSFQueryString ? this.currentSFQueryString + '&' : '' const sfQueryString = this.currentSFQueryString ? this.currentSFQueryString + '&' : ''
const fullQueryString = `?${sfQueryString}limit=${this.booksPerFetch}&page=${page}&minified=1&include=rssfeed,numEpisodesIncomplete` const fullQueryString = `?${sfQueryString}limit=${this.booksPerFetch}&page=${page}&minified=1&include=rssfeed,numEpisodesIncomplete`
@@ -623,6 +623,11 @@ export default {
return entitiesPerShelfBefore < this.entitiesPerShelf // Books per shelf has changed return entitiesPerShelfBefore < this.entitiesPerShelf // Books per shelf has changed
}, },
async init(bookshelf) { async init(bookshelf) {
if (this.entityName === 'series') {
this.booksPerFetch = 50
} else {
this.booksPerFetch = 100
}
this.checkUpdateSearchParams() this.checkUpdateSearchParams()
this.initSizeData(bookshelf) this.initSizeData(bookshelf)
+3 -10
View File
@@ -3,9 +3,7 @@
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<h1 class="text-xl">{{ headerText }}</h1> <h1 class="text-xl">{{ headerText }}</h1>
<div v-if="showAddButton" class="mx-2 w-7 h-7 flex items-center justify-center rounded-full cursor-pointer hover:bg-white hover:bg-opacity-10 text-center" @click="clicked"> <slot name="header-items"></slot>
<button type="button" class="material-icons" :aria-label="$strings.ButtonAdd + ': ' + headerText" style="font-size: 1.4rem">add</button>
</div>
</div> </div>
<p v-if="description" id="settings-description" class="mb-6 text-gray-200" v-html="description" /> <p v-if="description" id="settings-description" class="mb-6 text-gray-200" v-html="description" />
@@ -19,14 +17,9 @@ export default {
props: { props: {
headerText: String, headerText: String,
description: String, description: String,
note: String, note: String
showAddButton: Boolean
}, },
methods: { methods: {}
clicked() {
this.$emit('clicked')
}
}
} }
</script> </script>
+86 -75
View File
@@ -3,117 +3,119 @@
<!-- ugly little workaround to cover up the shadow overlapping the bookshelf toolbar --> <!-- ugly little workaround to cover up the shadow overlapping the bookshelf toolbar -->
<div v-if="isShowingBookshelfToolbar" class="absolute top-0 -right-4 w-4 bg-bg h-10 pointer-events-none" /> <div v-if="isShowingBookshelfToolbar" class="absolute top-0 -right-4 w-4 bg-bg h-10 pointer-events-none" />
<nuxt-link :to="`/library/${currentLibraryId}`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="homePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <div id="siderail-buttons-container" :class="{ 'player-open': streamLibraryItem }" class="w-full overflow-y-auto overflow-x-hidden">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <nuxt-link :to="`/library/${currentLibraryId}`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="homePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" /> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
</svg> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonHome }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonHome }}</p>
<div v-show="homePage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="homePage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isPodcastLibrary" :to="`/library/${currentLibraryId}/podcast/latest`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastLatestPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isPodcastLibrary" :to="`/library/${currentLibraryId}/podcast/latest`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastLatestPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons text-2xl">format_list_bulleted</span> <span class="material-icons text-2xl">format_list_bulleted</span>
<p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLatest }}</p> <p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLatest }}</p>
<div v-show="isPodcastLatestPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isPodcastLatestPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link :to="`/library/${currentLibraryId}/bookshelf`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="showLibrary ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link :to="`/library/${currentLibraryId}/bookshelf`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="showLibrary ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg> </svg>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLibrary }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLibrary }}</p>
<div v-show="showLibrary" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="showLibrary" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/series`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isSeriesPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
</svg> </svg>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonSeries }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonSeries }}</p>
<div v-show="isSeriesPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isSeriesPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons-outlined text-2xl">collections_bookmark</span> <span class="material-icons-outlined text-2xl">collections_bookmark</span>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonCollections }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonCollections }}</p>
<div v-show="paramId === 'collections'" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="paramId === 'collections'" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="showPlaylists" :to="`/library/${currentLibraryId}/bookshelf/playlists`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPlaylistsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="showPlaylists" :to="`/library/${currentLibraryId}/bookshelf/playlists`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPlaylistsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons text-2.5xl">queue_music</span> <span class="material-icons text-2.5xl">queue_music</span>
<p class="pt-0.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonPlaylists }}</p> <p class="pt-0.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonPlaylists }}</p>
<div v-show="isPlaylistsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isPlaylistsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<svg class="w-6 h-6" viewBox="0 0 24 24"> <svg class="w-6 h-6" viewBox="0 0 24 24">
<path <path
fill="currentColor" fill="currentColor"
d="M12,5.5A3.5,3.5 0 0,1 15.5,9A3.5,3.5 0 0,1 12,12.5A3.5,3.5 0 0,1 8.5,9A3.5,3.5 0 0,1 12,5.5M5,8C5.56,8 6.08,8.15 6.53,8.42C6.38,9.85 6.8,11.27 7.66,12.38C7.16,13.34 6.16,14 5,14A3,3 0 0,1 2,11A3,3 0 0,1 5,8M19,8A3,3 0 0,1 22,11A3,3 0 0,1 19,14C17.84,14 16.84,13.34 16.34,12.38C17.2,11.27 17.62,9.85 17.47,8.42C17.92,8.15 18.44,8 19,8M5.5,18.25C5.5,16.18 8.41,14.5 12,14.5C15.59,14.5 18.5,16.18 18.5,18.25V20H5.5V18.25M0,20V18.5C0,17.11 1.89,15.94 4.45,15.6C3.86,16.28 3.5,17.22 3.5,18.25V20H0M24,20H20.5V18.25C20.5,17.22 20.14,16.28 19.55,15.6C22.11,15.94 24,17.11 24,18.5V20Z" d="M12,5.5A3.5,3.5 0 0,1 15.5,9A3.5,3.5 0 0,1 12,12.5A3.5,3.5 0 0,1 8.5,9A3.5,3.5 0 0,1 12,5.5M5,8C5.56,8 6.08,8.15 6.53,8.42C6.38,9.85 6.8,11.27 7.66,12.38C7.16,13.34 6.16,14 5,14A3,3 0 0,1 2,11A3,3 0 0,1 5,8M19,8A3,3 0 0,1 22,11A3,3 0 0,1 19,14C17.84,14 16.84,13.34 16.34,12.38C17.2,11.27 17.62,9.85 17.47,8.42C17.92,8.15 18.44,8 19,8M5.5,18.25C5.5,16.18 8.41,14.5 12,14.5C15.59,14.5 18.5,16.18 18.5,18.25V20H5.5V18.25M0,20V18.5C0,17.11 1.89,15.94 4.45,15.6C3.86,16.28 3.5,17.22 3.5,18.25V20H0M24,20H20.5V18.25C20.5,17.22 20.14,16.28 19.55,15.6C22.11,15.94 24,17.11 24,18.5V20Z"
/> />
</svg> </svg>
<p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonAuthors }}</p> <p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonAuthors }}</p>
<div v-show="isAuthorsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isAuthorsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/narrators`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isNarratorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/narrators`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isNarratorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons text-2xl">record_voice_over</span> <span class="material-icons text-2xl">record_voice_over</span>
<p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.LabelNarrators }}</p> <p class="pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.LabelNarrators }}</p>
<div v-show="isNarratorsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isNarratorsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="abs-icons icon-podcast text-xl"></span> <span class="abs-icons icon-podcast text-xl"></span>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonSearch }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonAdd }}</p>
<div v-show="isPodcastSearchPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isPodcastSearchPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isMusicLibrary" :to="`/library/${currentLibraryId}/bookshelf/albums`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isMusicAlbumsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isMusicLibrary" :to="`/library/${currentLibraryId}/bookshelf/albums`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isMusicAlbumsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons-outlined text-xl">album</span> <span class="material-icons-outlined text-xl">album</span>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">Albums</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">Albums</p>
<div v-show="isMusicAlbumsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isMusicAlbumsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/download-queue`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastDownloadQueuePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/download-queue`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastDownloadQueuePage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons text-2xl">file_download</span> <span class="material-icons text-2xl">file_download</span>
<p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonDownloadQueue }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonDownloadQueue }}</p>
<div v-show="isPodcastDownloadQueuePage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isPodcastDownloadQueuePage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="numIssues" :to="`/library/${currentLibraryId}/bookshelf?filter=issues`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-opacity-40 cursor-pointer relative" :class="showingIssues ? 'bg-error bg-opacity-40' : ' bg-error bg-opacity-20'"> <nuxt-link v-if="numIssues" :to="`/library/${currentLibraryId}/bookshelf?filter=issues`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-opacity-40 cursor-pointer relative" :class="showingIssues ? 'bg-error bg-opacity-40' : ' bg-error bg-opacity-20'">
<span class="material-icons text-2xl">warning</span> <span class="material-icons text-2xl">warning</span>
<p class="pt-1.5 text-center leading-4" style="font-size: 1rem">{{ $strings.ButtonIssues }}</p> <p class="pt-1.5 text-center leading-4" style="font-size: 1rem">{{ $strings.ButtonIssues }}</p>
<div v-show="showingIssues" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="showingIssues" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
<div class="absolute top-1 right-1 w-4 h-4 rounded-full bg-white bg-opacity-30 flex items-center justify-center"> <div class="absolute top-1 right-1 w-4 h-4 rounded-full bg-white bg-opacity-30 flex items-center justify-center">
<p class="text-xs font-mono pb-0.5">{{ numIssues }}</p> <p class="text-xs font-mono pb-0.5">{{ numIssues }}</p>
</div> </div>
</nuxt-link> </nuxt-link>
</div>
<div class="w-full h-12 px-1 py-2 border-t border-black border-opacity-20 absolute left-0" :style="{ bottom: streamLibraryItem ? '240px' : '65px' }"> <div class="w-full h-12 px-1 py-2 border-t border-black/20 bg-bg absolute left-0" :style="{ bottom: streamLibraryItem ? '224px' : '65px' }">
<p class="underline font-mono text-xs text-center text-gray-300 leading-3 mb-1" @click="clickChangelog">v{{ $config.version }}</p> <p class="underline font-mono text-xs text-center text-gray-300 leading-3 mb-1" @click="clickChangelog">v{{ $config.version }}</p>
<a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xxs text-center block leading-3">Update</a> <a v-if="hasUpdate" :href="githubTagUrl" target="_blank" class="text-warning text-xxs text-center block leading-3">Update</a>
<p v-else class="text-xxs text-gray-400 leading-3 text-center italic">{{ Source }}</p> <p v-else class="text-xxs text-gray-400 leading-3 text-center italic">{{ Source }}</p>
@@ -235,3 +237,12 @@ export default {
mounted() {} mounted() {}
} }
</script> </script>
<style>
#siderail-buttons-container {
max-height: calc(100vh - 64px - 48px);
}
#siderail-buttons-container.player-open {
max-height: calc(100vh - 64px - 48px - 160px);
}
</style>
+4 -4
View File
@@ -1,9 +1,9 @@
<template> <template>
<div v-if="streamLibraryItem" id="streamContainer" class="w-full fixed bottom-0 left-0 right-0 h-48 md:h-40 z-50 bg-primary px-2 md:px-4 pb-1 md:pb-4 pt-2"> <div v-if="streamLibraryItem" id="streamContainer" class="w-full fixed bottom-0 left-0 right-0 h-48 md:h-40 z-50 bg-primary px-2 md:px-4 pb-1 md:pb-4 pt-2">
<div id="videoDock" /> <div id="videoDock" />
<nuxt-link v-if="!playerHandler.isVideo" :to="`/item/${streamLibraryItem.id}`" class="absolute left-2 top-2 md:left-4 cursor-pointer"> <div class="absolute left-2 top-2 md:left-4 cursor-pointer">
<covers-book-cover :library-item="streamLibraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" /> <covers-book-cover expand-on-click :library-item="streamLibraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" />
</nuxt-link> </div>
<div class="flex items-start mb-6 md:mb-0" :class="playerHandler.isVideo ? 'ml-4 pl-96' : isSquareCover ? 'pl-18 sm:pl-24' : 'pl-12 sm:pl-16'"> <div class="flex items-start mb-6 md:mb-0" :class="playerHandler.isVideo ? 'ml-4 pl-96' : isSquareCover ? 'pl-18 sm:pl-24' : 'pl-12 sm:pl-16'">
<div class="min-w-0"> <div class="min-w-0">
<nuxt-link :to="`/item/${streamLibraryItem.id}`" class="hover:underline cursor-pointer text-sm sm:text-lg block truncate"> <nuxt-link :to="`/item/${streamLibraryItem.id}`" class="hover:underline cursor-pointer text-sm sm:text-lg block truncate">
@@ -15,7 +15,7 @@
<div v-if="podcastAuthor" class="pl-1 sm:pl-1.5 text-xs sm:text-base">{{ podcastAuthor }}</div> <div v-if="podcastAuthor" class="pl-1 sm:pl-1.5 text-xs sm:text-base">{{ podcastAuthor }}</div>
<div v-else-if="musicArtists" class="pl-1 sm:pl-1.5 text-xs sm:text-base">{{ musicArtists }}</div> <div v-else-if="musicArtists" class="pl-1 sm:pl-1.5 text-xs sm:text-base">{{ musicArtists }}</div>
<div v-else-if="authors.length" class="pl-1 sm:pl-1.5 text-xs sm:text-base"> <div v-else-if="authors.length" class="pl-1 sm:pl-1.5 text-xs sm:text-base">
<nuxt-link v-for="(author, index) in authors" :key="index" :to="`/author/${author.id}?library=${libraryId}`" class="hover:underline">{{ author.name }}<span v-if="index < authors.length - 1">,&nbsp;</span></nuxt-link> <nuxt-link v-for="(author, index) in authors" :key="index" :to="`/author/${author.id}`" class="hover:underline">{{ author.name }}<span v-if="index < authors.length - 1">,&nbsp;</span></nuxt-link>
</div> </div>
<div v-else class="text-xs sm:text-base cursor-pointer pl-1 sm:pl-1.5">{{ $strings.LabelUnknown }}</div> <div v-else class="text-xs sm:text-base cursor-pointer pl-1 sm:pl-1.5">{{ $strings.LabelUnknown }}</div>
<widgets-explicit-indicator :explicit="isExplicit"></widgets-explicit-indicator> <widgets-explicit-indicator :explicit="isExplicit"></widgets-explicit-indicator>
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<nuxt-link :to="`/author/${author.id}?library=${currentLibraryId}`"> <nuxt-link :to="`/author/${author.id}`">
<div @mouseover="mouseover" @mouseleave="mouseleave"> <div @mouseover="mouseover" @mouseleave="mouseleave">
<div :style="{ width: width + 'px', height: height + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden"> <div :style="{ width: width + 'px', height: height + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden">
<!-- Image or placeholder --> <!-- Image or placeholder -->
@@ -8,7 +8,7 @@
<!-- Author name & num books overlay --> <!-- Author name & num books overlay -->
<div v-show="!searching && !nameBelow" class="absolute bottom-0 left-0 w-full py-1 bg-black bg-opacity-60 px-2"> <div v-show="!searching && !nameBelow" class="absolute bottom-0 left-0 w-full py-1 bg-black bg-opacity-60 px-2">
<p class="text-center font-semibold truncate" :style="{ fontSize: sizeMultiplier * 0.75 + 'rem' }">{{ name }}</p> <p class="text-center font-semibold truncate" :style="{ fontSize: sizeMultiplier * 0.75 + 'rem' }">{{ name }}</p>
<p class="text-center text-gray-200" :style="{ fontSize: sizeMultiplier * 0.65 + 'rem' }">{{ numBooks }} Book{{ numBooks === 1 ? '' : 's' }}</p> <p class="text-center text-gray-200" :style="{ fontSize: sizeMultiplier * 0.65 + 'rem' }">{{ numBooks }} {{ $strings.LabelBooks }}</p>
</div> </div>
<!-- Search icon btn --> <!-- Search icon btn -->
+22 -8
View File
@@ -15,8 +15,8 @@
</div> </div>
<p v-if="book.author" class="text-gray-300 text-xs md:text-sm">by {{ book.author }}</p> <p v-if="book.author" class="text-gray-300 text-xs md:text-sm">by {{ book.author }}</p>
<p v-if="book.narrator" class="text-gray-400 text-xs">Narrated by {{ book.narrator }}</p> <p v-if="book.narrator" class="text-gray-400 text-xs">Narrated by {{ book.narrator }}</p>
<p v-if="book.duration" class="text-gray-400 text-xs">Runtime: {{ $elapsedPrettyExtended(book.duration * 60) }}</p> <p v-if="book.duration" class="text-gray-400 text-xs">Runtime: {{ $elapsedPrettyExtended(bookDuration, false) }} {{ bookDurationComparison }}</p>
<div v-if="book.series && book.series.length" class="flex py-1 -mx-1"> <div v-if="book.series?.length" class="flex py-1 -mx-1">
<div v-for="(series, index) in book.series" :key="index" class="bg-white bg-opacity-10 rounded-full px-1 py-0.5 mx-1"> <div v-for="(series, index) in book.series" :key="index" class="bg-white bg-opacity-10 rounded-full px-1 py-0.5 mx-1">
<p class="leading-3 text-xs text-gray-400"> <p class="leading-3 text-xs text-gray-400">
{{ series.series }}<span v-if="series.sequence">&nbsp;#{{ series.sequence }}</span> {{ series.series }}<span v-if="series.sequence">&nbsp;#{{ series.sequence }}</span>
@@ -29,9 +29,7 @@
</div> </div>
<div v-else class="px-4 flex-grow"> <div v-else class="px-4 flex-grow">
<h1> <h1>
<div class="flex items-center"> <div class="flex items-center">{{ book.title }}<widgets-explicit-indicator :explicit="book.explicit" /></div>
{{ book.title }}<widgets-explicit-indicator :explicit="book.explicit" />
</div>
</h1> </h1>
<p class="text-base text-gray-300 whitespace-nowrap truncate">by {{ book.author }}</p> <p class="text-base text-gray-300 whitespace-nowrap truncate">by {{ book.author }}</p>
<p v-if="book.genres" class="text-xs text-gray-400 leading-5">{{ book.genres.join(', ') }}</p> <p v-if="book.genres" class="text-xs text-gray-400 leading-5">{{ book.genres.join(', ') }}</p>
@@ -56,7 +54,8 @@ export default {
default: () => {} default: () => {}
}, },
isPodcast: Boolean, isPodcast: Boolean,
bookCoverAspectRatio: Number bookCoverAspectRatio: Number,
currentBookDuration: Number
}, },
data() { data() {
return { return {
@@ -65,12 +64,27 @@ export default {
}, },
computed: { computed: {
bookCovers() { bookCovers() {
return this.book.covers ? this.book.covers || [] : [] return this.book.covers || []
},
bookDuration() {
return (this.book.duration || 0) * 60
},
bookDurationComparison() {
if (!this.book.duration || !this.currentBookDuration) return ''
const currentBookDurationMinutes = Math.floor(this.currentBookDuration / 60)
let differenceInMinutes = currentBookDurationMinutes - this.book.duration
if (differenceInMinutes < 0) {
differenceInMinutes = Math.abs(differenceInMinutes)
return `(${this.$elapsedPrettyExtended(differenceInMinutes * 60, false, false)} shorter)`
} else if (differenceInMinutes > 0) {
return `(${this.$elapsedPrettyExtended(differenceInMinutes * 60, false, false)} longer)`
}
return '(exact match)'
} }
}, },
methods: { methods: {
selectMatch() { selectMatch() {
var book = { ...this.book } const book = { ...this.book }
book.cover = this.selectedCover book.cover = this.selectedCover
this.$emit('select', book) this.$emit('select', book)
}, },
@@ -1,10 +1,8 @@
<template> <template>
<div class="flex items-center px-1 overflow-hidden"> <div class="flex items-center px-1 overflow-hidden">
<div class="w-8 flex items-center justify-center"> <div class="w-8 flex items-center justify-center">
<!-- <div class="text-lg"> -->
<span v-if="isFinished" :class="taskIconStatus" class="material-icons text-base">{{ actionIcon }}</span> <span v-if="isFinished" :class="taskIconStatus" class="material-icons text-base">{{ actionIcon }}</span>
<widgets-loading-spinner v-else /> <widgets-loading-spinner v-else />
<!-- </div> -->
</div> </div>
<div class="flex-grow px-2 taskRunningCardContent"> <div class="flex-grow px-2 taskRunningCardContent">
<p class="truncate text-sm">{{ title }}</p> <p class="truncate text-sm">{{ title }}</p>
@@ -12,7 +10,9 @@
<p class="truncate text-xs text-gray-300">{{ description }}</p> <p class="truncate text-xs text-gray-300">{{ description }}</p>
<p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p> <p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p>
<p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p>
</div> </div>
<ui-btn v-if="userIsAdminOrUp && !isFinished && isLibraryScan && !cancelingScan" color="primary" :padding-y="1" :padding-x="1" class="text-xs w-16 max-w-16 truncate mr-1" @click.stop="cancelScan">{{ this.$strings.ButtonCancel }}</ui-btn>
</div> </div>
</template> </template>
@@ -25,9 +25,14 @@ export default {
} }
}, },
data() { data() {
return {} return {
cancelingScan: false
}
}, },
computed: { computed: {
userIsAdminOrUp() {
return this.$store.getters['user/getIsAdminOrUp']
},
title() { title() {
return this.task.title || 'No Title' return this.task.title || 'No Title'
}, },
@@ -76,9 +81,22 @@ export default {
} }
return '' return ''
},
isLibraryScan() {
return this.action === 'library-scan' || this.action === 'library-match-all'
}
},
methods: {
cancelScan() {
const libraryId = this.task?.data?.libraryId
if (!libraryId) {
console.error('No library id in library-scan task', this.task)
return
}
this.cancelingScan = true
this.$root.socket.emit('cancel_scan', libraryId)
} }
}, },
methods: {},
mounted() {} mounted() {}
} }
</script> </script>
+13 -6
View File
@@ -68,7 +68,8 @@
<span class="material-icons" :style="{ fontSize: sizeMultiplier + 'rem' }">edit</span> <span class="material-icons" :style="{ fontSize: sizeMultiplier + 'rem' }">edit</span>
</div> </div>
<div class="absolute cursor-pointer hover:text-yellow-300 hover:scale-125 transform duration-100" :style="{ top: 0.375 * sizeMultiplier + 'rem', left: 0.375 * sizeMultiplier + 'rem' }" @click.stop.prevent="selectBtnClick"> <!-- Radio button -->
<div v-if="!isAuthorBookshelfView" class="absolute cursor-pointer hover:text-yellow-300 hover:scale-125 transform duration-100" :style="{ top: 0.375 * sizeMultiplier + 'rem', left: 0.375 * sizeMultiplier + 'rem' }" @click.stop.prevent="selectBtnClick">
<span class="material-icons" :class="selected ? 'text-yellow-400' : ''" :style="{ fontSize: 1.25 * sizeMultiplier + 'rem' }">{{ selected ? 'radio_button_checked' : 'radio_button_unchecked' }}</span> <span class="material-icons" :class="selected ? 'text-yellow-400' : ''" :style="{ fontSize: 1.25 * sizeMultiplier + 'rem' }">{{ selected ? 'radio_button_checked' : 'radio_button_unchecked' }}</span>
</div> </div>
@@ -89,7 +90,7 @@
<!-- Series name overlay --> <!-- Series name overlay -->
<div v-if="booksInSeries && libraryItem && isHovering" class="w-full h-full absolute top-0 left-0 z-10 bg-black bg-opacity-60 rounded flex items-center justify-center" :style="{ padding: sizeMultiplier + 'rem' }"> <div v-if="booksInSeries && libraryItem && isHovering" class="w-full h-full absolute top-0 left-0 z-10 bg-black bg-opacity-60 rounded flex items-center justify-center" :style="{ padding: sizeMultiplier + 'rem' }">
<p class="text-gray-200 text-center" :style="{ fontSize: 1.1 * sizeMultiplier + 'rem' }">{{ series }}</p> <p v-if="seriesName" class="text-gray-200 text-center" :style="{ fontSize: 1.1 * sizeMultiplier + 'rem' }">{{ seriesName }}</p>
</div> </div>
<!-- Error widget --> <!-- Error widget -->
@@ -218,8 +219,11 @@ export default {
// Only included when filtering by series or collapse series or Continue Series shelf on home page // Only included when filtering by series or collapse series or Continue Series shelf on home page
return this.mediaMetadata.series return this.mediaMetadata.series
}, },
seriesName() {
return this.series?.name || null
},
seriesSequence() { seriesSequence() {
return this.series ? this.series.sequence : null return this.series?.sequence || null
}, },
libraryId() { libraryId() {
return this._libraryItem.libraryId return this._libraryItem.libraryId
@@ -318,6 +322,7 @@ export default {
if (this.orderBy === 'media.duration') return 'Duration: ' + this.$elapsedPrettyExtended(this.media.duration, false) if (this.orderBy === 'media.duration') return 'Duration: ' + this.$elapsedPrettyExtended(this.media.duration, false)
if (this.orderBy === 'size') return 'Size: ' + this.$bytesPretty(this._libraryItem.size) if (this.orderBy === 'size') return 'Size: ' + this.$bytesPretty(this._libraryItem.size)
if (this.orderBy === 'media.numTracks') return `${this.numEpisodes} Episodes` if (this.orderBy === 'media.numTracks') return `${this.numEpisodes} Episodes`
if (this.orderBy === 'media.metadata.publishedYear' && this.mediaMetadata.publishedYear) return 'Published ' + this.mediaMetadata.publishedYear
return null return null
}, },
episodeProgress() { episodeProgress() {
@@ -839,13 +844,15 @@ export default {
}, },
deleteLibraryItem() { deleteLibraryItem() {
const payload = { const payload = {
message: 'This will delete the library item from the database and your file system. Are you sure?', message: this.$strings.MessageConfirmDeleteLibraryItem,
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.', checkboxLabel: this.$strings.LabelDeleteFromFileSystemCheckbox,
yesButtonText: this.$strings.ButtonDelete, yesButtonText: this.$strings.ButtonDelete,
yesButtonColor: 'error', yesButtonColor: 'error',
checkboxDefaultValue: true, checkboxDefaultValue: !Number(localStorage.getItem('softDeleteDefault') || 0),
callback: (confirmed, hardDelete) => { callback: (confirmed, hardDelete) => {
if (confirmed) { if (confirmed) {
localStorage.setItem('softDeleteDefault', hardDelete ? 0 : 1)
this.processing = true this.processing = true
const axios = this.$axios || this.$nuxt.$axios const axios = this.$axios || this.$nuxt.$axios
axios axios
+1 -1
View File
@@ -36,7 +36,7 @@ export default {
return this.narrator?.name || '' return this.narrator?.name || ''
}, },
numBooks() { numBooks() {
return this.narrator?.books?.length || 0 return this.narrator?.numBooks || this.narrator?.books?.length || 0
}, },
userCanUpdate() { userCanUpdate() {
return this.$store.getters['user/getUserCanUpdate'] return this.$store.getters['user/getUserCanUpdate']
+1 -1
View File
@@ -103,7 +103,7 @@ export default {
return this.$store.state.libraries.currentLibraryId return this.$store.state.libraries.currentLibraryId
}, },
totalResults() { totalResults() {
return this.bookResults.length + this.seriesResults.length + this.authorResults.length + this.tagResults.length + this.podcastResults.length return this.bookResults.length + this.seriesResults.length + this.authorResults.length + this.tagResults.length + this.podcastResults.length + this.narratorResults.length
} }
}, },
methods: { methods: {
@@ -348,6 +348,10 @@ export default {
}, },
tracks() { tracks() {
return [ return [
{
id: 'none',
name: this.$strings.LabelTracksNone
},
{ {
id: 'single', id: 'single',
name: this.$strings.LabelTracksSingleTrack name: this.$strings.LabelTracksSingleTrack
+8 -1
View File
@@ -5,7 +5,8 @@
<div class="absolute cover-bg" ref="coverBg" /> <div class="absolute cover-bg" ref="coverBg" />
</div> </div>
<img v-if="libraryItem" ref="cover" :src="fullCoverUrl" loading="lazy" @error="imageError" @load="imageLoaded" class="w-full h-full absolute top-0 left-0 z-10 duration-300 transition-opacity" :style="{ opacity: imageReady ? '1' : '0' }" :class="showCoverBg ? 'object-contain' : 'object-fill'" /> <img v-if="libraryItem" ref="cover" :src="fullCoverUrl" loading="lazy" draggable="false" @error="imageError" @load="imageLoaded" class="w-full h-full absolute top-0 left-0 z-10 duration-300 transition-opacity" :style="{ opacity: imageReady ? '1' : '0' }" :class="showCoverBg ? 'object-contain' : 'object-fill'" @click="clickCover" />
<div v-show="loading && libraryItem" class="absolute top-0 left-0 h-full w-full flex items-center justify-center"> <div v-show="loading && libraryItem" class="absolute top-0 left-0 h-full w-full flex items-center justify-center">
<p class="text-center" :style="{ fontSize: 0.75 * sizeMultiplier + 'rem' }">{{ title }}</p> <p class="text-center" :style="{ fontSize: 0.75 * sizeMultiplier + 'rem' }">{{ title }}</p>
<div class="absolute top-2 right-2"> <div class="absolute top-2 right-2">
@@ -43,6 +44,7 @@ export default {
type: Number, type: Number,
default: 120 default: 120
}, },
expandOnClick: Boolean,
bookCoverAspectRatio: Number bookCoverAspectRatio: Number
}, },
data() { data() {
@@ -132,6 +134,11 @@ export default {
} }
}, },
methods: { methods: {
clickCover() {
if (this.expandOnClick && this.libraryItem) {
this.$store.commit('globals/setRawCoverPreviewModal', this.libraryItem.id)
}
},
setCoverBg() { setCoverBg() {
if (this.$refs.coverBg) { if (this.$refs.coverBg) {
this.$refs.coverBg.style.backgroundImage = `url("${this.fullCoverUrl}")` this.$refs.coverBg.style.backgroundImage = `url("${this.fullCoverUrl}")`
+5 -2
View File
@@ -13,8 +13,8 @@
<div v-if="imageFailed" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-red-100" :style="{ padding: placeholderCoverPadding + 'rem' }"> <div v-if="imageFailed" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full bg-red-100" :style="{ padding: placeholderCoverPadding + 'rem' }">
<div class="w-full h-full border-2 border-error flex flex-col items-center justify-center"> <div class="w-full h-full border-2 border-error flex flex-col items-center justify-center">
<img src="/Logo.png" class="mb-2" :style="{ height: 64 * sizeMultiplier + 'px' }" /> <img v-if="width > 100" src="/Logo.png" class="mb-2" :style="{ height: 40 * sizeMultiplier + 'px' }" />
<p class="text-center text-error" :style="{ fontSize: sizeMultiplier + 'rem' }">Invalid Cover</p> <p class="text-center text-error" :style="{ fontSize: invalidCoverFontSize + 'rem' }">Invalid Cover</p>
</div> </div>
</div> </div>
@@ -58,6 +58,9 @@ export default {
sizeMultiplier() { sizeMultiplier() {
return this.width / 120 return this.width / 120
}, },
invalidCoverFontSize() {
return Math.max(this.sizeMultiplier * 0.8, 0.5)
},
placeholderCoverPadding() { placeholderCoverPadding() {
return 0.8 * this.sizeMultiplier return 0.8 * this.sizeMultiplier
}, },
+10 -5
View File
@@ -14,13 +14,17 @@
</div> </div>
<div class="w-1/2 px-2"> <div class="w-1/2 px-2">
<ui-text-input-with-label v-if="!isEditingRoot" v-model="newUser.password" :label="isNew ? $strings.LabelPassword : $strings.LabelChangePassword" type="password" /> <ui-text-input-with-label v-if="!isEditingRoot" v-model="newUser.password" :label="isNew ? $strings.LabelPassword : $strings.LabelChangePassword" type="password" />
<ui-text-input-with-label v-else v-model="newUser.email" :label="$strings.LabelEmail" />
</div> </div>
</div> </div>
<div v-show="!isEditingRoot" class="flex py-2"> <div v-show="!isEditingRoot" class="flex py-2">
<div class="px-2 w-52"> <div class="w-1/2 px-2">
<ui-dropdown v-model="newUser.type" :label="$strings.LabelAccountType" :disabled="isEditingRoot" :items="accountTypes" @input="userTypeUpdated" /> <ui-text-input-with-label v-model="newUser.email" :label="$strings.LabelEmail" />
</div> </div>
<div class="flex-grow" /> <div class="px-2 w-52">
<ui-dropdown v-model="newUser.type" :label="$strings.LabelAccountType" :disabled="isEditingRoot" :items="accountTypes" small @input="userTypeUpdated" />
</div>
<!-- <div class="flex-grow" /> -->
<div class="flex items-center pt-4 px-2"> <div class="flex items-center pt-4 px-2">
<p class="px-3 font-semibold" id="user-enabled-toggle" :class="isEditingRoot ? 'text-gray-300' : ''">{{ $strings.LabelEnable }}</p> <p class="px-3 font-semibold" id="user-enabled-toggle" :class="isEditingRoot ? 'text-gray-300' : ''">{{ $strings.LabelEnable }}</p>
<ui-toggle-switch labeledBy="user-enabled-toggle" v-model="newUser.isActive" :disabled="isEditingRoot" /> <ui-toggle-switch labeledBy="user-enabled-toggle" v-model="newUser.isActive" :disabled="isEditingRoot" />
@@ -257,7 +261,6 @@ export default {
if (account.type === 'root' && !account.isActive) return if (account.type === 'root' && !account.isActive) return
this.processing = true this.processing = true
console.log('Calling update', account)
this.$axios this.$axios
.$patch(`/api/users/${this.account.id}`, account) .$patch(`/api/users/${this.account.id}`, account)
.then((data) => { .then((data) => {
@@ -326,9 +329,11 @@ export default {
init() { init() {
this.fetchAllTags() this.fetchAllTags()
this.isNew = !this.account this.isNew = !this.account
if (this.account) { if (this.account) {
this.newUser = { this.newUser = {
username: this.account.username, username: this.account.username,
email: this.account.email,
password: this.account.password, password: this.account.password,
type: this.account.type, type: this.account.type,
isActive: this.account.isActive, isActive: this.account.isActive,
@@ -337,9 +342,9 @@ export default {
itemTagsSelected: [...(this.account.itemTagsSelected || [])] itemTagsSelected: [...(this.account.itemTagsSelected || [])]
} }
} else { } else {
this.fetchAllTags()
this.newUser = { this.newUser = {
username: null, username: null,
email: null,
password: null, password: null,
type: 'user', type: 'user',
isActive: true, isActive: true,
@@ -0,0 +1,33 @@
<template>
<modals-modal v-model="show" name="cover" :width="'90%'" :height="'90%'" :contentMarginTop="0">
<div class="w-full h-full" @click="show = false">
<img loading="lazy" :src="rawCoverUrl" class="w-full h-full z-10 object-scale-down" />
</div>
</modals-modal>
</template>
<script>
export default {
data() {
return {}
},
computed: {
show: {
get() {
return this.$store.state.globals.showRawCoverPreviewModal
},
set(val) {
this.$store.commit('globals/setShowRawCoverPreviewModal', val)
}
},
selectedLibraryItemId() {
return this.$store.state.globals.selectedLibraryItemId
},
rawCoverUrl() {
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.selectedLibraryItemId, null, true)
}
},
methods: {},
mounted() {}
}
</script>
+92 -32
View File
@@ -5,18 +5,23 @@
<p class="text-3xl text-white truncate">{{ title }}</p> <p class="text-3xl text-white truncate">{{ title }}</p>
</div> </div>
</template> </template>
<div class="p-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh"> <div v-if="author" class="p-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh">
<form v-if="author" @submit.prevent="submitForm"> <div class="flex">
<div class="flex"> <div class="w-40 p-2">
<div class="w-40 p-2"> <div class="w-full h-45 relative">
<div class="w-full h-45 relative"> <covers-author-image :author="author" />
<covers-author-image :author="author" /> <div v-if="userCanDelete && !processing && author.imagePath" class="absolute top-0 left-0 w-full h-full opacity-0 hover:opacity-100">
<div v-show="!processing && author.imagePath" class="absolute top-0 left-0 w-full h-full opacity-0 hover:opacity-100"> <span class="absolute top-2 right-2 material-icons text-error transform hover:scale-125 transition-transform cursor-pointer text-lg" @click="removeCover">delete</span>
<span class="absolute top-2 right-2 material-icons text-error transform hover:scale-125 transition-transform cursor-pointer text-lg" @click="removeCover">delete</span>
</div>
</div> </div>
</div> </div>
<div class="flex-grow"> </div>
<div class="flex-grow">
<form @submit.prevent="submitUploadCover" class="flex flex-grow mb-2 p-2">
<ui-text-input v-model="imageUrl" :placeholder="$strings.LabelImageURLFromTheWeb" class="h-9 w-full" />
<ui-btn color="success" type="submit" :padding-x="4" :disabled="!imageUrl" class="ml-2 sm:ml-3 w-24 h-9">{{ $strings.ButtonSubmit }}</ui-btn>
</form>
<form v-if="author" @submit.prevent="submitForm">
<div class="flex"> <div class="flex">
<div class="w-3/4 p-2"> <div class="w-3/4 p-2">
<ui-text-input-with-label v-model="authorCopy.name" :disabled="processing" :label="$strings.LabelName" /> <ui-text-input-with-label v-model="authorCopy.name" :disabled="processing" :label="$strings.LabelName" />
@@ -25,21 +30,23 @@
<ui-text-input-with-label v-model="authorCopy.asin" :disabled="processing" label="ASIN" /> <ui-text-input-with-label v-model="authorCopy.asin" :disabled="processing" label="ASIN" />
</div> </div>
</div> </div>
<div class="p-2"> <!-- <div class="p-2">
<ui-text-input-with-label v-model="authorCopy.imagePath" :disabled="processing" :label="$strings.LabelPhotoPathURL" /> <ui-text-input-with-label v-model="authorCopy.imagePath" :disabled="processing" :label="$strings.LabelPhotoPathURL" />
</div> </div> -->
<div class="p-2"> <div class="p-2">
<ui-textarea-with-label v-model="authorCopy.description" :disabled="processing" :label="$strings.LabelDescription" :rows="8" /> <ui-textarea-with-label v-model="authorCopy.description" :disabled="processing" :label="$strings.LabelDescription" :rows="8" />
</div> </div>
<div class="flex pt-2 px-2"> <div class="flex pt-2 px-2">
<ui-btn type="button" @click="searchAuthor">{{ $strings.ButtonQuickMatch }}</ui-btn> <ui-btn v-if="userCanDelete" small color="error" type="button" @click.stop="removeClick">{{ $strings.ButtonRemove }}</ui-btn>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn type="button" class="mx-2" @click="searchAuthor">{{ $strings.ButtonQuickMatch }}</ui-btn>
<ui-btn type="submit">{{ $strings.ButtonSave }}</ui-btn> <ui-btn type="submit">{{ $strings.ButtonSave }}</ui-btn>
</div> </div>
</div> </form>
</div> </div>
</form> </div>
</div> </div>
</modals-modal> </modals-modal>
</template> </template>
@@ -51,9 +58,9 @@ export default {
authorCopy: { authorCopy: {
name: '', name: '',
asin: '', asin: '',
description: '', description: ''
imagePath: ''
}, },
imageUrl: '',
processing: false processing: false
} }
}, },
@@ -91,17 +98,45 @@ export default {
}, },
libraryProvider() { libraryProvider() {
return this.$store.getters['libraries/getLibraryProvider'](this.currentLibraryId) || 'google' return this.$store.getters['libraries/getLibraryProvider'](this.currentLibraryId) || 'google'
},
userCanDelete() {
return this.$store.getters['user/getUserCanDelete']
} }
}, },
methods: { methods: {
init() { init() {
this.imageUrl = ''
this.authorCopy.name = this.author.name this.authorCopy.name = this.author.name
this.authorCopy.asin = this.author.asin this.authorCopy.asin = this.author.asin
this.authorCopy.description = this.author.description this.authorCopy.description = this.author.description
this.authorCopy.imagePath = this.author.imagePath },
removeClick() {
const payload = {
message: this.$getString('MessageConfirmRemoveAuthor', [this.author.name]),
callback: (confirmed) => {
if (confirmed) {
this.processing = true
this.$axios
.$delete(`/api/authors/${this.authorId}`)
.then(() => {
this.$toast.success('Author removed')
this.show = false
})
.catch((error) => {
console.error('Failed to remove author', error)
this.$toast.error('Failed to remove author')
})
.finally(() => {
this.processing = false
})
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
}, },
async submitForm() { async submitForm() {
var keysToCheck = ['name', 'asin', 'description', 'imagePath'] var keysToCheck = ['name', 'asin', 'description']
var updatePayload = {} var updatePayload = {}
keysToCheck.forEach((key) => { keysToCheck.forEach((key) => {
if (this.authorCopy[key] !== this.author[key]) { if (this.authorCopy[key] !== this.author[key]) {
@@ -130,21 +165,46 @@ export default {
} }
this.processing = false this.processing = false
}, },
async removeCover() { removeCover() {
var updatePayload = {
imagePath: null
}
this.processing = true this.processing = true
var result = await this.$axios.$patch(`/api/authors/${this.authorId}`, updatePayload).catch((error) => { this.$axios
console.error('Failed', error) .$delete(`/api/authors/${this.authorId}/image`)
this.$toast.error(this.$strings.ToastAuthorImageRemoveFailed) .then((data) => {
return null this.$toast.success(this.$strings.ToastAuthorImageRemoveSuccess)
}) this.$store.commit('globals/showEditAuthorModal', data.author)
if (result && result.updated) { })
this.$toast.success(this.$strings.ToastAuthorImageRemoveSuccess) .catch((error) => {
this.$store.commit('globals/showEditAuthorModal', result.author) console.error('Failed', error)
this.$toast.error(this.$strings.ToastAuthorImageRemoveFailed)
})
.finally(() => {
this.processing = false
})
},
submitUploadCover() {
if (!this.imageUrl?.startsWith('http:') && !this.imageUrl?.startsWith('https:')) {
this.$toast.error('Invalid image url')
return
} }
this.processing = false
this.processing = true
const updatePayload = {
url: this.imageUrl
}
this.$axios
.$post(`/api/authors/${this.authorId}/image`, updatePayload)
.then((data) => {
this.imageUrl = ''
this.$toast.success('Author image updated')
this.$store.commit('globals/showEditAuthorModal', data.author)
})
.catch((error) => {
console.error('Failed', error)
this.$toast.error(error.response.data || 'Failed to remove author image')
})
.finally(() => {
this.processing = false
})
}, },
async searchAuthor() { async searchAuthor() {
if (!this.authorCopy.name && !this.authorCopy.asin) { if (!this.authorCopy.name && !this.authorCopy.asin) {
@@ -8,7 +8,7 @@
<form @submit.prevent="submitForm"> <form @submit.prevent="submitForm">
<div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300"> <div class="w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300">
<div class="w-full px-3 py-5 md:p-12"> <div class="w-full px-3 py-5 md:p-12">
<div class="flex items-center -mx-1 mb-2"> <div class="flex items-center -mx-1 mb-4">
<div class="w-full md:w-1/2 px-1"> <div class="w-full md:w-1/2 px-1">
<ui-text-input-with-label ref="ereaderNameInput" v-model="newDevice.name" :disabled="processing" :label="$strings.LabelName" /> <ui-text-input-with-label ref="ereaderNameInput" v-model="newDevice.name" :disabled="processing" :label="$strings.LabelName" />
</div> </div>
@@ -16,6 +16,14 @@
<ui-text-input-with-label ref="ereaderEmailInput" v-model="newDevice.email" :disabled="processing" :label="$strings.LabelEmail" /> <ui-text-input-with-label ref="ereaderEmailInput" v-model="newDevice.email" :disabled="processing" :label="$strings.LabelEmail" />
</div> </div>
</div> </div>
<div class="flex items-center -mx-1 mb-4">
<div class="w-full md:w-1/2 px-1">
<ui-dropdown v-model="newDevice.availabilityOption" :label="$strings.LabelDeviceIsAvailableTo" :items="userAvailabilityOptions" @input="availabilityOptionChanged" />
</div>
<div class="w-full md:w-1/2 px-1">
<ui-multi-select-dropdown v-if="newDevice.availabilityOption === 'specificUsers'" v-model="newDevice.users" :label="$strings.HeaderUsers" :items="userOptions" />
</div>
</div>
<div class="flex items-center pt-4"> <div class="flex items-center pt-4">
<div class="flex-grow" /> <div class="flex-grow" />
@@ -45,8 +53,11 @@ export default {
processing: false, processing: false,
newDevice: { newDevice: {
name: '', name: '',
email: '' email: '',
} availabilityOption: 'adminAndUp',
users: []
},
users: []
} }
}, },
watch: { watch: {
@@ -68,10 +79,55 @@ export default {
} }
}, },
title() { title() {
return this.ereaderDevice ? 'Create Device' : 'Update Device' return !this.ereaderDevice ? 'Create Device' : 'Update Device'
},
userAvailabilityOptions() {
return [
{
text: this.$strings.LabelAdminUsersOnly,
value: 'adminOrUp'
},
{
text: this.$strings.LabelAllUsersExcludingGuests,
value: 'userOrUp'
},
{
text: this.$strings.LabelAllUsersIncludingGuests,
value: 'guestOrUp'
},
{
text: this.$strings.LabelSelectUsers,
value: 'specificUsers'
}
]
},
userOptions() {
return this.users.map((u) => ({ text: u.username, value: u.id }))
} }
}, },
methods: { methods: {
availabilityOptionChanged(option) {
if (option === 'specificUsers' && !this.users.length) {
this.loadUsers()
}
},
async loadUsers() {
this.processing = true
this.users = await this.$axios
.$get('/api/users')
.then((res) => {
return res.users.sort((a, b) => {
return a.createdAt - b.createdAt
})
})
.catch((error) => {
console.error('Failed', error)
return []
})
.finally(() => {
this.processing = false
})
},
submitForm() { submitForm() {
this.$refs.ereaderNameInput.blur() this.$refs.ereaderNameInput.blur()
this.$refs.ereaderEmailInput.blur() this.$refs.ereaderEmailInput.blur()
@@ -81,19 +137,27 @@ export default {
return return
} }
if (this.newDevice.availabilityOption === 'specificUsers' && !this.newDevice.users.length) {
this.$toast.error('Must select at least one user')
return
}
if (this.newDevice.availabilityOption !== 'specificUsers') {
this.newDevice.users = []
}
this.newDevice.name = this.newDevice.name.trim() this.newDevice.name = this.newDevice.name.trim()
this.newDevice.email = this.newDevice.email.trim() this.newDevice.email = this.newDevice.email.trim()
if (!this.ereaderDevice) { if (!this.ereaderDevice) {
if (this.existingDevices.some((d) => d.name === this.newDevice.name)) { if (this.existingDevices.some((d) => d.name === this.newDevice.name)) {
this.$toast.error('EReader device with that name already exists') this.$toast.error('Ereader device with that name already exists')
return return
} }
this.submitCreate() this.submitCreate()
} else { } else {
if (this.ereaderDevice.name !== this.newDevice.name && this.existingDevices.some((d) => d.name === this.newDevice.name)) { if (this.ereaderDevice.name !== this.newDevice.name && this.existingDevices.some((d) => d.name === this.newDevice.name)) {
this.$toast.error('EReader device with that name already exists') this.$toast.error('Ereader device with that name already exists')
return return
} }
@@ -160,9 +224,17 @@ export default {
if (this.ereaderDevice) { if (this.ereaderDevice) {
this.newDevice.name = this.ereaderDevice.name this.newDevice.name = this.ereaderDevice.name
this.newDevice.email = this.ereaderDevice.email this.newDevice.email = this.ereaderDevice.email
this.newDevice.availabilityOption = this.ereaderDevice.availabilityOption || 'adminOrUp'
this.newDevice.users = this.ereaderDevice.users || []
if (this.newDevice.availabilityOption === 'specificUsers' && !this.users.length) {
this.loadUsers()
}
} else { } else {
this.newDevice.name = '' this.newDevice.name = ''
this.newDevice.email = '' this.newDevice.email = ''
this.newDevice.availabilityOption = 'adminOrUp'
this.newDevice.users = []
} }
} }
}, },
+50 -53
View File
@@ -7,7 +7,7 @@
<!-- book cover overlay --> <!-- book cover overlay -->
<div v-if="media.coverPath" class="absolute top-0 left-0 w-full h-full z-10 opacity-0 hover:opacity-100 transition-opacity duration-100"> <div v-if="media.coverPath" class="absolute top-0 left-0 w-full h-full z-10 opacity-0 hover:opacity-100 transition-opacity duration-100">
<div class="absolute top-0 left-0 w-full h-16 bg-gradient-to-b from-black-600 to-transparent" /> <div class="absolute top-0 left-0 w-full h-16 bg-gradient-to-b from-black-600 to-transparent" />
<div class="p-1 absolute top-1 right-1 text-red-500 rounded-full w-8 h-8 cursor-pointer hover:text-red-400 shadow-sm" @click="removeCover"> <div v-if="userCanDelete" class="p-1 absolute top-1 right-1 text-red-500 rounded-full w-8 h-8 cursor-pointer hover:text-red-400 shadow-sm" @click="removeCover">
<ui-tooltip direction="top" :text="$strings.LabelRemoveCover"> <ui-tooltip direction="top" :text="$strings.LabelRemoveCover">
<span class="material-icons text-2xl">delete</span> <span class="material-icons text-2xl">delete</span>
</ui-tooltip> </ui-tooltip>
@@ -16,15 +16,16 @@
</div> </div>
<div class="flex-grow sm:pl-2 md:pl-6 sm:pr-2 mt-2 md:mt-0"> <div class="flex-grow sm:pl-2 md:pl-6 sm:pr-2 mt-2 md:mt-0">
<div class="flex items-center"> <div class="flex items-center">
<div v-if="userCanUpload" class="w-10 md:w-40 pr-2 pt-4 md:min-w-32"> <div v-if="userCanUpload" class="w-10 md:w-40 pr-2 md:min-w-32">
<ui-file-input ref="fileInput" @change="fileUploadSelected"> <ui-file-input ref="fileInput" @change="fileUploadSelected">
<span class="hidden md:inline-block">{{ $strings.ButtonUploadCover }}</span> <span class="hidden md:inline-block">{{ $strings.ButtonUploadCover }}</span>
<span class="material-icons text-2xl inline-block md:!hidden">upload</span> <span class="material-icons text-2xl inline-block md:!hidden">upload</span>
</ui-file-input> </ui-file-input>
</div> </div>
<form @submit.prevent="submitForm" class="flex flex-grow"> <form @submit.prevent="submitForm" class="flex flex-grow">
<ui-text-input-with-label v-model="imageUrl" :label="$strings.LabelCoverImageURL" /> <ui-text-input v-model="imageUrl" :placeholder="$strings.LabelImageURLFromTheWeb" class="h-9 w-full" />
<ui-btn color="success" type="submit" :padding-x="4" class="mt-5 ml-2 sm:ml-3 w-24">{{ $strings.ButtonSave }}</ui-btn> <ui-btn color="success" type="submit" :padding-x="4" :disabled="!imageUrl" class="ml-2 sm:ml-3 w-24 h-9">{{ $strings.ButtonSubmit }}</ui-btn>
</form> </form>
</div> </div>
@@ -64,7 +65,7 @@
<div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-80 overflow-y-scroll mt-2 max-w-full"> <div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-80 overflow-y-scroll mt-2 max-w-full">
<p v-if="!coversFound.length">{{ $strings.MessageNoCoversFound }}</p> <p v-if="!coversFound.length">{{ $strings.MessageNoCoversFound }}</p>
<template v-for="cover in coversFound"> <template v-for="cover in coversFound">
<div :key="cover" class="m-0.5 mb-5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === imageUrl ? 'border-yellow-300' : ''" @click="updateCover(cover)"> <div :key="cover" class="m-0.5 mb-5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === coverPath ? 'border-yellow-300' : ''" @click="updateCover(cover)">
<covers-preview-cover :src="cover" :width="80" show-open-new-tab :book-cover-aspect-ratio="bookCoverAspectRatio" /> <covers-preview-cover :src="cover" :width="80" show-open-new-tab :book-cover-aspect-ratio="bookCoverAspectRatio" />
</div> </div>
</template> </template>
@@ -165,6 +166,9 @@ export default {
userCanUpload() { userCanUpload() {
return this.$store.getters['user/getUserCanUpload'] return this.$store.getters['user/getUserCanUpload']
}, },
userCanDelete() {
return this.$store.getters['user/getUserCanDelete']
},
userToken() { userToken() {
return this.$store.getters['user/getToken'] return this.$store.getters['user/getToken']
}, },
@@ -222,72 +226,53 @@ export default {
this.coversFound = [] this.coversFound = []
this.hasSearched = false this.hasSearched = false
} }
this.imageUrl = this.media.coverPath || '' this.imageUrl = ''
this.searchTitle = this.mediaMetadata.title || '' this.searchTitle = this.mediaMetadata.title || ''
this.searchAuthor = this.mediaMetadata.authorName || '' this.searchAuthor = this.mediaMetadata.authorName || ''
if (this.isPodcast) this.provider = 'itunes' if (this.isPodcast) this.provider = 'itunes'
else this.provider = localStorage.getItem('book-cover-provider') || localStorage.getItem('book-provider') || 'google' else this.provider = localStorage.getItem('book-cover-provider') || localStorage.getItem('book-provider') || 'google'
}, },
removeCover() { removeCover() {
if (!this.media.coverPath) { if (!this.coverPath) {
this.imageUrl = ''
return return
} }
this.updateCover('') this.isProcessing = true
this.$axios
.$delete(`/api/items/${this.libraryItemId}/cover`)
.then(() => {})
.catch((error) => {
console.error('Failed to remove cover', error)
if (error.response?.data) {
this.$toast.error(error.response.data)
}
})
.finally(() => {
this.isProcessing = false
})
}, },
submitForm() { submitForm() {
this.updateCover(this.imageUrl) this.updateCover(this.imageUrl)
}, },
async updateCover(cover) { async updateCover(cover) {
if (cover === this.coverPath) { if (!cover.startsWith('http:') && !cover.startsWith('https:')) {
console.warn('Cover has not changed..', cover) this.$toast.error('Invalid URL')
return return
} }
this.isProcessing = true this.isProcessing = true
var success = false this.$axios
.$post(`/api/items/${this.libraryItemId}/cover`, { url: cover })
if (!cover) { .then(() => {
// Remove cover this.imageUrl = ''
success = await this.$axios this.$toast.success('Update Successful')
.$delete(`/api/items/${this.libraryItemId}/cover`)
.then(() => true)
.catch((error) => {
console.error('Failed to remove cover', error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
}
return false
})
} else if (cover.startsWith('http:') || cover.startsWith('https:')) {
// Download cover from url and use
success = await this.$axios.$post(`/api/items/${this.libraryItemId}/cover`, { url: cover }).catch((error) => {
console.error('Failed to download cover from url', error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
}
return false
}) })
} else { .catch((error) => {
// Update local cover url console.error('Failed to update cover', error)
const updatePayload = { this.$toast.error(error.response?.data || 'Failed to update cover')
cover })
} .finally(() => {
success = await this.$axios.$patch(`/api/items/${this.libraryItemId}/cover`, updatePayload).catch((error) => { this.isProcessing = false
console.error('Failed to update', error)
if (error.response && error.response.data) {
this.$toast.error(error.response.data)
}
return false
}) })
}
if (success) {
this.$toast.success('Update Successful')
// this.$emit('close')
} else {
this.imageUrl = this.media.coverPath || ''
}
this.isProcessing = false
}, },
getSearchQuery() { getSearchQuery() {
var searchQuery = `provider=${this.provider}&title=${this.searchTitle}` var searchQuery = `provider=${this.provider}&title=${this.searchTitle}`
@@ -320,7 +305,19 @@ export default {
this.hasSearched = true this.hasSearched = true
}, },
setCover(coverFile) { setCover(coverFile) {
this.updateCover(coverFile.metadata.path) this.isProcessing = true
this.$axios
.$patch(`/api/items/${this.libraryItemId}/cover`, { cover: coverFile.metadata.path })
.then(() => {
this.$toast.success('Update Successful')
})
.catch((error) => {
console.error('Failed to set local cover', error)
this.$toast.error(error.response?.data || 'Failed to set cover')
})
.finally(() => {
this.isProcessing = false
})
} }
} }
} }
@@ -11,8 +11,8 @@
<ui-btn v-if="userIsAdminOrUp" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">{{ $strings.ButtonQuickMatch }}</ui-btn> <ui-btn v-if="userIsAdminOrUp" :loading="quickMatching" color="bg" type="button" class="h-full" small @click.stop.prevent="quickMatch">{{ $strings.ButtonQuickMatch }}</ui-btn>
</ui-tooltip> </ui-tooltip>
<ui-tooltip :disabled="!!libraryScan" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4"> <ui-tooltip :disabled="isLibraryScanning" text="Rescan library item including metadata" direction="bottom" class="mr-2 md:mr-4">
<ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="!!libraryScan" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn> <ui-btn v-if="userIsAdminOrUp && !isFile" :loading="rescanning" :disabled="isLibraryScanning" color="bg" type="button" class="h-full" small @click.stop.prevent="rescan">{{ $strings.ButtonReScan }}</ui-btn>
</ui-tooltip> </ui-tooltip>
<div class="flex-grow" /> <div class="flex-grow" />
@@ -80,9 +80,9 @@ export default {
libraryProvider() { libraryProvider() {
return this.$store.getters['libraries/getLibraryProvider'](this.libraryId) || 'google' return this.$store.getters['libraries/getLibraryProvider'](this.libraryId) || 'google'
}, },
libraryScan() { isLibraryScanning() {
if (!this.libraryId) return null if (!this.libraryId) return null
return this.$store.getters['scanners/getLibraryScan'](this.libraryId) return !!this.$store.getters['tasks/getRunningLibraryScanTask'](this.libraryId)
} }
}, },
methods: { methods: {
@@ -20,18 +20,14 @@
<div v-if="!episodes.length" class="flex my-4 text-center justify-center text-xl">{{ $strings.MessageNoEpisodes }}</div> <div v-if="!episodes.length" class="flex my-4 text-center justify-center text-xl">{{ $strings.MessageNoEpisodes }}</div>
<table v-else class="text-sm tracksTable"> <table v-else class="text-sm tracksTable">
<tr> <tr>
<th class="text-left">Sort #</th> <th class="text-center w-20 min-w-20">{{ $strings.LabelEpisode }}</th>
<th class="text-left whitespace-nowrap">{{ $strings.LabelEpisode }}</th> <th class="text-left">{{ $strings.LabelEpisodeTitle }}</th>
<th class="text-left">{{ $strings.EpisodeTitle }}</th> <th class="text-center w-28">{{ $strings.LabelEpisodeDuration }}</th>
<th class="text-center w-28">{{ $strings.EpisodeDuration }}</th> <th class="text-center w-28">{{ $strings.LabelEpisodeSize }}</th>
<th class="text-center w-28">{{ $strings.EpisodeSize }}</th>
</tr> </tr>
<tr v-for="episode in episodes" :key="episode.id"> <tr v-for="episode in episodes" :key="episode.id">
<td class="text-left"> <td class="text-center w-20 min-w-20">
<p class="px-4">{{ episode.index }}</p> <p>{{ episode.episode }}</p>
</td>
<td class="text-left">
<p class="px-4">{{ episode.episode }}</p>
</td> </td>
<td> <td>
{{ episode.title }} {{ episode.title }}
+1 -2
View File
@@ -14,8 +14,7 @@ export default {
}, },
data() { data() {
return { return {
tracks: [], tracks: []
showFullPath: false
} }
}, },
watch: { watch: {
+12 -7
View File
@@ -22,7 +22,7 @@
</div> </div>
<div v-show="!processing" class="w-full max-h-full overflow-y-auto overflow-x-hidden matchListWrapper mt-4"> <div v-show="!processing" class="w-full max-h-full overflow-y-auto overflow-x-hidden matchListWrapper mt-4">
<template v-for="(res, index) in searchResults"> <template v-for="(res, index) in searchResults">
<cards-book-match-card :key="index" :book="res" :is-podcast="isPodcast" :book-cover-aspect-ratio="bookCoverAspectRatio" @select="selectMatch" /> <cards-book-match-card :key="index" :book="res" :current-book-duration="currentBookDuration" :is-podcast="isPodcast" :book-cover-aspect-ratio="bookCoverAspectRatio" @select="selectMatch" />
</template> </template>
</div> </div>
<div v-if="selectedMatchOrig" class="absolute top-0 left-0 w-full bg-bg h-full px-2 py-6 md:p-8 max-h-full overflow-y-auto overflow-x-hidden"> <div v-if="selectedMatchOrig" class="absolute top-0 left-0 w-full bg-bg h-full px-2 py-6 md:p-8 max-h-full overflow-y-auto overflow-x-hidden">
@@ -290,13 +290,17 @@ export default {
return this.$strings.LabelSearchTitle return this.$strings.LabelSearchTitle
}, },
media() { media() {
return this.libraryItem ? this.libraryItem.media || {} : {} return this.libraryItem?.media || {}
}, },
mediaMetadata() { mediaMetadata() {
return this.media.metadata || {} return this.media.metadata || {}
}, },
currentBookDuration() {
if (this.isPodcast) return 0
return this.media.duration || 0
},
mediaType() { mediaType() {
return this.libraryItem ? this.libraryItem.mediaType : null return this.libraryItem?.mediaType || null
}, },
isPodcast() { isPodcast() {
return this.mediaType == 'podcast' return this.mediaType == 'podcast'
@@ -305,7 +309,7 @@ export default {
const filterData = this.$store.state.libraries.filterData || {} const filterData = this.$store.state.libraries.filterData || {}
const currentGenres = filterData.genres || [] const currentGenres = filterData.genres || []
const selectedMatchGenres = this.selectedMatch.genres || [] const selectedMatchGenres = this.selectedMatch.genres || []
return [...new Set([...currentGenres ,...selectedMatchGenres])] return [...new Set([...currentGenres, ...selectedMatchGenres])]
} }
}, },
methods: { methods: {
@@ -325,9 +329,9 @@ export default {
} }
}, },
getSearchQuery() { getSearchQuery() {
if (this.isPodcast) return `term=${this.searchTitle}` if (this.isPodcast) return `term=${encodeURIComponent(this.searchTitle)}`
var searchQuery = `provider=${this.provider}&fallbackTitleOnly=1&title=${this.searchTitle}` var searchQuery = `provider=${this.provider}&fallbackTitleOnly=1&title=${encodeURIComponent(this.searchTitle)}`
if (this.searchAuthor) searchQuery += `&author=${this.searchAuthor}` if (this.searchAuthor) searchQuery += `&author=${encodeURIComponent(this.searchAuthor)}`
return searchQuery return searchQuery
}, },
submitSearch() { submitSearch() {
@@ -580,6 +584,7 @@ export default {
.matchListWrapper { .matchListWrapper {
height: calc(100% - 124px); height: calc(100% - 124px);
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.matchListWrapper { .matchListWrapper {
height: calc(100% - 80px); height: calc(100% - 80px);
@@ -20,7 +20,7 @@
<p class="px-1 text-sm font-semibold">{{ $strings.LabelFolders }}</p> <p class="px-1 text-sm font-semibold">{{ $strings.LabelFolders }}</p>
<div v-for="(folder, index) in folders" :key="index" class="w-full flex items-center py-1 px-2"> <div v-for="(folder, index) in folders" :key="index" class="w-full flex items-center py-1 px-2">
<span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span> <span class="material-icons bg-opacity-50 mr-2 text-yellow-200" style="font-size: 1.2rem">folder</span>
<ui-editable-text ref="folderInput" v-model="folder.fullPath" readonly type="text" class="w-full" /> <ui-editable-text ref="folderInput" v-model="folder.fullPath" :readonly="!!folder.id" type="text" class="w-full" @blur="existingFolderInputBlurred(folder)" />
<span v-show="folders.length > 1" class="material-icons text-2xl ml-2 cursor-pointer hover:text-error" @click="removeFolder(folder)">close</span> <span v-show="folders.length > 1" class="material-icons text-2xl ml-2 cursor-pointer hover:text-error" @click="removeFolder(folder)">close</span>
</div> </div>
<div class="flex py-1 px-2 items-center w-full"> <div class="flex py-1 px-2 items-center w-full">
@@ -67,10 +67,6 @@ export default {
value: 'podcast', value: 'podcast',
text: this.$strings.LabelPodcasts text: this.$strings.LabelPodcasts
} }
// {
// value: 'music',
// text: 'Music'
// }
] ]
}, },
folderPaths() { folderPaths() {
@@ -110,6 +106,11 @@ export default {
formUpdated() { formUpdated() {
this.$emit('update', this.getLibraryData()) this.$emit('update', this.getLibraryData())
}, },
existingFolderInputBlurred(folder) {
if (!folder.fullPath) {
this.removeFolder(folder)
}
},
newFolderInputBlurred() { newFolderInputBlurred() {
if (this.newFolderPath) { if (this.newFolderPath) {
this.folders.push({ fullPath: this.newFolderPath }) this.folders.push({ fullPath: this.newFolderPath })
@@ -149,6 +150,7 @@ export default {
this.folders = this.library ? this.library.folders.map((p) => ({ ...p })) : [] this.folders = this.library ? this.library.folders.map((p) => ({ ...p })) : []
this.icon = this.library ? this.library.icon : 'default' this.icon = this.library ? this.library.icon : 'default'
this.mediaType = this.library ? this.library.mediaType : 'book' this.mediaType = this.library ? this.library.mediaType : 'book'
this.showDirectoryPicker = false this.showDirectoryPicker = false
} }
}, },
@@ -1,5 +1,5 @@
<template> <template>
<modals-modal v-model="show" name="edit-library" :width="700" :height="'unset'" :processing="processing"> <modals-modal v-model="show" name="edit-library" :width="800" :height="'unset'" :processing="processing">
<template #outer> <template #outer>
<div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden"> <div class="absolute top-0 left-0 p-5 w-2/3 overflow-hidden">
<p class="text-xl md:text-3xl text-white truncate">{{ title }}</p> <p class="text-xl md:text-3xl text-white truncate">{{ title }}</p>
@@ -12,9 +12,9 @@
</div> </div>
<div class="px-2 md:px-4 w-full text-sm pt-2 md:pt-6 pb-20 rounded-b-lg rounded-tr-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh"> <div class="px-2 md:px-4 w-full text-sm pt-2 md:pt-6 pb-20 rounded-b-lg rounded-tr-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden" style="min-height: 400px; max-height: 80vh">
<component v-if="libraryCopy && show" ref="tabComponent" :is="tabName" :is-new="!library" :library="libraryCopy" :processing.sync="processing" @update="updateLibrary" @close="show = false" /> <component v-if="libraryCopy && show" ref="tabComponent" :is="tabName" :is-new="!library" :library="libraryCopy" :library-id="libraryId" :processing.sync="processing" @update="updateLibrary" @close="show = false" />
<div class="absolute bottom-0 left-0 w-full px-4 py-4 border-t border-white border-opacity-10"> <div v-show="selectedTab !== 'tools'" class="absolute bottom-0 left-0 w-full px-4 py-4 border-t border-white border-opacity-10">
<div class="flex justify-end"> <div class="flex justify-end">
<ui-btn @click="submit">{{ buttonText }}</ui-btn> <ui-btn @click="submit">{{ buttonText }}</ui-btn>
</div> </div>
@@ -54,6 +54,12 @@ export default {
buttonText() { buttonText() {
return this.library ? this.$strings.ButtonSave : this.$strings.ButtonCreate return this.library ? this.$strings.ButtonSave : this.$strings.ButtonCreate
}, },
mediaType() {
return this.libraryCopy?.mediaType
},
libraryId() {
return this.library?.id
},
tabs() { tabs() {
return [ return [
{ {
@@ -66,12 +72,26 @@ export default {
title: this.$strings.HeaderSettings, title: this.$strings.HeaderSettings,
component: 'modals-libraries-library-settings' component: 'modals-libraries-library-settings'
}, },
{
id: 'scanner',
title: this.$strings.HeaderSettingsScanner,
component: 'modals-libraries-library-scanner-settings'
},
{ {
id: 'schedule', id: 'schedule',
title: this.$strings.HeaderSchedule, title: this.$strings.HeaderSchedule,
component: 'modals-libraries-schedule-scan' component: 'modals-libraries-schedule-scan'
},
{
id: 'tools',
title: this.$strings.HeaderTools,
component: 'modals-libraries-library-tools'
} }
] ].filter((tab) => {
// Do not show tools tab for new libraries
if (tab.id === 'tools' && !this.library) return false
return tab.id !== 'scanner' || this.mediaType === 'book'
})
}, },
tabName() { tabName() {
var _tab = this.tabs.find((t) => t.id === this.selectedTab) var _tab = this.tabs.find((t) => t.id === this.selectedTab)
@@ -105,7 +125,9 @@ export default {
disableWatcher: false, disableWatcher: false,
skipMatchingMediaWithAsin: false, skipMatchingMediaWithAsin: false,
skipMatchingMediaWithIsbn: false, skipMatchingMediaWithIsbn: false,
autoScanCronExpression: null autoScanCronExpression: null,
hideSingleBookSeries: false,
metadataPrecedence: ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
} }
} }
}, },
@@ -120,7 +142,7 @@ export default {
for (const key in this.libraryCopy) { for (const key in this.libraryCopy) {
if (library[key] !== undefined) { if (library[key] !== undefined) {
if (key === 'folders') { if (key === 'folders') {
this.libraryCopy.folders = library.folders.map((f) => ({ ...f })) this.libraryCopy.folders = library.folders.map((f) => ({ ...f })).filter((f) => !!f.fullPath?.trim())
} else if (key === 'settings') { } else if (key === 'settings') {
for (const settingKey in library.settings) { for (const settingKey in library.settings) {
this.libraryCopy.settings[settingKey] = library.settings[settingKey] this.libraryCopy.settings[settingKey] = library.settings[settingKey]
@@ -0,0 +1,160 @@
<template>
<div class="w-full h-full px-1 md:px-4 py-1 mb-4">
<div class="flex items-center justify-between mb-2">
<h2 class="text-base md:text-lg text-gray-200">{{ $strings.HeaderMetadataOrderOfPrecedence }}</h2>
<ui-btn small @click="resetToDefault">{{ $strings.ButtonResetToDefault }}</ui-btn>
</div>
<div class="flex items-center justify-between md:justify-start mb-4">
<p class="text-sm text-gray-300 pr-2">{{ $strings.LabelMetadataOrderOfPrecedenceDescription }}</p>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex">
<a href="https://www.audiobookshelf.org/guides/book-scanner" target="_blank" class="inline-flex">
<span class="material-icons text-xl w-5">help_outline</span>
</a>
</ui-tooltip>
</div>
<draggable v-model="metadataSourceMapped" v-bind="dragOptions" class="list-group" draggable=".item" handle=".drag-handle" tag="ul" @start="drag = true" @end="drag = false" @update="draggableUpdate">
<transition-group type="transition" :name="!drag ? 'flip-list' : null">
<li v-for="(source, index) in metadataSourceMapped" :key="source.id" :class="source.include ? 'item' : 'opacity-50'" class="w-full px-2 flex items-center relative border border-white/10">
<span class="material-icons drag-handle text-xl text-gray-400 hover:text-gray-50 mr-2 md:mr-4">reorder</span>
<div class="text-center py-1 w-8 min-w-8">
{{ source.include ? getSourceIndex(source.id) : '' }}
</div>
<div class="flex-grow inline-flex justify-between px-4 py-3">
{{ source.name }} <span v-if="source.include && (index === firstActiveSourceIndex || index === lastActiveSourceIndex)" class="px-2 italic font-semibold text-xs text-gray-400">{{ index === firstActiveSourceIndex ? $strings.LabelHighestPriority : $strings.LabelLowestPriority }}</span>
</div>
<div class="px-2 opacity-100">
<ui-toggle-switch v-model="source.include" :off-color="'error'" @input="includeToggled(source)" />
</div>
</li>
</transition-group>
</draggable>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: {
draggable
},
props: {
library: {
type: Object,
default: () => null
},
processing: Boolean
},
data() {
return {
drag: false,
dragOptions: {
animation: 200,
group: 'description',
ghostClass: 'ghost'
},
metadataSourceData: {
folderStructure: {
id: 'folderStructure',
name: 'Folder structure',
include: true
},
audioMetatags: {
id: 'audioMetatags',
name: 'Audio file meta tags',
include: true
},
nfoFile: {
id: 'nfoFile',
name: 'NFO file',
include: true
},
txtFiles: {
id: 'txtFiles',
name: 'desc.txt & reader.txt files',
include: true
},
opfFile: {
id: 'opfFile',
name: 'OPF file',
include: true
},
absMetadata: {
id: 'absMetadata',
name: 'Audiobookshelf metadata file',
include: true
}
},
metadataSourceMapped: []
}
},
computed: {
librarySettings() {
return this.library.settings || {}
},
mediaType() {
return this.library.mediaType
},
isBookLibrary() {
return this.mediaType === 'book'
},
firstActiveSourceIndex() {
return this.metadataSourceMapped.findIndex((source) => source.include)
},
lastActiveSourceIndex() {
return this.metadataSourceMapped.findLastIndex((source) => source.include)
}
},
methods: {
getSourceIndex(source) {
const activeSources = (this.librarySettings.metadataPrecedence || []).map((s) => s).reverse()
return activeSources.findIndex((s) => s === source) + 1
},
resetToDefault() {
this.metadataSourceMapped = []
for (const key in this.metadataSourceData) {
this.metadataSourceMapped.push({ ...this.metadataSourceData[key] })
}
this.metadataSourceMapped.reverse()
this.$emit('update', this.getLibraryData())
},
getLibraryData() {
const metadataSourceIds = this.metadataSourceMapped.map((source) => (source.include ? source.id : null)).filter((s) => s)
metadataSourceIds.reverse()
return {
settings: {
metadataPrecedence: metadataSourceIds
}
}
},
includeToggled(source) {
this.updated()
},
draggableUpdate() {
this.updated()
},
updated() {
this.$emit('update', this.getLibraryData())
},
init() {
const metadataPrecedence = this.librarySettings.metadataPrecedence || []
this.metadataSourceMapped = metadataPrecedence.map((source) => this.metadataSourceData[source]).filter((s) => s)
for (const sourceKey in this.metadataSourceData) {
if (!metadataPrecedence.includes(sourceKey)) {
const unusedSourceData = { ...this.metadataSourceData[sourceKey], include: false }
this.metadataSourceMapped.unshift(unusedSourceData)
}
}
this.metadataSourceMapped.reverse()
}
},
mounted() {
this.init()
}
}
</script>
@@ -11,9 +11,9 @@
</div> </div>
<div class="py-3"> <div class="py-3">
<div class="flex items-center"> <div class="flex items-center">
<ui-toggle-switch v-if="!globalWatcherDisabled" v-model="disableWatcher" @input="formUpdated" /> <ui-toggle-switch v-if="!globalWatcherDisabled" v-model="enableWatcher" @input="formUpdated" />
<ui-toggle-switch v-else disabled :value="false" /> <ui-toggle-switch v-else disabled :value="false" />
<p class="pl-4 text-base">{{ $strings.LabelSettingsDisableWatcherForLibrary }}</p> <p class="pl-4 text-base">{{ $strings.LabelSettingsEnableWatcherForLibrary }}</p>
</div> </div>
<p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p> <p v-if="globalWatcherDisabled" class="text-xs text-warning">*{{ $strings.MessageWatcherIsDisabledGlobally }}</p>
</div> </div>
@@ -65,7 +65,7 @@ export default {
return { return {
provider: null, provider: null,
useSquareBookCovers: false, useSquareBookCovers: false,
disableWatcher: false, enableWatcher: false,
skipMatchingMediaWithAsin: false, skipMatchingMediaWithAsin: false,
skipMatchingMediaWithIsbn: false, skipMatchingMediaWithIsbn: false,
audiobooksOnly: false, audiobooksOnly: false,
@@ -95,7 +95,7 @@ export default {
return { return {
settings: { settings: {
coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD, coverAspectRatio: this.useSquareBookCovers ? this.$constants.BookCoverAspectRatio.SQUARE : this.$constants.BookCoverAspectRatio.STANDARD,
disableWatcher: !!this.disableWatcher, disableWatcher: !this.enableWatcher,
skipMatchingMediaWithAsin: !!this.skipMatchingMediaWithAsin, skipMatchingMediaWithAsin: !!this.skipMatchingMediaWithAsin,
skipMatchingMediaWithIsbn: !!this.skipMatchingMediaWithIsbn, skipMatchingMediaWithIsbn: !!this.skipMatchingMediaWithIsbn,
audiobooksOnly: !!this.audiobooksOnly, audiobooksOnly: !!this.audiobooksOnly,
@@ -108,7 +108,7 @@ export default {
}, },
init() { init() {
this.useSquareBookCovers = this.librarySettings.coverAspectRatio === this.$constants.BookCoverAspectRatio.SQUARE this.useSquareBookCovers = this.librarySettings.coverAspectRatio === this.$constants.BookCoverAspectRatio.SQUARE
this.disableWatcher = !!this.librarySettings.disableWatcher this.enableWatcher = !this.librarySettings.disableWatcher
this.skipMatchingMediaWithAsin = !!this.librarySettings.skipMatchingMediaWithAsin this.skipMatchingMediaWithAsin = !!this.librarySettings.skipMatchingMediaWithAsin
this.skipMatchingMediaWithIsbn = !!this.librarySettings.skipMatchingMediaWithIsbn this.skipMatchingMediaWithIsbn = !!this.librarySettings.skipMatchingMediaWithIsbn
this.audiobooksOnly = !!this.librarySettings.audiobooksOnly this.audiobooksOnly = !!this.librarySettings.audiobooksOnly
@@ -0,0 +1,81 @@
<template>
<div class="w-full h-full px-1 md:px-2 py-1 mb-4">
<div class="w-full border border-black-200 p-4 my-8">
<div class="flex flex-wrap items-center">
<div>
<p class="text-lg">Remove metadata files in library item folders</p>
<p class="max-w-sm text-sm pt-2 text-gray-300">Remove all metadata.json or metadata.abs files in your {{ mediaType }} folders</p>
</div>
<div class="flex-grow" />
<div>
<ui-btn class="mb-4 block" @click.stop="removeAllMetadataClick('json')">Remove all metadata.json</ui-btn>
<ui-btn @click.stop="removeAllMetadataClick('abs')">Remove all metadata.abs</ui-btn>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
library: {
type: Object,
default: () => null
},
libraryId: String,
processing: Boolean
},
data() {
return {}
},
computed: {
librarySettings() {
return this.library.settings || {}
},
mediaType() {
return this.library.mediaType
},
isBookLibrary() {
return this.mediaType === 'book'
}
},
methods: {
removeAllMetadataClick(ext) {
const payload = {
message: `Are you sure you want to remove all metadata.${ext} files in your library item folders?`,
persistent: true,
callback: (confirmed) => {
if (confirmed) {
this.removeAllMetadataInLibrary(ext)
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
},
removeAllMetadataInLibrary(ext) {
this.$emit('update:processing', true)
this.$axios
.$post(`/api/libraries/${this.libraryId}/remove-metadata?ext=${ext}`)
.then((data) => {
if (!data.found) {
this.$toast.info(`No metadata.${ext} files were found in library`)
} else if (!data.removed) {
this.$toast.success(`No metadata.${ext} files removed`)
} else {
this.$toast.success(`Successfully removed ${data.removed} metadata.${ext} files`)
}
})
.catch((error) => {
console.error('Failed to remove metadata files', error)
this.$toast.error('Failed to remove metadata files')
})
.finally(() => {
this.$emit('update:processing', false)
})
}
},
mounted() {}
}
</script>
@@ -16,11 +16,11 @@
v-for="(episode, index) in episodesList" v-for="(episode, index) in episodesList"
:key="index" :key="index"
class="relative" class="relative"
:class="itemEpisodeMap[episode.cleanUrl] ? 'bg-primary bg-opacity-40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'" :class="getIsEpisodeDownloaded(episode) ? 'bg-primary bg-opacity-40' : selectedEpisodes[episode.cleanUrl] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'"
@click="toggleSelectEpisode(episode)" @click="toggleSelectEpisode(episode)"
> >
<div class="absolute top-0 left-0 h-full flex items-center p-2"> <div class="absolute top-0 left-0 h-full flex items-center p-2">
<span v-if="itemEpisodeMap[episode.cleanUrl]" class="material-icons text-success text-xl">download_done</span> <span v-if="getIsEpisodeDownloaded(episode)" class="material-icons text-success text-xl">download_done</span>
<ui-checkbox v-else v-model="selectedEpisodes[episode.cleanUrl]" small checkbox-bg="primary" border-color="gray-600" /> <ui-checkbox v-else v-model="selectedEpisodes[episode.cleanUrl]" small checkbox-bg="primary" border-color="gray-600" />
</div> </div>
<div class="px-8 py-2"> <div class="px-8 py-2">
@@ -93,7 +93,7 @@ export default {
return this.libraryItem.media.metadata.title || 'Unknown' return this.libraryItem.media.metadata.title || 'Unknown'
}, },
allDownloaded() { allDownloaded() {
return !this.episodesCleaned.some((episode) => !this.itemEpisodeMap[episode.cleanUrl]) return !this.episodesCleaned.some((episode) => !this.getIsEpisodeDownloaded(episode))
}, },
episodesSelected() { episodesSelected() {
return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key]) return Object.keys(this.selectedEpisodes).filter((key) => !!this.selectedEpisodes[key])
@@ -104,18 +104,7 @@ export default {
return this.$getString('LabelDownloadNEpisodes', [this.episodesSelected.length]) return this.$getString('LabelDownloadNEpisodes', [this.episodesSelected.length])
}, },
itemEpisodes() { itemEpisodes() {
if (!this.libraryItem) return [] return this.libraryItem?.media.episodes || []
return this.libraryItem.media.episodes || []
},
itemEpisodeMap() {
const map = {}
this.itemEpisodes.forEach((item) => {
if (item.enclosure) {
const cleanUrl = this.getCleanEpisodeUrl(item.enclosure.url)
map[cleanUrl] = true
}
})
return map
}, },
episodesList() { episodesList() {
return this.episodesCleaned.filter((episode) => { return this.episodesCleaned.filter((episode) => {
@@ -127,12 +116,23 @@ export default {
if (this.episodesList.length === this.episodesCleaned.length) { if (this.episodesList.length === this.episodesCleaned.length) {
return this.$strings.LabelSelectAllEpisodes return this.$strings.LabelSelectAllEpisodes
} }
const episodesNotDownloaded = this.episodesList.filter((ep) => !this.itemEpisodeMap[ep.cleanUrl]).length const episodesNotDownloaded = this.episodesList.filter((ep) => !this.getIsEpisodeDownloaded(ep)).length
return this.$getString('LabelSelectEpisodesShowing', [episodesNotDownloaded]) return this.$getString('LabelSelectEpisodesShowing', [episodesNotDownloaded])
} }
}, },
methods: { methods: {
getIsEpisodeDownloaded(episode) {
return this.itemEpisodes.some((downloadedEpisode) => {
if (episode.guid && downloadedEpisode.guid === episode.guid) return true
if (!downloadedEpisode.enclosure?.url) return false
return this.getCleanEpisodeUrl(downloadedEpisode.enclosure.url) === episode.cleanUrl
})
},
/** /**
* UPDATE: As of v2.4.5 guid is used for matching existing downloaded episodes if it is found on the RSS feed.
* Fallback to checking the clean url
* @see https://github.com/advplyr/audiobookshelf/issues/2207
*
* RSS feed episode url is used for matching with existing downloaded episodes. * RSS feed episode url is used for matching with existing downloaded episodes.
* Some RSS feeds include timestamps in the episode url (e.g. patreon) that can change on requests. * Some RSS feeds include timestamps in the episode url (e.g. patreon) that can change on requests.
* These need to be removed in order to detect the same episode each time the feed is pulled. * These need to be removed in order to detect the same episode each time the feed is pulled.
@@ -169,13 +169,13 @@ export default {
}, },
toggleSelectAll(val) { toggleSelectAll(val) {
for (const episode of this.episodesList) { for (const episode of this.episodesList) {
if (this.itemEpisodeMap[episode.cleanUrl]) this.selectedEpisodes[episode.cleanUrl] = false if (this.getIsEpisodeDownloaded(episode)) this.selectedEpisodes[episode.cleanUrl] = false
else this.$set(this.selectedEpisodes, episode.cleanUrl, val) else this.$set(this.selectedEpisodes, episode.cleanUrl, val)
} }
}, },
checkSetIsSelectedAll() { checkSetIsSelectedAll() {
for (const episode of this.episodesList) { for (const episode of this.episodesList) {
if (!this.itemEpisodeMap[episode.cleanUrl] && !this.selectedEpisodes[episode.cleanUrl]) { if (!this.getIsEpisodeDownloaded(episode) && !this.selectedEpisodes[episode.cleanUrl]) {
this.selectAll = false this.selectAll = false
return return
} }
@@ -183,7 +183,7 @@ export default {
this.selectAll = true this.selectAll = true
}, },
toggleSelectEpisode(episode) { toggleSelectEpisode(episode) {
if (this.itemEpisodeMap[episode.cleanUrl]) return if (this.getIsEpisodeDownloaded(episode)) return
this.$set(this.selectedEpisodes, episode.cleanUrl, !this.selectedEpisodes[episode.cleanUrl]) this.$set(this.selectedEpisodes, episode.cleanUrl, !this.selectedEpisodes[episode.cleanUrl])
this.checkSetIsSelectedAll() this.checkSetIsSelectedAll()
}, },
@@ -132,6 +132,8 @@ export default {
return return
} }
this.processing = true
const payload = { const payload = {
serverAddress: window.origin, serverAddress: window.origin,
slug: this.newFeedSlug, slug: this.newFeedSlug,
@@ -151,6 +153,9 @@ export default {
const errorMsg = error.response ? error.response.data : null const errorMsg = error.response ? error.response.data : null
this.$toast.error(errorMsg || 'Failed to open RSS Feed') this.$toast.error(errorMsg || 'Failed to open RSS Feed')
}) })
.finally(() => {
this.processing = false
})
}, },
copyToClipboard(str) { copyToClipboard(str) {
this.$copyToClipboard(str, this) this.$copyToClipboard(str, this)
@@ -0,0 +1,124 @@
<template>
<modals-modal v-model="show" name="rss-feed-view-modal" :processing="processing" :width="700" :height="'unset'">
<div ref="wrapper" class="px-8 py-6 w-full text-sm rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden">
<div v-if="feed" class="w-full">
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
<div class="w-full relative">
<ui-text-input v-model="feed.feedUrl" readonly />
<span class="material-icons absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feed.feedUrl)">content_copy</span>
</div>
<div v-if="feed.meta" class="mt-5">
<div class="flex py-0.5">
<div class="w-48">
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelRSSFeedPreventIndexing }}</span>
</div>
<div>{{ feed.meta.preventIndexing ? 'Yes' : 'No' }}</div>
</div>
<div v-if="feed.meta.ownerName" class="flex py-0.5">
<div class="w-48">
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelRSSFeedCustomOwnerName }}</span>
</div>
<div>{{ feed.meta.ownerName }}</div>
</div>
<div v-if="feed.meta.ownerEmail" class="flex py-0.5">
<div class="w-48">
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelRSSFeedCustomOwnerEmail }}</span>
</div>
<div>{{ feed.meta.ownerEmail }}</div>
</div>
</div>
<!-- -->
<div class="episodesTable mt-2">
<div class="bg-primary bg-opacity-40 h-12 header">
{{ $strings.LabelEpisodeTitle }}
</div>
<div class="scroller">
<div v-for="episode in feed.episodes" :key="episode.id" class="h-8 text-xs truncate">
{{ episode.title }}
</div>
</div>
</div>
</div>
</div>
</modals-modal>
</template>
<script>
export default {
props: {
value: Boolean,
feed: {
type: Object,
default: () => {}
}
},
data() {
return {
processing: false
}
},
computed: {
show: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
_feed() {
return this.feed || {}
}
},
methods: {
copyToClipboard(str) {
this.$copyToClipboard(str, this)
}
},
mounted() {}
}
</script>
<style scoped>
.episodesTable {
width: 100%;
max-width: 100%;
border: 1px solid #474747;
display: flex;
flex-direction: column;
}
.episodesTable div.header {
background-color: #272727;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 4px 8px;
}
.episodesTable .scroller {
display: flex;
flex-direction: column;
max-height: 250px;
overflow-x: hidden;
overflow-y: scroll;
}
.episodesTable .scroller div {
background-color: #373838;
padding: 4px 8px;
display: flex;
align-items: center;
justify-content: flex-start;
height: 32px;
flex: 0 0 32px;
}
.episodesTable .scroller div:nth-child(even) {
background-color: #2f2f2f;
}
</style>
+2 -2
View File
@@ -303,8 +303,8 @@ export default {
}, },
parseImageFilename(filename) { parseImageFilename(filename) {
var basename = Path.basename(filename, Path.extname(filename)) var basename = Path.basename(filename, Path.extname(filename))
var numbersinpath = basename.match(/\d{1,5}/g) var numbersinpath = basename.match(/\d+/g)
if (!numbersinpath || !numbersinpath.length) { if (!numbersinpath?.length) {
return { return {
index: -1, index: -1,
filename filename
+109 -4
View File
@@ -40,8 +40,10 @@ export default {
book: null, book: null,
/** @type {ePub.Rendition} */ /** @type {ePub.Rendition} */
rendition: null, rendition: null,
chapters: [],
ereaderSettings: { ereaderSettings: {
theme: 'dark', theme: 'dark',
font: 'serif',
fontScale: 100, fontScale: 100,
lineSpacing: 115, lineSpacing: 115,
spread: 'auto' spread: 'auto'
@@ -67,10 +69,6 @@ export default {
hasNext() { hasNext() {
return !this.rendition?.location?.atEnd return !this.rendition?.location?.atEnd
}, },
/** @returns {Array<ePub.NavItem>} */
chapters() {
return this.book?.navigation?.toc || []
},
userMediaProgress() { userMediaProgress() {
if (!this.libraryItemId) return if (!this.libraryItemId) return
return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId) return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId)
@@ -130,17 +128,55 @@ export default {
const fontScale = settings.fontScale || 100 const fontScale = settings.fontScale || 100
this.rendition.themes.fontSize(`${fontScale}%`) this.rendition.themes.fontSize(`${fontScale}%`)
this.rendition.themes.font(settings.font)
this.rendition.spread(settings.spread || 'auto') this.rendition.spread(settings.spread || 'auto')
}, },
prev() { prev() {
if (!this.rendition?.manager) return
return this.rendition?.prev() return this.rendition?.prev()
}, },
next() { next() {
if (!this.rendition?.manager) return
return this.rendition?.next() return this.rendition?.next()
}, },
goToChapter(href) { goToChapter(href) {
if (!this.rendition?.manager) return
return this.rendition?.display(href) return this.rendition?.display(href)
}, },
/** @returns {object} Returns the chapter that the `position` in the book is in */
findChapterFromPosition(chapters, position) {
let foundChapter
for (let i = 0; i < chapters.length; i++) {
if (position >= chapters[i].start && (!chapters[i + 1] || position < chapters[i + 1].start)) {
foundChapter = chapters[i]
if (chapters[i].subitems && chapters[i].subitems.length > 0) {
return this.findChapterFromPosition(chapters[i].subitems, position, foundChapter)
}
break
}
}
return foundChapter
},
/** @returns {Array} Returns an array of chapters that only includes chapters with query results */
async searchBook(query) {
const chapters = structuredClone(await this.chapters)
const searchResults = await Promise.all(this.book.spine.spineItems.map((item) => item.load(this.book.load.bind(this.book)).then(item.find.bind(item, query)).finally(item.unload.bind(item))))
const mergedResults = [].concat(...searchResults)
mergedResults.forEach((chapter) => {
chapter.start = this.book.locations.percentageFromCfi(chapter.cfi)
const foundChapter = this.findChapterFromPosition(chapters, chapter.start)
if (foundChapter) foundChapter.searchResults.push(chapter)
})
let filteredResults = chapters.filter(function f(o) {
if (o.searchResults.length) return true
if (o.subitems.length) {
return (o.subitems = o.subitems.filter(f)).length
}
})
return filteredResults
},
keyUp(e) { keyUp(e) {
const rtl = this.book.package.metadata.direction === 'rtl' const rtl = this.book.package.metadata.direction === 'rtl'
if ((e.keyCode || e.which) == 37) { if ((e.keyCode || e.which) == 37) {
@@ -314,8 +350,77 @@ export default {
this.checkSaveLocations(reader.book.locations.save()) this.checkSaveLocations(reader.book.locations.save())
}) })
} }
this.getChapters()
}) })
}, },
getChapters() {
// Load the list of chapters in the book. See https://github.com/futurepress/epub.js/issues/759
const toc = this.book?.navigation?.toc || []
const tocTree = []
const resolveURL = (url, relativeTo) => {
// see https://github.com/futurepress/epub.js/issues/1084
// HACK-ish: abuse the URL API a little to resolve the path
// the base needs to be a valid URL, or it will throw a TypeError,
// so we just set a random base URI and remove it later
const base = 'https://example.invalid/'
return new URL(url, base + relativeTo).href.replace(base, '')
}
const basePath = this.book.packaging.navPath || this.book.packaging.ncxPath
const createTree = async (toc, parent) => {
const promises = toc.map(async (tocItem, i) => {
const href = resolveURL(tocItem.href, basePath)
const id = href.split('#')[1]
const item = this.book.spine.get(href)
await item.load(this.book.load.bind(this.book))
const el = id ? item.document.getElementById(id) : item.document.body
const cfi = item.cfiFromElement(el)
parent[i] = {
title: tocItem.label.trim(),
subitems: [],
href,
cfi,
start: this.book.locations.percentageFromCfi(cfi),
end: null, // set by flattenChapters()
id: null, // set by flattenChapters()
searchResults: []
}
if (tocItem.subitems) {
await createTree(tocItem.subitems, parent[i].subitems)
}
})
await Promise.all(promises)
}
return createTree(toc, tocTree).then(() => {
this.chapters = tocTree
})
},
flattenChapters(chapters) {
// Convert the nested epub chapters into something that looks like audiobook chapters for player-ui
const unwrap = (chapters) => {
return chapters.reduce((acc, chapter) => {
return chapter.subitems ? [...acc, chapter, ...unwrap(chapter.subitems)] : [...acc, chapter]
}, [])
}
let flattenedChapters = unwrap(chapters)
flattenedChapters = flattenedChapters.sort((a, b) => a.start - b.start)
for (let i = 0; i < flattenedChapters.length; i++) {
flattenedChapters[i].id = i
if (i < flattenedChapters.length - 1) {
flattenedChapters[i].end = flattenedChapters[i + 1].start
} else {
flattenedChapters[i].end = 1
}
}
return flattenedChapters
},
resize() { resize() {
this.windowWidth = window.innerWidth this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight this.windowHeight = window.innerHeight
+70 -22
View File
@@ -26,9 +26,9 @@
<component v-if="componentName" ref="readerComponent" :is="componentName" :library-item="selectedLibraryItem" :player-open="!!streamLibraryItem" :keep-progress="keepProgress" :file-id="ebookFileId" @touchstart="touchstart" @touchend="touchend" @hook:mounted="readerMounted" /> <component v-if="componentName" ref="readerComponent" :is="componentName" :library-item="selectedLibraryItem" :player-open="!!streamLibraryItem" :keep-progress="keepProgress" :file-id="ebookFileId" @touchstart="touchstart" @touchend="touchend" @hook:mounted="readerMounted" />
<!-- TOC side nav --> <!-- TOC side nav -->
<div v-if="tocOpen" class="w-full h-full fixed inset-0 bg-black/20 z-20" @click.stop.prevent="toggleToC"></div> <div v-if="tocOpen" class="w-full h-full overflow-y-scroll absolute inset-0 bg-black/20 z-20" @click.stop.prevent="toggleToC"></div>
<div v-if="isEpub" class="w-96 h-full max-h-full absolute top-0 left-0 shadow-xl transition-transform z-30 group-data-[theme=dark]:bg-primary group-data-[theme=dark]:text-white group-data-[theme=light]:bg-white group-data-[theme=light]:text-black" :class="tocOpen ? 'translate-x-0' : '-translate-x-96'" @click.stop.prevent="toggleToC"> <div v-if="isEpub" class="w-96 h-full max-h-full absolute top-0 left-0 shadow-xl transition-transform z-30 group-data-[theme=dark]:bg-primary group-data-[theme=dark]:text-white group-data-[theme=light]:bg-white group-data-[theme=light]:text-black" :class="tocOpen ? 'translate-x-0' : '-translate-x-96'" @click.stop.prevent>
<div class="p-4 h-full"> <div class="flex flex-col p-4 h-full">
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<button @click.stop.prevent="toggleToC" type="button" aria-label="Close table of contents" class="inline-flex opacity-80 hover:opacity-100"> <button @click.stop.prevent="toggleToC" type="button" aria-label="Close table of contents" class="inline-flex opacity-80 hover:opacity-100">
<span class="material-icons text-2xl">arrow_back</span> <span class="material-icons text-2xl">arrow_back</span>
@@ -36,13 +36,28 @@
<p class="text-lg font-semibold ml-2">{{ $strings.HeaderTableOfContents }}</p> <p class="text-lg font-semibold ml-2">{{ $strings.HeaderTableOfContents }}</p>
</div> </div>
<div class="tocContent"> <form @submit.prevent="searchBook" @click.stop.prevent>
<ui-text-input clearable ref="input" @clear="searchBook" v-model="searchQuery" :placeholder="$strings.PlaceholderSearch" class="h-8 w-full text-sm flex mb-2" />
</form>
<div class="overflow-y-auto">
<div v-if="isSearching && !this.searchResults.length" class="w-full h-40 justify-center">
<p class="text-center text-xl py-4">{{ $strings.MessageNoResults }}</p>
</div>
<ul> <ul>
<li v-for="chapter in chapters" :key="chapter.id" class="py-1"> <li v-for="chapter in isSearching ? this.searchResults : chapters" :key="chapter.id" class="py-1">
<a :href="chapter.href" class="opacity-80 hover:opacity-100" @click.prevent="$refs.readerComponent.goToChapter(chapter.href)">{{ chapter.label }}</a> <a :href="chapter.href" class="opacity-80 hover:opacity-100" @click.prevent="goToChapter(chapter.href)">{{ chapter.title }}</a>
<div v-for="searchResults in chapter.searchResults" :key="searchResults.cfi" class="text-sm py-1 pl-4">
<a :href="searchResults.cfi" class="opacity-50 hover:opacity-100" @click.prevent="goToChapter(searchResults.cfi)">{{ searchResults.excerpt }}</a>
</div>
<ul v-if="chapter.subitems.length"> <ul v-if="chapter.subitems.length">
<li v-for="subchapter in chapter.subitems" :key="subchapter.id" class="py-1 pl-4"> <li v-for="subchapter in chapter.subitems" :key="subchapter.id" class="py-1 pl-4">
<a :href="subchapter.href" class="opacity-80 hover:opacity-100" @click.prevent="$refs.readerComponent.goToChapter(subchapter.href)">{{ subchapter.label }}</a> <a :href="subchapter.href" class="opacity-80 hover:opacity-100" @click.prevent="goToChapter(subchapter.href)">{{ subchapter.title }}</a>
<div v-for="subChapterSearchResults in subchapter.searchResults" :key="subChapterSearchResults.cfi" class="text-sm py-1 pl-4">
<a :href="subChapterSearchResults.cfi" class="opacity-50 hover:opacity-100" @click.prevent="goToChapter(subChapterSearchResults.cfi)">{{ subChapterSearchResults.excerpt }}</a>
</div>
</li> </li>
</ul> </ul>
</li> </li>
@@ -63,7 +78,13 @@
<div class="w-40"> <div class="w-40">
<p class="text-lg">{{ $strings.LabelTheme }}:</p> <p class="text-lg">{{ $strings.LabelTheme }}:</p>
</div> </div>
<ui-toggle-btns v-model="ereaderSettings.theme" :items="themeItems" @input="settingsUpdated" /> <ui-toggle-btns v-model="ereaderSettings.theme" :items="themeItems.theme" @input="settingsUpdated" />
</div>
<div class="flex items-center mb-4">
<div class="w-40">
<p class="text-lg">{{ $strings.LabelFontFamily }}:</p>
</div>
<ui-toggle-btns v-model="ereaderSettings.font" :items="themeItems.font" @input="settingsUpdated" />
</div> </div>
<div class="flex items-center mb-4"> <div class="flex items-center mb-4">
<div class="w-40"> <div class="w-40">
@@ -99,10 +120,14 @@ export default {
touchstartTime: 0, touchstartTime: 0,
touchIdentifier: null, touchIdentifier: null,
chapters: [], chapters: [],
isSearching: false,
searchResults: [],
searchQuery: '',
tocOpen: false, tocOpen: false,
showSettings: false, showSettings: false,
ereaderSettings: { ereaderSettings: {
theme: 'dark', theme: 'dark',
font: 'serif',
fontScale: 100, fontScale: 100,
lineSpacing: 115, lineSpacing: 115,
spread: 'auto' spread: 'auto'
@@ -142,16 +167,28 @@ export default {
] ]
}, },
themeItems() { themeItems() {
return [ return {
{ theme: [
text: this.$strings.LabelThemeDark, {
value: 'dark' text: this.$strings.LabelThemeDark,
}, value: 'dark'
{ },
text: this.$strings.LabelThemeLight, {
value: 'light' text: this.$strings.LabelThemeLight,
} value: 'light'
] }
],
font: [
{
text: 'Sans',
value: 'sans-serif'
},
{
text: 'Serif',
value: 'serif'
}
]
}
}, },
componentName() { componentName() {
if (this.ebookType === 'epub') return 'readers-epub-reader' if (this.ebookType === 'epub') return 'readers-epub-reader'
@@ -235,6 +272,10 @@ export default {
} }
}, },
methods: { methods: {
goToChapter(uri) {
this.toggleToC()
this.$refs.readerComponent.goToChapter(uri)
},
readerMounted() { readerMounted() {
if (this.isEpub) { if (this.isEpub) {
this.loadEreaderSettings() this.loadEreaderSettings()
@@ -262,6 +303,15 @@ export default {
this.close() this.close()
} }
}, },
async searchBook() {
if (this.searchQuery.length > 1) {
this.searchResults = await this.$refs.readerComponent.searchBook(this.searchQuery)
this.isSearching = true
} else {
this.isSearching = false
this.searchResults = []
}
},
next() { next() {
if (this.$refs.readerComponent?.next) this.$refs.readerComponent.next() if (this.$refs.readerComponent?.next) this.$refs.readerComponent.next()
}, },
@@ -340,6 +390,8 @@ export default {
}, },
close() { close() {
this.unregisterListeners() this.unregisterListeners()
this.isSearching = false
this.searchQuery = ''
this.show = false this.show = false
} }
}, },
@@ -353,10 +405,6 @@ export default {
</script> </script>
<style> <style>
.tocContent {
height: calc(100% - 36px);
overflow-y: auto;
}
#reader { #reader {
height: 100%; height: 100%;
} }
+12 -6
View File
@@ -18,7 +18,7 @@
</div> </div>
</div> </div>
<div class="flex px-4"> <div v-if="isBookLibrary" class="flex px-4">
<svg class="h-14 w-14 md:h-18 md:w-18" viewBox="0 0 24 24"> <svg class="h-14 w-14 md:h-18 md:w-18" viewBox="0 0 24 24">
<path fill="currentColor" d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9.03,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 14.97,14.9 12,14.9Z" /> <path fill="currentColor" d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,6A2,2 0 0,0 10,8A2,2 0 0,0 12,10A2,2 0 0,0 14,8A2,2 0 0,0 12,6M12,13C14.67,13 20,14.33 20,17V20H4V17C4,14.33 9.33,13 12,13M12,14.9C9.03,14.9 5.9,16.36 5.9,17V18.1H18.1V17C18.1,16.36 14.97,14.9 12,14.9Z" />
</svg> </svg>
@@ -58,26 +58,32 @@ export default {
return {} return {}
}, },
computed: { computed: {
currentLibraryMediaType() {
return this.$store.getters['libraries/getCurrentLibraryMediaType']
},
isBookLibrary() {
return this.currentLibraryMediaType === 'book'
},
user() { user() {
return this.$store.state.user.user return this.$store.state.user.user
}, },
totalItems() { totalItems() {
return this.libraryStats ? this.libraryStats.totalItems : 0 return this.libraryStats?.totalItems || 0
}, },
totalAuthors() { totalAuthors() {
return this.libraryStats ? this.libraryStats.totalAuthors : 0 return this.libraryStats?.totalAuthors || 0
}, },
numAudioTracks() { numAudioTracks() {
return this.libraryStats ? this.libraryStats.numAudioTracks : 0 return this.libraryStats?.numAudioTracks || 0
}, },
totalDuration() { totalDuration() {
return this.libraryStats ? this.libraryStats.totalDuration : 0 return this.libraryStats?.totalDuration || 0
}, },
totalHours() { totalHours() {
return Math.round(this.totalDuration / (60 * 60)) return Math.round(this.totalDuration / (60 * 60))
}, },
totalSizePretty() { totalSizePretty() {
var totalSize = this.libraryStats ? this.libraryStats.totalSize : 0 var totalSize = this.libraryStats?.totalSize || 0
return this.$bytesPretty(totalSize, 1) return this.$bytesPretty(totalSize, 1)
}, },
totalSizeNum() { totalSizeNum() {
@@ -164,6 +164,7 @@ export default {
this.$axios this.$axios
.$get('/api/backups') .$get('/api/backups')
.then((data) => { .then((data) => {
this.$emit('loaded', data.backupLocation)
this.setBackups(data.backups || []) this.setBackups(data.backups || [])
}) })
.catch((error) => { .catch((error) => {
+10 -2
View File
@@ -6,7 +6,7 @@
<span class="text-sm font-mono">{{ ebookFiles.length }}</span> <span class="text-sm font-mono">{{ ebookFiles.length }}</span>
</div> </div>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn> <ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="toggleFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
<div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''"> <div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''">
<span class="material-icons text-4xl">expand_more</span> <span class="material-icons text-4xl">expand_more</span>
</div> </div>
@@ -75,6 +75,10 @@ export default {
} }
}, },
methods: { methods: {
toggleFullPath() {
this.showFullPath = !this.showFullPath
localStorage.setItem('showFullPath', this.showFullPath ? 1 : 0)
},
readEbook(fileIno) { readEbook(fileIno) {
this.$store.commit('showEReader', { libraryItem: this.libraryItem, keepProgress: false, fileId: fileIno }) this.$store.commit('showEReader', { libraryItem: this.libraryItem, keepProgress: false, fileId: fileIno })
}, },
@@ -82,6 +86,10 @@ export default {
this.showFiles = !this.showFiles this.showFiles = !this.showFiles
} }
}, },
mounted() {} mounted() {
if (this.userIsAdmin) {
this.showFullPath = !!Number(localStorage.getItem('showFullPath') || 0)
}
}
} }
</script> </script>
@@ -6,7 +6,7 @@
<span class="text-sm font-mono">{{ files.length }}</span> <span class="text-sm font-mono">{{ files.length }}</span>
</div> </div>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn> <ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="toggleFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
<div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''"> <div class="cursor-pointer h-10 w-10 rounded-full hover:bg-black-400 flex justify-center items-center duration-500" :class="showFiles ? 'transform rotate-180' : ''">
<span class="material-icons text-4xl">expand_more</span> <span class="material-icons text-4xl">expand_more</span>
</div> </div>
@@ -84,6 +84,10 @@ export default {
} }
}, },
methods: { methods: {
toggleFullPath() {
this.showFullPath = !this.showFullPath
localStorage.setItem('showFullPath', this.showFullPath ? 1 : 0)
},
clickBar() { clickBar() {
this.showFiles = !this.showFiles this.showFiles = !this.showFiles
}, },
@@ -93,6 +97,9 @@ export default {
} }
}, },
mounted() { mounted() {
if (this.userIsAdmin) {
this.showFullPath = !!Number(localStorage.getItem('showFullPath') || 0)
}
this.showFiles = this.expanded this.showFiles = this.expanded
} }
} }
+10 -2
View File
@@ -6,7 +6,7 @@
<span class="text-sm font-mono">{{ tracks.length }}</span> <span class="text-sm font-mono">{{ tracks.length }}</span>
</div> </div>
<div class="flex-grow" /> <div class="flex-grow" />
<ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="showFullPath = !showFullPath">{{ $strings.ButtonFullPath }}</ui-btn> <ui-btn v-if="userIsAdmin" small :color="showFullPath ? 'gray-600' : 'primary'" class="mr-2 hidden md:block" @click.stop="toggleFullPath">{{ $strings.ButtonFullPath }}</ui-btn>
<nuxt-link v-if="userCanUpdate && !isFile" :to="`/audiobook/${libraryItemId}/edit`" class="mr-2 md:mr-4" @mousedown.prevent> <nuxt-link v-if="userCanUpdate && !isFile" :to="`/audiobook/${libraryItemId}/edit`" class="mr-2 md:mr-4" @mousedown.prevent>
<ui-btn small color="primary">{{ $strings.ButtonManageTracks }}</ui-btn> <ui-btn small color="primary">{{ $strings.ButtonManageTracks }}</ui-btn>
</nuxt-link> </nuxt-link>
@@ -74,6 +74,10 @@ export default {
} }
}, },
methods: { methods: {
toggleFullPath() {
this.showFullPath = !this.showFullPath
localStorage.setItem('showFullPath', this.showFullPath ? 1 : 0)
},
clickBar() { clickBar() {
this.showTracks = !this.showTracks this.showTracks = !this.showTracks
}, },
@@ -82,6 +86,10 @@ export default {
this.showAudioFileDataModal = true this.showAudioFileDataModal = true
} }
}, },
mounted() {} mounted() {
if (this.userIsAdmin) {
this.showFullPath = !!Number(localStorage.getItem('showFullPath') || 0)
}
}
} }
</script> </script>
+1 -11
View File
@@ -52,8 +52,6 @@
</tr> </tr>
</table> </table>
</div> </div>
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
</div> </div>
</template> </template>
@@ -62,8 +60,6 @@ export default {
data() { data() {
return { return {
users: [], users: [],
selectedAccount: null,
showAccountModal: false,
isDeletingUser: false isDeletingUser: false
} }
}, },
@@ -114,13 +110,8 @@ export default {
}) })
} }
}, },
clickAddUser() {
this.selectedAccount = null
this.showAccountModal = true
},
editUser(user) { editUser(user) {
this.selectedAccount = user this.$emit('edit', user)
this.showAccountModal = true
}, },
loadUsers() { loadUsers() {
this.$axios this.$axios
@@ -129,7 +120,6 @@ export default {
this.users = res.users.sort((a, b) => { this.users = res.users.sort((a, b) => {
return a.createdAt - b.createdAt return a.createdAt - b.createdAt
}) })
console.log('Loaded users', this.users)
}) })
.catch((error) => { .catch((error) => {
console.error('Failed', error) console.error('Failed', error)
@@ -26,11 +26,11 @@
</div> </div>
<div class="truncate max-w-48 md:max-w-md text-xs md:text-sm text-gray-300"> <div class="truncate max-w-48 md:max-w-md text-xs md:text-sm text-gray-300">
<template v-for="(author, index) in bookAuthors"> <template v-for="(author, index) in bookAuthors">
<nuxt-link :key="author.id" :to="`/author/${author.id}?library=${book.libraryId}`" class="truncate hover:underline">{{ author.name }}</nuxt-link <nuxt-link :key="author.id" :to="`/author/${author.id}`" class="truncate hover:underline">{{ author.name }}</nuxt-link
><span :key="author.id + '-comma'" v-if="index < bookAuthors.length - 1">,&nbsp;</span> ><span :key="author.id + '-comma'" v-if="index < bookAuthors.length - 1">,&nbsp;</span>
</template> </template>
</div> </div>
<p class="text-xs md:text-sm text-gray-400">{{ bookDuration }}</p> <p v-if="media.duration" class="text-xs md:text-sm text-gray-400">{{ bookDuration }}</p>
</div> </div>
</div> </div>
</div> </div>
@@ -11,10 +11,6 @@
<ui-btn @click="clickAddLibrary">{{ $strings.ButtonAddYourFirstLibrary }}</ui-btn> <ui-btn @click="clickAddLibrary">{{ $strings.ButtonAddYourFirstLibrary }}</ui-btn>
</div> </div>
<p v-if="libraries.length" class="text-xs mt-4 text-gray-200">
*<strong>{{ $strings.ButtonForceReScan }}</strong> {{ $strings.MessageForceReScanDescription }}
</p>
<p v-if="libraries.length && libraries.some((li) => li.mediaType === 'book')" class="text-xs mt-4 text-gray-200"> <p v-if="libraries.length && libraries.some((li) => li.mediaType === 'book')" class="text-xs mt-4 text-gray-200">
**<strong>{{ $strings.ButtonMatchBooks }}</strong> {{ $strings.MessageMatchBooksDescription }} **<strong>{{ $strings.ButtonMatchBooks }}</strong> {{ $strings.MessageMatchBooksDescription }}
</p> </p>
@@ -46,13 +42,10 @@ export default {
return this.$store.getters['libraries/getCurrentLibrary'] return this.$store.getters['libraries/getCurrentLibrary']
}, },
currentLibraryId() { currentLibraryId() {
return this.currentLibrary ? this.currentLibrary.id : null return this.currentLibrary?.id || null
}, },
libraries() { libraries() {
return this.$store.getters['libraries/getSortedLibraries']() return this.$store.getters['libraries/getSortedLibraries']()
},
libraryScans() {
return this.$store.state.scanners.libraryScans
} }
}, },
methods: { methods: {
@@ -1,7 +1,7 @@
<template> <template>
<div class="w-full pl-2 pr-4 md:px-4 h-12 border border-white border-opacity-10 flex items-center relative -mt-px" :class="selected ? 'bg-primary bg-opacity-50' : 'hover:bg-primary hover:bg-opacity-25'" @mouseover="mouseover = true" @mouseleave="mouseover = false"> <div class="w-full pl-2 pr-4 md:px-4 h-12 border border-white border-opacity-10 flex items-center relative -mt-px" :class="selected ? 'bg-primary bg-opacity-50' : 'hover:bg-primary hover:bg-opacity-25'" @mouseover="mouseover = true" @mouseleave="mouseover = false">
<div v-show="selected" class="absolute top-0 left-0 h-full w-0.5 bg-warning z-10" /> <div v-show="selected" class="absolute top-0 left-0 h-full w-0.5 bg-warning z-10" />
<ui-library-icon v-if="!libraryScan" :icon="library.icon" :size="6" font-size="lg md:text-xl" class="text-white" :class="isHovering ? 'text-opacity-90' : 'text-opacity-50'" /> <ui-library-icon v-if="!isScanning" :icon="library.icon" :size="6" font-size="lg md:text-xl" class="text-white" :class="isHovering ? 'text-opacity-90' : 'text-opacity-50'" />
<svg v-else viewBox="0 0 24 24" class="h-6 w-6 text-white text-opacity-50 animate-spin"> <svg v-else viewBox="0 0 24 24" class="h-6 w-6 text-white text-opacity-50 animate-spin">
<path fill="currentColor" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" /> <path fill="currentColor" d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z" />
</svg> </svg>
@@ -9,11 +9,14 @@
<div class="flex-grow" /> <div class="flex-grow" />
<!-- Scan button only shown on desktop -->
<ui-btn v-if="!isScanning && !isDeleting" color="bg" class="hidden md:block mx-2 text-xs" :padding-y="1" :padding-x="3" @click.stop="scanBtnClick">{{ this.$strings.ButtonScan }}</ui-btn>
<!-- Desktop context menu icon --> <!-- Desktop context menu icon -->
<ui-context-menu-dropdown v-if="!libraryScan && !isDeleting" :items="contextMenuItems" :icon-class="`text-1.5xl text-gray-${isHovering ? 50 : 400}`" class="!hidden md:!block" @action="contextMenuAction" /> <ui-context-menu-dropdown v-if="!isScanning && !isDeleting" :items="contextMenuItems" :icon-class="`text-1.5xl text-gray-${isHovering ? 50 : 400}`" class="!hidden md:!block" @action="contextMenuAction" />
<!-- Mobile context menu icon --> <!-- Mobile context menu icon -->
<span v-if="!libraryScan && !isDeleting" class="!block md:!hidden material-icons text-xl text-gray-300 ml-3 cursor-pointer" @click.stop="showMenu">more_vert</span> <span v-if="!isScanning && !isDeleting" class="!block md:!hidden material-icons text-xl text-gray-300 ml-3 cursor-pointer" @click.stop="showMenu">more_vert</span>
<div v-show="isDeleting" class="text-xl text-gray-300 ml-3 animate-spin"> <div v-show="isDeleting" class="text-xl text-gray-300 ml-3 animate-spin">
<svg viewBox="0 0 24 24" class="w-6 h-6"> <svg viewBox="0 0 24 24" class="w-6 h-6">
@@ -48,8 +51,8 @@ export default {
isHovering() { isHovering() {
return this.mouseover && !this.dragging return this.mouseover && !this.dragging
}, },
libraryScan() { isScanning() {
return this.$store.getters['scanners/getLibraryScan'](this.library.id) return !!this.$store.getters['tasks/getRunningLibraryScanTask'](this.library.id)
}, },
mediaType() { mediaType() {
return this.library.mediaType return this.library.mediaType
@@ -71,11 +74,6 @@ export default {
text: this.$strings.ButtonScan, text: this.$strings.ButtonScan,
action: 'scan', action: 'scan',
value: 'scan' value: 'scan'
},
{
text: this.$strings.ButtonForceReScan,
action: 'force-scan',
value: 'force-scan'
} }
] ]
if (this.isBookLibrary) { if (this.isBookLibrary) {
@@ -94,14 +92,17 @@ export default {
} }
}, },
methods: { methods: {
scanBtnClick() {
this.scan()
},
contextMenuAction({ action }) { contextMenuAction({ action }) {
this.showMobileMenu = false this.showMobileMenu = false
if (action === 'edit') { if (action === 'edit') {
this.editClick() this.editClick()
} else if (action === 'scan') { } else if (action === 'scan') {
this.scan() this.scan()
} else if (action === 'force-scan') { } else if (action === 'force-rescan') {
this.forceScan() this.scan(true)
} else if (action === 'match-books') { } else if (action === 'match-books') {
this.matchAll() this.matchAll()
} else if (action === 'delete') { } else if (action === 'delete') {
@@ -126,37 +127,17 @@ export default {
editClick() { editClick() {
this.$emit('edit', this.library) this.$emit('edit', this.library)
}, },
scan() { scan(force = false) {
this.$store this.$store
.dispatch('libraries/requestLibraryScan', { libraryId: this.library.id }) .dispatch('libraries/requestLibraryScan', { libraryId: this.library.id, force })
.then(() => { .then(() => {
this.$toast.success(this.$strings.ToastLibraryScanStarted) // this.$toast.success(this.$strings.ToastLibraryScanStarted)
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to start scan', error) console.error('Failed to start scan', error)
this.$toast.error(this.$strings.ToastLibraryScanFailedToStart) this.$toast.error(this.$strings.ToastLibraryScanFailedToStart)
}) })
}, },
forceScan() {
const payload = {
message: this.$strings.MessageConfirmForceReScan,
callback: (confirmed) => {
if (confirmed) {
this.$store
.dispatch('libraries/requestLibraryScan', { libraryId: this.library.id, force: 1 })
.then(() => {
this.$toast.success(this.$strings.ToastLibraryScanStarted)
})
.catch((error) => {
console.error('Failed to start scan', error)
this.$toast.error(this.$strings.ToastLibraryScanFailedToStart)
})
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
},
deleteClick() { deleteClick() {
const payload = { const payload = {
message: this.$getString('MessageConfirmDeleteLibrary', [this.library.name]), message: this.$getString('MessageConfirmDeleteLibrary', [this.library.name]),
@@ -21,7 +21,7 @@
</div> </div>
<div class="truncate max-w-48 md:max-w-md text-xs md:text-sm text-gray-300"> <div class="truncate max-w-48 md:max-w-md text-xs md:text-sm text-gray-300">
<template v-for="(author, index) in bookAuthors"> <template v-for="(author, index) in bookAuthors">
<nuxt-link :key="author.id" :to="`/author/${author.id}?library=${libraryItem.libraryId}`" class="truncate hover:underline">{{ author.name }}</nuxt-link <nuxt-link :key="author.id" :to="`/author/${author.id}`" class="truncate hover:underline">{{ author.name }}</nuxt-link
><span :key="author.id + '-comma'" v-if="index < bookAuthors.length - 1">,&nbsp;</span> ><span :key="author.id + '-comma'" v-if="index < bookAuthors.length - 1">,&nbsp;</span>
</template> </template>
<nuxt-link v-if="episode" :to="`/item/${libraryItem.id}`" class="truncate hover:underline">{{ mediaMetadata.title }}</nuxt-link> <nuxt-link v-if="episode" :to="`/item/${libraryItem.id}`" class="truncate hover:underline">{{ mediaMetadata.title }}</nuxt-link>
@@ -191,6 +191,7 @@ export default {
} }
}, },
methods: { methods: {
submit() {},
inputUpdate() { inputUpdate() {
clearTimeout(this.searchTimeout) clearTimeout(this.searchTimeout)
this.searchTimeout = setTimeout(() => { this.searchTimeout = setTimeout(() => {
+2 -22
View File
@@ -1,5 +1,5 @@
<template> <template>
<nuxt-link v-if="to" :to="to" class="btn outline-none rounded-md shadow-md relative border border-gray-600 text-center" :disabled="disabled || loading" :class="classList"> <nuxt-link v-if="to" :to="to" class="abs-btn outline-none rounded-md shadow-md relative border border-gray-600 text-center" :disabled="disabled || loading" :class="classList">
<slot /> <slot />
<div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100"> <div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100">
<svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24"> <svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24">
@@ -7,7 +7,7 @@
</svg> </svg>
</div> </div>
</nuxt-link> </nuxt-link>
<button v-else class="btn outline-none rounded-md shadow-md relative border border-gray-600" :disabled="disabled || loading" :type="type" :class="classList" @mousedown.prevent @click="click"> <button v-else class="abs-btn outline-none rounded-md shadow-md relative border border-gray-600" :disabled="disabled || loading" :type="type" :class="classList" @mousedown.prevent @click="click">
<slot /> <slot />
<div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100"> <div v-if="loading" class="text-white absolute top-0 left-0 w-full h-full flex items-center justify-center text-opacity-100">
<svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24"> <svg class="animate-spin" style="width: 24px; height: 24px" viewBox="0 0 24 24">
@@ -72,23 +72,3 @@ export default {
mounted() {} mounted() {}
} }
</script> </script>
<style scoped>
.btn::before {
content: '';
position: absolute;
border-radius: 6px;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0);
transition: all 0.1s ease-in-out;
}
.btn:hover:not(:disabled)::before {
background-color: rgba(255, 255, 255, 0.1);
}
button:disabled::before {
background-color: rgba(0, 0, 0, 0.2);
}
</style>
+1 -1
View File
@@ -13,7 +13,7 @@
</button> </button>
<transition name="menu"> <transition name="menu">
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full bg-primary border border-black-200 shadow-lg max-h-56 rounded-b-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto sm:text-sm" tabindex="-1" role="listbox"> <ul v-show="showMenu" class="absolute z-10 -mt-px w-full bg-primary border border-black-200 shadow-lg max-h-56 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto sm:text-sm" tabindex="-1" role="listbox">
<template v-for="item in itemsToShow"> <template v-for="item in itemsToShow">
<li :key="item.value" class="text-gray-100 relative py-2 cursor-pointer hover:bg-black-400" :id="'listbox-option-' + item.value" role="option" tabindex="0" @keyup.enter="clickedOption(item.value)" @click="clickedOption(item.value)"> <li :key="item.value" class="text-gray-100 relative py-2 cursor-pointer hover:bg-black-400" :id="'listbox-option-' + item.value" role="option" tabindex="0" @keyup.enter="clickedOption(item.value)" @click="clickedOption(item.value)">
<div class="flex items-center"> <div class="flex items-center">
+1 -11
View File
@@ -4,7 +4,7 @@
<div ref="wrapper" class="relative"> <div ref="wrapper" class="relative">
<form @submit.prevent="submitForm"> <form @submit.prevent="submitForm">
<div ref="inputWrapper" class="input-wrapper flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-2" :class="disabled ? 'pointer-events-none bg-black-300 text-gray-400' : 'bg-primary'"> <div ref="inputWrapper" class="input-wrapper flex-wrap relative w-full shadow-sm flex items-center border border-gray-600 rounded px-2 py-2" :class="disabled ? 'pointer-events-none bg-black-300 text-gray-400' : 'bg-primary'">
<input ref="input" v-model="textInput" :disabled="disabled" :readonly="!editable" class="h-full w-full bg-transparent focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" /> <input ref="input" v-model="textInput" :disabled="disabled" :readonly="!editable" class="h-full w-full bg-transparent focus:outline-none px-1" @focus="inputFocus" @blur="inputBlur" />
</div> </div>
</form> </form>
@@ -48,8 +48,6 @@ export default {
data() { data() {
return { return {
isFocused: false, isFocused: false,
// currentSearch: null,
typingTimeout: null,
textInput: null textInput: null
} }
}, },
@@ -83,12 +81,6 @@ export default {
} }
}, },
methods: { methods: {
keydownInput() {
clearTimeout(this.typingTimeout)
this.typingTimeout = setTimeout(() => {
// this.currentSearch = this.textInput
}, 100)
},
setFocus() { setFocus() {
if (this.$refs.input && this.editable) this.$refs.input.focus() if (this.$refs.input && this.editable) this.$refs.input.focus()
}, },
@@ -133,11 +125,9 @@ export default {
if (val && !this.items.includes(val)) { if (val && !this.items.includes(val)) {
this.$emit('newItem', val) this.$emit('newItem', val)
} }
// this.currentSearch = null
}, },
clickedOption(e, item) { clickedOption(e, item) {
this.textInput = null this.textInput = null
// this.currentSearch = null
this.input = item this.input = item
if (this.$refs.input) this.$refs.input.blur() if (this.$refs.input) this.$refs.input.blur()
} }
+26 -1
View File
@@ -11,7 +11,7 @@
</div> </div>
{{ item }} {{ item }}
</div> </div>
<input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" style="min-width: 40px; width: 40px" class="h-full bg-primary focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" /> <input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" style="min-width: 40px; width: 40px" class="h-full bg-primary focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
</div> </div>
</form> </form>
@@ -145,6 +145,31 @@ export default {
this.menu.style.left = boundingBox.x + 'px' this.menu.style.left = boundingBox.x + 'px'
this.menu.style.width = boundingBox.width + 'px' this.menu.style.width = boundingBox.width + 'px'
}, },
inputPaste(evt) {
setTimeout(() => {
const pastedText = evt.target?.value || ''
console.log('Pasted text=', pastedText)
const pastedItems = [
...new Set(
pastedText
.split(';')
.map((i) => i.trim())
.filter((i) => i)
)
]
// Filter out items already selected
const itemsToAdd = pastedItems.filter((i) => !this.selected.some((_i) => _i.toLowerCase() === i.toLowerCase()))
if (pastedItems.length && !itemsToAdd.length) {
this.textInput = null
this.currentSearch = null
} else {
for (const itemToAdd of itemsToAdd) {
this.insertNewItem(itemToAdd)
}
}
}, 10)
},
inputFocus() { inputFocus() {
if (!this.menu) { if (!this.menu) {
this.unmountMountMenu() this.unmountMountMenu()
+23 -17
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="w-full" v-click-outside="closeMenu"> <div class="w-full" v-click-outside="clickOutsideObj">
<p class="px-1 text-sm font-semibold">{{ label }}</p> <p class="px-1 text-sm font-semibold">{{ label }}</p>
<div ref="wrapper" class="relative"> <div ref="wrapper" class="relative">
<div ref="inputWrapper" style="min-height: 40px" class="flex-wrap relative w-full shadow-sm flex items-center bg-primary border border-gray-600 rounded-md px-2 py-1 cursor-pointer" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent> <div ref="inputWrapper" style="min-height: 40px" class="flex-wrap relative w-full shadow-sm flex items-center bg-primary border border-gray-600 rounded-md px-2 py-1 cursor-pointer" @click.stop.prevent="clickWrapper" @mouseup.stop.prevent @mousedown.prevent>
@@ -11,23 +11,24 @@
</div> </div>
</div> </div>
<ul ref="menu" v-show="showMenu" class="absolute z-60 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm" role="listbox" aria-labelledby="listbox-label"> <transition name="menu">
<template v-for="item in items"> <ul ref="menu" v-show="showMenu" class="absolute z-60 -mt-px w-full bg-primary border border-black-200 shadow-lg max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm" role="listbox" aria-labelledby="listbox-label">
<li :key="item.value" class="text-gray-50 select-none relative py-2 pr-9 cursor-pointer hover:bg-black-400" role="option" @click="clickedOption($event, item)" @mouseup.stop.prevent @mousedown.prevent> <template v-for="item in items">
<div class="flex items-center"> <li :key="item.value" class="text-gray-50 select-none relative py-2 pr-9 cursor-pointer hover:bg-black-400" role="option" @click="clickedOption($event, item)" @mouseup.stop.prevent @mousedown.prevent>
<span class="font-normal ml-3 block truncate">{{ item.text }}</span> <p class="font-normal ml-3 block truncate">{{ item.text }}</p>
<div v-if="selected.includes(item.value)" class="text-yellow-400 absolute inset-y-0 right-0 my-auto w-5 h-5 mr-3 overflow-hidden">
<span class="material-icons text-xl">checkmark</span>
</div>
</li>
</template>
<li v-if="!items.length" class="text-gray-50 select-none relative py-2 pr-9" role="option">
<div class="flex items-center justify-center">
<span class="font-normal">{{ $strings.MessageNoItems }}</span>
</div> </div>
<span v-if="selected.includes(item.value)" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
<span class="material-icons text-xl">checkmark</span>
</span>
</li> </li>
</template> </ul>
<li v-if="!items.length" class="text-gray-50 select-none relative py-2 pr-9" role="option"> </transition>
<div class="flex items-center justify-center">
<span class="font-normal">{{ $strings.MessageNoItems }}</span>
</div>
</li>
</ul>
</div> </div>
</div> </div>
</template> </template>
@@ -48,7 +49,12 @@ export default {
data() { data() {
return { return {
showMenu: false, showMenu: false,
menu: null menu: null,
clickOutsideObj: {
handler: this.closeMenu,
events: ['mousedown'],
isActive: true
}
} }
}, },
computed: { computed: {
+40 -14
View File
@@ -14,7 +14,7 @@
<div v-if="showEdit && !disabled" class="rounded-full cursor-pointer w-6 h-6 mx-0.5 bg-bg flex items-center justify-center"> <div v-if="showEdit && !disabled" class="rounded-full cursor-pointer w-6 h-6 mx-0.5 bg-bg flex items-center justify-center">
<span class="material-icons text-white hover:text-success pt-px pr-px" style="font-size: 1.1rem" @click.stop="addItem">add</span> <span class="material-icons text-white hover:text-success pt-px pr-px" style="font-size: 1.1rem" @click.stop="addItem">add</span>
</div> </div>
<input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" style="min-width: 40px; width: 40px" class="h-full bg-primary focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" /> <input v-show="!readonly" ref="input" v-model="textInput" :disabled="disabled" style="min-width: 40px; width: 40px" class="h-full bg-primary focus:outline-none px-1" @keydown="keydownInput" @focus="inputFocus" @blur="inputBlur" @paste="inputPaste" />
</div> </div>
</form> </form>
@@ -46,7 +46,7 @@ export default {
type: Array, type: Array,
default: () => [] default: () => []
}, },
endpoint: String, filterKey: String,
label: String, label: String,
disabled: Boolean, disabled: Boolean,
readonly: Boolean, readonly: Boolean,
@@ -60,7 +60,6 @@ export default {
return { return {
textInput: null, textInput: null,
currentSearch: null, currentSearch: null,
searching: false,
typingTimeout: null, typingTimeout: null,
isFocused: false, isFocused: false,
menu: null, menu: null,
@@ -97,6 +96,9 @@ export default {
}, },
itemsToShow() { itemsToShow() {
return this.items return this.items
},
filterData() {
return this.$store.state.libraries.filterData || {}
} }
}, },
methods: { methods: {
@@ -109,20 +111,16 @@ export default {
getIsSelected(itemValue) { getIsSelected(itemValue) {
return !!this.selected.find((i) => i.id === itemValue) return !!this.selected.find((i) => i.id === itemValue)
}, },
async search() { search() {
if (this.searching) return if (!this.textInput) return
this.currentSearch = this.textInput this.currentSearch = this.textInput
this.searching = true const dataToSearch = this.filterData[this.filterKey] || []
const results = await this.$axios
.$get(`/api/${this.endpoint}?q=${this.currentSearch}&limit=15&token=${this.userToken}`) const results = dataToSearch.filter((au) => {
.then((res) => res.results || res) return au.name.toLowerCase().includes(this.currentSearch.toLowerCase().trim())
.catch((error) => { })
console.error('Failed to get search results', error)
return []
})
this.items = results || [] this.items = results || []
this.searching = false
}, },
keydownInput() { keydownInput() {
clearTimeout(this.typingTimeout) clearTimeout(this.typingTimeout)
@@ -168,6 +166,34 @@ export default {
this.menu.style.left = boundingBox.x + 'px' this.menu.style.left = boundingBox.x + 'px'
this.menu.style.width = boundingBox.width + 'px' this.menu.style.width = boundingBox.width + 'px'
}, },
inputPaste(evt) {
setTimeout(() => {
const pastedText = evt.target?.value || ''
console.log('Pasted text=', pastedText)
const pastedItems = [
...new Set(
pastedText
.split(';')
.map((i) => i.trim())
.filter((i) => i)
)
]
// Filter out items already selected
const itemsToAdd = pastedItems.filter((i) => !this.selected.some((_i) => _i[this.textKey].toLowerCase() === i.toLowerCase()))
if (pastedItems.length && !itemsToAdd.length) {
this.textInput = null
this.currentSearch = null
} else {
for (const [index, itemToAdd] of itemsToAdd.entries()) {
this.insertNewItem({
id: `new-${Date.now()}-${index}`,
name: itemToAdd
})
}
}
}, 10)
},
inputFocus() { inputFocus() {
if (!this.menu) { if (!this.menu) {
this.unmountMountMenu() this.unmountMountMenu()
+1
View File
@@ -68,6 +68,7 @@ export default {
methods: { methods: {
clear() { clear() {
this.inputValue = '' this.inputValue = ''
this.$emit('clear')
}, },
focused() { focused() {
this.isFocused = true this.isFocused = true
@@ -12,8 +12,8 @@
<div class="flex flex-wrap mt-2 -mx-1"> <div class="flex flex-wrap mt-2 -mx-1">
<div class="w-full md:w-3/4 px-1"> <div class="w-full md:w-3/4 px-1">
<!-- Authors filter only contains authors in this library, use query input to query all authors --> <!-- Authors filter only contains authors in this library, uses filter data -->
<ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" :label="$strings.LabelAuthors" endpoint="authors/search" /> <ui-multi-select-query-input ref="authorsSelect" v-model="details.authors" :label="$strings.LabelAuthors" filter-key="authors" />
</div> </div>
<div class="flex-grow px-1 mt-2 md:mt-0"> <div class="flex-grow px-1 mt-2 md:mt-0">
<ui-text-input-with-label ref="publishYearInput" v-model="details.publishedYear" type="number" :label="$strings.LabelPublishYear" /> <ui-text-input-with-label ref="publishYearInput" v-model="details.publishedYear" type="number" :label="$strings.LabelPublishYear" />
-33
View File
@@ -1,33 +0,0 @@
<template>
<button class="bg-error text-white px-2 py-1 shadow-md" @click="$emit('click', $event)">Cancel</button>
</template>
<script>
export default {
data() {
return {}
},
computed: {},
methods: {},
mounted() {}
}
</script>
<style>
.Vue-Toastification__close-button.cancel-scan-btn {
background-color: rgb(255, 82, 82);
color: white;
font-size: 0.9rem;
opacity: 1;
padding: 0px 10px;
border-radius: 6px;
font-weight: normal;
font-family: 'Open Sans';
margin-left: 10px;
opacity: 0.3;
}
.Vue-Toastification__close-button.cancel-scan-btn:hover {
background-color: rgb(235, 65, 65);
opacity: 1;
}
</style>
@@ -9,6 +9,8 @@
<span class="material-icons text-1.5xl" aria-label="Activities" role="button">notifications</span> <span class="material-icons text-1.5xl" aria-label="Activities" role="button">notifications</span>
</ui-tooltip> </ui-tooltip>
</div> </div>
<div v-if="showUnseenSuccessIndicator" class="w-2 h-2 rounded-full bg-success pointer-events-none absolute -top-1 -right-0.5" />
<div v-if="showUnseenSuccessIndicator" class="w-2 h-2 rounded-full bg-success/50 pointer-events-none absolute animate-ping -top-1 -right-0.5" />
</button> </button>
<transition name="menu"> <transition name="menu">
<div class="sm:w-80 w-full relative"> <div class="sm:w-80 w-full relative">
@@ -46,7 +48,8 @@ export default {
isActive: true isActive: true
}, },
showMenu: false, showMenu: false,
disabled: false disabled: false,
tasksSeen: []
} }
}, },
computed: { computed: {
@@ -60,12 +63,20 @@ export default {
// return just the tasks that are running or failed (or show success) in the last 1 minute // return just the tasks that are running or failed (or show success) in the last 1 minute
const tasks = this.tasks.filter((t) => !t.isFinished || ((t.isFailed || t.showSuccess) && t.finishedAt > new Date().getTime() - 1000 * 60)) || [] const tasks = this.tasks.filter((t) => !t.isFinished || ((t.isFailed || t.showSuccess) && t.finishedAt > new Date().getTime() - 1000 * 60)) || []
return tasks.sort((a, b) => b.startedAt - a.startedAt) return tasks.sort((a, b) => b.startedAt - a.startedAt)
},
showUnseenSuccessIndicator() {
return this.tasksToShow.some((t) => t.isFinished && !t.isFailed && !this.tasksSeen.includes(t.id))
} }
}, },
methods: { methods: {
clickShowMenu() { clickShowMenu() {
if (this.disabled) return if (this.disabled) return
this.showMenu = !this.showMenu this.showMenu = !this.showMenu
if (this.showMenu) {
this.tasksToShow.forEach((t) => {
if (!this.tasksSeen.includes(t.id)) this.tasksSeen.push(t.id)
})
}
}, },
clickedOutside() { clickedOutside() {
this.showMenu = false this.showMenu = false
@@ -83,9 +94,20 @@ export default {
default: default:
return '' return ''
} }
},
taskFinished(task) {
// add task as seen if menu is open when it finished
if (this.showMenu && !this.tasksSeen.includes(task.id)) {
this.tasksSeen.push(task.id)
}
} }
}, },
mounted() {} mounted() {
this.$root.socket?.on('task_finished', this.taskFinished)
},
beforeDestroy() {
this.$root.socket?.off('task_finished', this.taskFinished)
}
} }
</script> </script>
+8 -67
View File
@@ -19,14 +19,13 @@
<modals-authors-edit-modal /> <modals-authors-edit-modal />
<modals-batch-quick-match-model /> <modals-batch-quick-match-model />
<modals-rssfeed-open-close-modal /> <modals-rssfeed-open-close-modal />
<modals-raw-cover-preview-modal />
<prompt-confirm /> <prompt-confirm />
<readers-reader /> <readers-reader />
</div> </div>
</template> </template>
<script> <script>
import CloseButton from '@/components/widgets/CloseButton'
export default { export default {
middleware: 'authenticated', middleware: 'authenticated',
data() { data() {
@@ -123,22 +122,6 @@ export default {
init(payload) { init(payload) {
console.log('Init Payload', payload) console.log('Init Payload', payload)
// Start scans currently running
if (payload.librariesScanning) {
payload.librariesScanning.forEach((libraryScan) => {
this.scanStart(libraryScan)
})
}
// Remove any current scans that are no longer running
var currentScans = [...this.$store.state.scanners.libraryScans]
currentScans.forEach((ls) => {
if (!payload.librariesScanning || !payload.librariesScanning.find((_ls) => _ls.id === ls.id)) {
this.$toast.dismiss(ls.toastId)
this.$store.commit('scanners/remove', ls)
}
})
if (payload.usersOnline) { if (payload.usersOnline) {
this.$store.commit('users/setUsersOnline', payload.usersOnline) this.$store.commit('users/setUsersOnline', payload.usersOnline)
} }
@@ -228,50 +211,6 @@ export default {
this.libraryItemAdded(ab) this.libraryItemAdded(ab)
}) })
}, },
scanComplete(data) {
console.log('Scan complete received', data)
var message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" complete!`
if (data.results) {
var scanResultMsgs = []
var results = data.results
if (results.added) scanResultMsgs.push(`${results.added} added`)
if (results.updated) scanResultMsgs.push(`${results.updated} updated`)
if (results.removed) scanResultMsgs.push(`${results.removed} removed`)
if (results.missing) scanResultMsgs.push(`${results.missing} missing`)
if (!scanResultMsgs.length) message += '\nEverything was up to date'
else message += '\n' + scanResultMsgs.join('\n')
} else {
message = `${data.type === 'match' ? 'Match' : 'Scan'} "${data.name}" was canceled`
}
var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
if (existingScan && !isNaN(existingScan.toastId)) {
this.$toast.update(existingScan.toastId, { content: message, options: { timeout: 5000, type: 'success', closeButton: false, onClose: () => null } }, true)
} else {
this.$toast.success(message, { timeout: 5000 })
}
this.$store.commit('scanners/remove', data)
},
onScanToastCancel(id) {
this.$root.socket.emit('cancel_scan', id)
},
scanStart(data) {
data.toastId = this.$toast(`${data.type === 'match' ? 'Matching' : 'Scanning'} "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, onClose: () => this.onScanToastCancel(data.id) })
this.$store.commit('scanners/addUpdate', data)
},
scanProgress(data) {
var existingScan = this.$store.getters['scanners/getLibraryScan'](data.id)
if (existingScan && !isNaN(existingScan.toastId)) {
data.toastId = existingScan.toastId
this.$toast.update(existingScan.toastId, { content: `Scanning "${existingScan.name}"... ${data.progress.progress || 0}%`, options: { timeout: false } }, true)
} else {
data.toastId = this.$toast(`Scanning "${data.name}"...`, { timeout: false, type: 'info', draggable: false, closeOnClick: false, closeButton: CloseButton, closeButtonClassName: 'cancel-scan-btn', showCloseButtonOnHover: false, onClose: () => this.onScanToastCancel(data.id) })
}
this.$store.commit('scanners/addUpdate', data)
},
taskStarted(task) { taskStarted(task) {
console.log('Task started', task) console.log('Task started', task)
this.$store.commit('tasks/addUpdateTask', task) this.$store.commit('tasks/addUpdateTask', task)
@@ -343,6 +282,10 @@ export default {
} }
this.$store.commit('libraries/removeCollection', collection) this.$store.commit('libraries/removeCollection', collection)
}, },
seriesRemoved({ id, libraryId }) {
if (this.currentLibraryId !== libraryId) return
this.$store.commit('libraries/removeSeriesFromFilterData', id)
},
playlistAdded(playlist) { playlistAdded(playlist) {
if (playlist.userId !== this.user.id || this.currentLibraryId !== playlist.libraryId) return if (playlist.userId !== this.user.id || this.currentLibraryId !== playlist.libraryId) return
this.$store.commit('libraries/addUpdateUserPlaylist', playlist) this.$store.commit('libraries/addUpdateUserPlaylist', playlist)
@@ -442,16 +385,14 @@ export default {
this.socket.on('collection_updated', this.collectionUpdated) this.socket.on('collection_updated', this.collectionUpdated)
this.socket.on('collection_removed', this.collectionRemoved) this.socket.on('collection_removed', this.collectionRemoved)
// Series Listeners
this.socket.on('series_removed', this.seriesRemoved)
// User Playlist Listeners // User Playlist Listeners
this.socket.on('playlist_added', this.playlistAdded) this.socket.on('playlist_added', this.playlistAdded)
this.socket.on('playlist_updated', this.playlistUpdated) this.socket.on('playlist_updated', this.playlistUpdated)
this.socket.on('playlist_removed', this.playlistRemoved) this.socket.on('playlist_removed', this.playlistRemoved)
// Scan Listeners
this.socket.on('scan_start', this.scanStart)
this.socket.on('scan_complete', this.scanComplete)
this.socket.on('scan_progress', this.scanProgress)
// Task Listeners // Task Listeners
this.socket.on('task_started', this.taskStarted) this.socket.on('task_started', this.taskStarted)
this.socket.on('task_finished', this.taskFinished) this.socket.on('task_finished', this.taskFinished)
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.3.3", "version": "2.6.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.3.3", "version": "2.6.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",
+2 -1
View File
@@ -1,6 +1,7 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.3.3", "version": "2.6.0",
"buildNumber": 1,
"description": "Self-hosted audiobook and podcast client", "description": "Self-hosted audiobook and podcast client",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
+3 -3
View File
@@ -3,7 +3,7 @@
<div class="max-w-6xl mx-auto"> <div class="max-w-6xl mx-auto">
<div class="flex flex-wrap sm:flex-nowrap justify-center mb-6"> <div class="flex flex-wrap sm:flex-nowrap justify-center mb-6">
<div class="w-48 min-w-48"> <div class="w-48 min-w-48">
<div class="w-full h-52"> <div class="w-full h-60">
<covers-author-image :author="author" rounded="0" /> <covers-author-image :author="author" rounded="0" />
</div> </div>
</div> </div>
@@ -17,7 +17,7 @@
</div> </div>
<p v-if="author.description" class="text-white text-opacity-60 uppercase text-xs mb-2">{{ $strings.LabelDescription }}</p> <p v-if="author.description" class="text-white text-opacity-60 uppercase text-xs mb-2">{{ $strings.LabelDescription }}</p>
<p class="text-white max-w-3xl text-sm leading-5">{{ author.description }}</p> <p class="text-white max-w-3xl text-sm leading-5 whitespace-pre-wrap">{{ author.description }}</p>
</div> </div>
</div> </div>
@@ -44,7 +44,7 @@
<script> <script>
export default { export default {
async asyncData({ store, app, params, redirect, query }) { async asyncData({ store, app, params, redirect, query }) {
const author = await app.$axios.$get(`/api/authors/${params.id}?library=${query.library || store.state.libraries.currentLibraryId}&include=items,series`).catch((error) => { const author = await app.$axios.$get(`/api/authors/${params.id}?include=items,series`).catch((error) => {
console.error('Failed to get author', error) console.error('Failed to get author', error)
return null return null
}) })
+2 -2
View File
@@ -26,8 +26,8 @@
</div> </div>
<div v-if="!isPodcastLibrary" class="flex items-center px-4 w-1/2"> <div v-if="!isPodcastLibrary" class="flex items-center px-4 w-1/2">
<ui-checkbox v-model="selectedBatchUsage.authors" /> <ui-checkbox v-model="selectedBatchUsage.authors" />
<!-- Authors filter only contains authors in this library, use query input to query all authors --> <!-- Authors filter only contains authors in this library, uses filter data -->
<ui-multi-select-query-input ref="authorsSelect" v-model="batchDetails.authors" :disabled="!selectedBatchUsage.authors" :label="$strings.LabelAuthors" endpoint="authors/search" class="mb-4 ml-4" /> <ui-multi-select-query-input ref="authorsSelect" v-model="batchDetails.authors" :disabled="!selectedBatchUsage.authors" :label="$strings.LabelAuthors" filter-key="authors" class="mb-4 ml-4" />
</div> </div>
<div v-if="!isPodcastLibrary && !isMapAppend" class="flex items-center px-4 w-1/2"> <div v-if="!isPodcastLibrary && !isMapAppend" class="flex items-center px-4 w-1/2">
<ui-checkbox v-model="selectedBatchUsage.publishedYear" /> <ui-checkbox v-model="selectedBatchUsage.publishedYear" />
+2
View File
@@ -55,7 +55,9 @@ export default {
else if (pageName === 'library-stats') return this.$strings.HeaderLibraryStats else if (pageName === 'library-stats') return this.$strings.HeaderLibraryStats
else if (pageName === 'users') return this.$strings.HeaderUsers else if (pageName === 'users') return this.$strings.HeaderUsers
else if (pageName === 'item-metadata-utils') return this.$strings.HeaderItemMetadataUtils else if (pageName === 'item-metadata-utils') return this.$strings.HeaderItemMetadataUtils
else if (pageName === 'rss-feeds') return this.$strings.HeaderRSSFeeds
else if (pageName === 'email') return this.$strings.HeaderEmail else if (pageName === 'email') return this.$strings.HeaderEmail
else if (pageName === 'authentication') return this.$strings.HeaderAuthentication
} }
return this.$strings.HeaderSettings return this.$strings.HeaderSettings
} }
+244
View File
@@ -0,0 +1,244 @@
<template>
<div id="authentication-settings">
<app-settings-content :header-text="$strings.HeaderAuthentication">
<div class="w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25">
<div class="flex items-center">
<ui-checkbox v-model="enableLocalAuth" checkbox-bg="bg" />
<p class="text-lg pl-4">{{ $strings.HeaderPasswordAuthentication }}</p>
</div>
</div>
<div class="w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25">
<div class="flex items-center">
<ui-checkbox v-model="enableOpenIDAuth" checkbox-bg="bg" />
<p class="text-lg pl-4">{{ $strings.HeaderOpenIDConnectAuthentication }}</p>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
<a href="https://www.audiobookshelf.org/guides/oidc_authentication" target="_blank" class="inline-flex">
<span class="material-icons text-xl w-5 text-gray-200">help_outline</span>
</a>
</ui-tooltip>
</div>
<transition name="slide">
<div v-if="enableOpenIDAuth" class="flex flex-wrap pt-4">
<div class="w-full flex items-center mb-2">
<div class="flex-grow">
<ui-text-input-with-label ref="issuerUrl" v-model="newAuthSettings.authOpenIDIssuerURL" :disabled="savingSettings" :label="'Issuer URL'" />
</div>
<div class="w-36 mx-1 mt-[1.375rem]">
<ui-btn class="h-[2.375rem] text-sm inline-flex items-center justify-center w-full" type="button" :padding-y="0" :padding-x="4" @click.stop="autoPopulateOIDCClick">
<span class="material-icons text-base">auto_fix_high</span>
<span class="whitespace-nowrap break-keep pl-1">Auto-populate</span></ui-btn
>
</div>
</div>
<ui-text-input-with-label ref="authorizationUrl" v-model="newAuthSettings.authOpenIDAuthorizationURL" :disabled="savingSettings" :label="'Authorize URL'" class="mb-2" />
<ui-text-input-with-label ref="tokenUrl" v-model="newAuthSettings.authOpenIDTokenURL" :disabled="savingSettings" :label="'Token URL'" class="mb-2" />
<ui-text-input-with-label ref="userInfoUrl" v-model="newAuthSettings.authOpenIDUserInfoURL" :disabled="savingSettings" :label="'Userinfo URL'" class="mb-2" />
<ui-text-input-with-label ref="jwksUrl" v-model="newAuthSettings.authOpenIDJwksURL" :disabled="savingSettings" :label="'JWKS URL'" class="mb-2" />
<ui-text-input-with-label ref="logoutUrl" v-model="newAuthSettings.authOpenIDLogoutURL" :disabled="savingSettings" :label="'Logout URL'" class="mb-2" />
<ui-text-input-with-label ref="openidClientId" v-model="newAuthSettings.authOpenIDClientID" :disabled="savingSettings" :label="'Client ID'" class="mb-2" />
<ui-text-input-with-label ref="openidClientSecret" v-model="newAuthSettings.authOpenIDClientSecret" :disabled="savingSettings" :label="'Client Secret'" class="mb-2" />
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" />
<div class="flex items-center pt-1 mb-2">
<div class="w-44">
<ui-dropdown v-model="newAuthSettings.authOpenIDMatchExistingBy" small :items="matchingExistingOptions" :label="$strings.LabelMatchExistingUsersBy" :disabled="savingSettings" />
</div>
<p class="pl-4 text-sm text-gray-300 mt-5">{{ $strings.LabelMatchExistingUsersByDescription }}</p>
</div>
<div class="flex items-center py-4 px-1">
<ui-toggle-switch labeledBy="auto-redirect-toggle" v-model="newAuthSettings.authOpenIDAutoLaunch" :disabled="savingSettings" />
<p id="auto-redirect-toggle" class="pl-4 whitespace-nowrap">{{ $strings.LabelAutoLaunch }}</p>
<p class="pl-4 text-sm text-gray-300" v-html="$strings.LabelAutoLaunchDescription" />
</div>
<div class="flex items-center py-4 px-1">
<ui-toggle-switch labeledBy="auto-register-toggle" v-model="newAuthSettings.authOpenIDAutoRegister" :disabled="savingSettings" />
<p id="auto-register-toggle" class="pl-4 whitespace-nowrap">{{ $strings.LabelAutoRegister }}</p>
<p class="pl-4 text-sm text-gray-300">{{ $strings.LabelAutoRegisterDescription }}</p>
</div>
</div>
</transition>
</div>
<div class="w-full flex items-center justify-end p-4">
<ui-btn color="success" :padding-x="8" small class="text-base" :loading="savingSettings" @click="saveSettings">{{ $strings.ButtonSave }}</ui-btn>
</div>
</app-settings-content>
</div>
</template>
<script>
export default {
async asyncData({ store, redirect, app }) {
if (!store.getters['user/getIsAdminOrUp']) {
redirect('/')
return
}
const authSettings = await app.$axios.$get('/api/auth-settings').catch((error) => {
console.error('Failed', error)
return null
})
if (!authSettings) {
redirect('/config')
return
}
return {
authSettings
}
},
data() {
return {
enableLocalAuth: false,
enableOpenIDAuth: false,
savingSettings: false,
newAuthSettings: {}
}
},
computed: {
authMethods() {
return this.authSettings.authActiveAuthMethods || []
},
matchingExistingOptions() {
return [
{
text: 'Do not match',
value: null
},
{
text: 'Match by email',
value: 'email'
},
{
text: 'Match by username',
value: 'username'
}
]
}
},
methods: {
autoPopulateOIDCClick() {
if (!this.newAuthSettings.authOpenIDIssuerURL) {
this.$toast.error('Issuer URL required')
return
}
// Remove trailing slash
let issuerUrl = this.newAuthSettings.authOpenIDIssuerURL
if (issuerUrl.endsWith('/')) issuerUrl = issuerUrl.slice(0, -1)
// If the full config path is on the issuer url then remove it
if (issuerUrl.endsWith('/.well-known/openid-configuration')) {
issuerUrl = issuerUrl.replace('/.well-known/openid-configuration', '')
this.newAuthSettings.authOpenIDIssuerURL = this.newAuthSettings.authOpenIDIssuerURL.replace('/.well-known/openid-configuration', '')
}
this.$axios
.$get(`/auth/openid/config?issuer=${issuerUrl}`)
.then((data) => {
if (data.issuer) this.newAuthSettings.authOpenIDIssuerURL = data.issuer
if (data.authorization_endpoint) this.newAuthSettings.authOpenIDAuthorizationURL = data.authorization_endpoint
if (data.token_endpoint) this.newAuthSettings.authOpenIDTokenURL = data.token_endpoint
if (data.userinfo_endpoint) this.newAuthSettings.authOpenIDUserInfoURL = data.userinfo_endpoint
if (data.end_session_endpoint) this.newAuthSettings.authOpenIDLogoutURL = data.end_session_endpoint
if (data.jwks_uri) this.newAuthSettings.authOpenIDJwksURL = data.jwks_uri
})
.catch((error) => {
console.error('Failed to receive data', error)
const errorMsg = error.response?.data || 'Unknown error'
this.$toast.error(errorMsg)
})
},
validateOpenID() {
let isValid = true
if (!this.newAuthSettings.authOpenIDIssuerURL) {
this.$toast.error('Issuer URL required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDAuthorizationURL) {
this.$toast.error('Authorize URL required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDTokenURL) {
this.$toast.error('Token URL required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDUserInfoURL) {
this.$toast.error('Userinfo URL required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDJwksURL) {
this.$toast.error('JWKS URL required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDClientID) {
this.$toast.error('Client ID required')
isValid = false
}
if (!this.newAuthSettings.authOpenIDClientSecret) {
this.$toast.error('Client Secret required')
isValid = false
}
return isValid
},
async saveSettings() {
if (!this.enableLocalAuth && !this.enableOpenIDAuth) {
this.$toast.error('Must have at least one authentication method enabled')
return
}
if (this.enableOpenIDAuth && !this.validateOpenID()) {
return
}
this.newAuthSettings.authActiveAuthMethods = []
if (this.enableLocalAuth) this.newAuthSettings.authActiveAuthMethods.push('local')
if (this.enableOpenIDAuth) this.newAuthSettings.authActiveAuthMethods.push('openid')
this.savingSettings = true
this.$axios
.$patch('/api/auth-settings', this.newAuthSettings)
.then((data) => {
this.$store.commit('setServerSettings', data.serverSettings)
this.$toast.success('Server settings updated')
})
.catch((error) => {
console.error('Failed to update server settings', error)
this.$toast.error('Failed to update server settings')
})
.finally(() => {
this.savingSettings = false
})
},
init() {
this.newAuthSettings = {
...this.authSettings
}
this.enableLocalAuth = this.authMethods.includes('local')
this.enableOpenIDAuth = this.authMethods.includes('openid')
}
},
mounted() {
this.init()
}
}
</script>
<style>
#authentication-settings code {
font-size: 0.8rem;
border-radius: 6px;
background-color: rgb(82, 82, 82);
color: white;
padding: 2px 4px;
white-space: nowrap;
}
</style>
+14 -4
View File
@@ -1,6 +1,12 @@
<template> <template>
<div> <div>
<app-settings-content :header-text="$strings.HeaderBackups" :description="$strings.MessageBackupsDescription"> <app-settings-content :header-text="$strings.HeaderBackups" :description="$strings.MessageBackupsDescription">
<div v-if="backupLocation" class="flex items-center mb-4">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">folder</span>
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelBackupLocation }}:</span>
<div class="text-gray-100 pl-4">{{ backupLocation }}</div>
</div>
<div class="flex items-center py-2"> <div class="flex items-center py-2">
<ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" /> <ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" />
<ui-tooltip :text="$strings.LabelBackupsEnableAutomaticBackupsHelp"> <ui-tooltip :text="$strings.LabelBackupsEnableAutomaticBackupsHelp">
@@ -11,7 +17,7 @@
<div v-if="enableBackups" class="mb-6"> <div v-if="enableBackups" class="mb-6">
<div class="flex items-center pl-6 mb-2"> <div class="flex items-center pl-6 mb-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">schedule</span> <span class="material-icons-outlined text-2xl text-black-50 mr-2">schedule</span>
<div class="w-48"> <div class="w-40">
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.HeaderSchedule }}:</span> <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.HeaderSchedule }}:</span>
</div> </div>
<div class="text-gray-100">{{ scheduleDescription }}</div> <div class="text-gray-100">{{ scheduleDescription }}</div>
@@ -20,7 +26,7 @@
<div v-if="nextBackupDate" class="flex items-center pl-6 py-0.5 px-2"> <div v-if="nextBackupDate" class="flex items-center pl-6 py-0.5 px-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">event</span> <span class="material-icons-outlined text-2xl text-black-50 mr-2">event</span>
<div class="w-48"> <div class="w-40">
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNextBackupDate }}:</span> <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNextBackupDate }}:</span>
</div> </div>
<div class="text-gray-100">{{ nextBackupDate }}</div> <div class="text-gray-100">{{ nextBackupDate }}</div>
@@ -43,7 +49,7 @@
</ui-tooltip> </ui-tooltip>
</div> </div>
<tables-backups-table /> <tables-backups-table @loaded="backupsLoaded" />
<modals-backup-schedule-modal v-model="showCronBuilder" :cron-expression.sync="cronExpression" /> <modals-backup-schedule-modal v-model="showCronBuilder" :cron-expression.sync="cronExpression" />
</app-settings-content> </app-settings-content>
@@ -65,7 +71,8 @@ export default {
maxBackupSize: 1, maxBackupSize: 1,
cronExpression: '', cronExpression: '',
newServerSettings: {}, newServerSettings: {},
showCronBuilder: false showCronBuilder: false,
backupLocation: ''
} }
}, },
watch: { watch: {
@@ -98,6 +105,9 @@ export default {
} }
}, },
methods: { methods: {
backupsLoaded(backupLocation) {
this.backupLocation = backupLocation
},
updateBackupsSettings() { updateBackupsSettings() {
if (isNaN(this.maxBackupSize) || this.maxBackupSize <= 0) { if (isNaN(this.maxBackupSize) || this.maxBackupSize <= 0) {
this.$toast.error('Invalid maximum backup size') this.$toast.error('Invalid maximum backup size')
+8 -2
View File
@@ -51,8 +51,14 @@
</div> </div>
</app-settings-content> </app-settings-content>
<app-settings-content :header-text="$strings.HeaderEreaderDevices" showAddButton :description="''" @clicked="addNewDeviceClick"> <app-settings-content :header-text="$strings.HeaderEreaderDevices" :description="''">
<table v-if="existingEReaderDevices.length" class="tracksTable my-4"> <template #header-items>
<div class="flex-grow" />
<ui-btn color="primary" small @click="addNewDeviceClick">{{ $strings.ButtonAddDevice }}</ui-btn>
</template>
<table v-if="existingEReaderDevices.length" class="tracksTable mt-4">
<tr> <tr>
<th class="text-left">{{ $strings.LabelName }}</th> <th class="text-left">{{ $strings.LabelName }}</th>
<th class="text-left">{{ $strings.LabelEmail }}</th> <th class="text-left">{{ $strings.LabelEmail }}</th>
+86 -103
View File
@@ -36,7 +36,10 @@
</ui-tooltip> </ui-tooltip>
</div> </div>
<div v-if="newServerSettings.sortingIgnorePrefix" class="w-72 ml-14 mb-2"> <div v-if="newServerSettings.sortingIgnorePrefix" class="w-72 ml-14 mb-2">
<ui-multi-select v-model="newServerSettings.sortingPrefixes" small :items="newServerSettings.sortingPrefixes" :label="$strings.LabelPrefixesToIgnore" @input="updateSortingPrefixes" :disabled="updatingServerSettings" /> <ui-multi-select v-model="newServerSettings.sortingPrefixes" small :items="newServerSettings.sortingPrefixes" :label="$strings.LabelPrefixesToIgnore" @input="sortingPrefixesUpdated" :disabled="savingPrefixes" />
<div class="flex justify-end py-1">
<ui-btn v-if="hasPrefixesChanged" color="success" :loading="savingPrefixes" small @click="updateSortingPrefixes">Save</ui-btn>
</div>
</div> </div>
<div class="flex items-center py-2 mb-2"> <div class="flex items-center py-2 mb-2">
@@ -44,10 +47,56 @@
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p> <p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
</div> </div>
<div class="w-44 mb-2"> <div class="pt-4">
<ui-dropdown v-model="newServerSettings.metadataFileFormat" small :items="metadataFileFormats" label="Metadata File Format" @input="updateMetadataFileFormat" :disabled="updatingServerSettings" /> <h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
</div> </div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-parse-subtitles" v-model="newServerSettings.scannerParseSubtitle" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerParseSubtitle', val)" />
<ui-tooltip :text="$strings.LabelSettingsParseSubtitlesHelp">
<p class="pl-4">
<span id="settings-parse-subtitles">{{ $strings.LabelSettingsParseSubtitles }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-find-covers" v-model="newServerSettings.scannerFindCovers" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerFindCovers', val)" />
<ui-tooltip :text="$strings.LabelSettingsFindCoversHelp">
<p class="pl-4">
<span id="settings-find-covers">{{ $strings.LabelSettingsFindCovers }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
<div class="flex-grow" />
</div>
<div v-if="newServerSettings.scannerFindCovers" class="w-44 ml-14 mb-2">
<ui-dropdown v-model="newServerSettings.scannerCoverProvider" small :items="providers" label="Cover Provider" @input="updateScannerCoverProvider" :disabled="updatingServerSettings" />
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-prefer-matched-metadata" v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
<ui-tooltip :text="$strings.LabelSettingsPreferMatchedMetadataHelp">
<p class="pl-4">
<span id="settings-prefer-matched-metadata">{{ $strings.LabelSettingsPreferMatchedMetadata }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-disable-watcher" v-model="scannerEnableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', !val)" />
<ui-tooltip :text="$strings.LabelSettingsEnableWatcherHelp">
<p class="pl-4">
<span id="settings-disable-watcher">{{ $strings.LabelSettingsEnableWatcher }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
</div>
<div class="flex-1">
<div class="pt-4"> <div class="pt-4">
<h2 class="font-semibold">{{ $strings.HeaderSettingsDisplay }}</h2> <h2 class="font-semibold">{{ $strings.HeaderSettingsDisplay }}</h2>
</div> </div>
@@ -85,86 +134,6 @@
<div class="py-2"> <div class="py-2">
<ui-dropdown :label="$strings.LabelLanguageDefaultServer" ref="langDropdown" v-model="newServerSettings.language" :items="$languageCodeOptions" small class="max-w-52" @input="updateServerLanguage" /> <ui-dropdown :label="$strings.LabelLanguageDefaultServer" ref="langDropdown" v-model="newServerSettings.language" :items="$languageCodeOptions" small class="max-w-52" @input="updateServerLanguage" />
</div> </div>
</div>
<div class="flex-1">
<div class="pt-4">
<h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-parse-subtitles" v-model="newServerSettings.scannerParseSubtitle" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerParseSubtitle', val)" />
<ui-tooltip :text="$strings.LabelSettingsParseSubtitlesHelp">
<p class="pl-4">
<span id="settings-parse-subtitles">{{ $strings.LabelSettingsParseSubtitles }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-find-covers" v-model="newServerSettings.scannerFindCovers" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerFindCovers', val)" />
<ui-tooltip :text="$strings.LabelSettingsFindCoversHelp">
<p class="pl-4">
<span id="settings-find-covers">{{ $strings.LabelSettingsFindCovers }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
<div class="flex-grow" />
</div>
<div v-if="newServerSettings.scannerFindCovers" class="w-44 ml-14 mb-2">
<ui-dropdown v-model="newServerSettings.scannerCoverProvider" small :items="providers" label="Cover Provider" @input="updateScannerCoverProvider" :disabled="updatingServerSettings" />
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-overdrive-media-markers" v-model="newServerSettings.scannerPreferOverdriveMediaMarker" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOverdriveMediaMarker', val)" />
<ui-tooltip :text="$strings.LabelSettingsOverdriveMediaMarkersHelp">
<p class="pl-4">
<span id="settings-overdrive-media-markers">{{ $strings.LabelSettingsOverdriveMediaMarkers }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-prefer-audio-metadata" v-model="newServerSettings.scannerPreferAudioMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferAudioMetadata', val)" />
<ui-tooltip :text="$strings.LabelSettingsPreferAudioMetadataHelp">
<p class="pl-4">
<span id="settings-prefer-audio-metadata">{{ $strings.LabelSettingsPreferAudioMetadata }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-prefer-opf-metadata" v-model="newServerSettings.scannerPreferOpfMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferOpfMetadata', val)" />
<ui-tooltip :text="$strings.LabelSettingsPreferOPFMetadataHelp">
<p class="pl-4">
<span id="settings-prefer-opf-metadata">{{ $strings.LabelSettingsPreferOPFMetadata }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-prefer-matched-metadata" v-model="newServerSettings.scannerPreferMatchedMetadata" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerPreferMatchedMetadata', val)" />
<ui-tooltip :text="$strings.LabelSettingsPreferMatchedMetadataHelp">
<p class="pl-4">
<span id="settings-prefer-matched-metadata">{{ $strings.LabelSettingsPreferMatchedMetadata }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-disable-watcher" v-model="newServerSettings.scannerDisableWatcher" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('scannerDisableWatcher', val)" />
<ui-tooltip :text="$strings.LabelSettingsDisableWatcherHelp">
<p class="pl-4">
<span id="settings-disable-watcher">{{ $strings.LabelSettingsDisableWatcher }}</span>
<span class="material-icons icon-text">info_outlined</span>
</p>
</ui-tooltip>
</div>
<!-- old experimental features --> <!-- old experimental features -->
<!-- <div class="pt-4"> <!-- <div class="pt-4">
@@ -259,19 +228,12 @@ export default {
updatingServerSettings: false, updatingServerSettings: false,
homepageUseBookshelfView: false, homepageUseBookshelfView: false,
useBookshelfView: false, useBookshelfView: false,
scannerEnableWatcher: false,
isPurgingCache: false, isPurgingCache: false,
hasPrefixesChanged: false,
newServerSettings: {}, newServerSettings: {},
showConfirmPurgeCache: false, showConfirmPurgeCache: false,
metadataFileFormats: [ savingPrefixes: false
{
text: '.json',
value: 'json'
},
{
text: '.abs',
value: 'abs'
}
]
} }
}, },
watch: { watch: {
@@ -304,15 +266,36 @@ export default {
} }
}, },
methods: { methods: {
updateSortingPrefixes(val) { sortingPrefixesUpdated(val) {
if (!val || !val.length) { const prefixes = [...new Set(val?.map((prefix) => prefix.trim().toLowerCase()) || [])]
this.newServerSettings.sortingPrefixes = prefixes
const serverPrefixes = this.serverSettings.sortingPrefixes || []
this.hasPrefixesChanged = prefixes.some((p) => !serverPrefixes.includes(p)) || serverPrefixes.some((p) => !prefixes.includes(p))
},
updateSortingPrefixes() {
const prefixes = [...new Set(this.newServerSettings.sortingPrefixes.map((prefix) => prefix.trim().toLowerCase()) || [])]
if (!prefixes.length) {
this.$toast.error('Must have at least 1 prefix') this.$toast.error('Must have at least 1 prefix')
return return
} }
var prefixes = val.map((prefix) => prefix.trim().toLowerCase())
this.updateServerSettings({ this.savingPrefixes = true
sortingPrefixes: prefixes this.$axios
}) .$patch(`/api/sorting-prefixes`, { sortingPrefixes: prefixes })
.then((data) => {
this.$toast.success(`Sorting prefixes updated. ${data.rowsUpdated} rows`)
if (data.serverSettings) {
this.$store.commit('setServerSettings', data.serverSettings)
}
this.hasPrefixesChanged = false
})
.catch((error) => {
console.error('Failed to update prefixes', error)
this.$toast.error('Failed to update sorting prefixes')
})
.finally(() => {
this.savingPrefixes = false
})
}, },
updateScannerCoverProvider(val) { updateScannerCoverProvider(val) {
this.updateServerSettings({ this.updateServerSettings({
@@ -332,11 +315,10 @@ export default {
updateServerLanguage(val) { updateServerLanguage(val) {
this.updateSettingsKey('language', val) this.updateSettingsKey('language', val)
}, },
updateMetadataFileFormat(val) {
if (this.serverSettings.metadataFileFormat === val) return
this.updateSettingsKey('metadataFileFormat', val)
},
updateSettingsKey(key, val) { updateSettingsKey(key, val) {
if (key === 'scannerDisableWatcher') {
this.newServerSettings.scannerDisableWatcher = val
}
this.updateServerSettings({ this.updateServerSettings({
[key]: val [key]: val
}) })
@@ -363,6 +345,7 @@ export default {
initServerSettings() { initServerSettings() {
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {} this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
this.newServerSettings.sortingPrefixes = [...(this.newServerSettings.sortingPrefixes || [])] this.newServerSettings.sortingPrefixes = [...(this.newServerSettings.sortingPrefixes || [])]
this.scannerEnableWatcher = !this.newServerSettings.scannerDisableWatcher
this.homepageUseBookshelfView = this.newServerSettings.homeBookshelfView != this.$constants.BookshelfView.DETAIL this.homepageUseBookshelfView = this.newServerSettings.homeBookshelfView != this.$constants.BookshelfView.DETAIL
this.useBookshelfView = this.newServerSettings.bookshelfView != this.$constants.BookshelfView.DETAIL this.useBookshelfView = this.newServerSettings.bookshelfView != this.$constants.BookshelfView.DETAIL
+13 -2
View File
@@ -1,7 +1,18 @@
<template> <template>
<div> <div>
<app-settings-content :header-text="$strings.HeaderLibraries" show-add-button @clicked="setShowLibraryModal"> <app-settings-content :header-text="$strings.HeaderLibraries">
<tables-library-libraries-table @showLibraryModal="setShowLibraryModal" /> <template #header-items>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
<a href="https://www.audiobookshelf.org/guides/library_creation" target="_blank" class="inline-flex">
<span class="material-icons text-xl w-5 text-gray-200">help_outline</span>
</a>
</ui-tooltip>
<div class="flex-grow" />
<ui-btn color="primary" small @click="setShowLibraryModal()">{{ $strings.ButtonAddLibrary }}</ui-btn>
</template>
<tables-library-libraries-table @showLibraryModal="setShowLibraryModal" class="pt-2" />
</app-settings-content> </app-settings-content>
<modals-libraries-edit-modal v-model="showLibraryModal" :library="selectedLibrary" /> <modals-libraries-edit-modal v-model="showLibraryModal" :library="selectedLibrary" />
</div> </div>
+14 -8
View File
@@ -22,7 +22,7 @@
</div> </div>
</template> </template>
</div> </div>
<div class="w-80 my-6 mx-auto"> <div v-if="isBookLibrary" class="w-80 my-6 mx-auto">
<h1 class="text-2xl mb-4">{{ $strings.HeaderStatsTop10Authors }}</h1> <h1 class="text-2xl mb-4">{{ $strings.HeaderStatsTop10Authors }}</h1>
<p v-if="!top10Authors.length">{{ $strings.MessageNoAuthors }}</p> <p v-if="!top10Authors.length">{{ $strings.MessageNoAuthors }}</p>
<template v-for="(author, index) in top10Authors"> <template v-for="(author, index) in top10Authors">
@@ -114,43 +114,49 @@ export default {
return this.$store.state.user.user return this.$store.state.user.user
}, },
totalItems() { totalItems() {
return this.libraryStats ? this.libraryStats.totalItems : 0 return this.libraryStats?.totalItems || 0
}, },
genresWithCount() { genresWithCount() {
return this.libraryStats ? this.libraryStats.genresWithCount : [] return this.libraryStats?.genresWithCount || []
}, },
top5Genres() { top5Genres() {
return this.genresWithCount.slice(0, 5) return this.genresWithCount?.slice(0, 5) || []
}, },
top10LongestItems() { top10LongestItems() {
return this.libraryStats ? this.libraryStats.longestItems || [] : [] return this.libraryStats?.longestItems || []
}, },
longestItemDuration() { longestItemDuration() {
if (!this.top10LongestItems.length) return 0 if (!this.top10LongestItems.length) return 0
return this.top10LongestItems[0].duration return this.top10LongestItems[0].duration
}, },
top10LargestItems() { top10LargestItems() {
return this.libraryStats ? this.libraryStats.largestItems || [] : [] return this.libraryStats?.largestItems || []
}, },
largestItemSize() { largestItemSize() {
if (!this.top10LargestItems.length) return 0 if (!this.top10LargestItems.length) return 0
return this.top10LargestItems[0].size return this.top10LargestItems[0].size
}, },
authorsWithCount() { authorsWithCount() {
return this.libraryStats ? this.libraryStats.authorsWithCount : [] return this.libraryStats?.authorsWithCount || []
}, },
mostUsedAuthorCount() { mostUsedAuthorCount() {
if (!this.authorsWithCount.length) return 0 if (!this.authorsWithCount.length) return 0
return this.authorsWithCount[0].count return this.authorsWithCount[0].count
}, },
top10Authors() { top10Authors() {
return this.authorsWithCount.slice(0, 10) return this.authorsWithCount?.slice(0, 10) || []
}, },
currentLibraryId() { currentLibraryId() {
return this.$store.state.libraries.currentLibraryId return this.$store.state.libraries.currentLibraryId
}, },
currentLibraryName() { currentLibraryName() {
return this.$store.getters['libraries/getCurrentLibraryName'] return this.$store.getters['libraries/getCurrentLibraryName']
},
currentLibraryMediaType() {
return this.$store.getters['libraries/getCurrentLibraryMediaType']
},
isBookLibrary() {
return this.currentLibraryMediaType === 'book'
} }
}, },
methods: { methods: {
+184
View File
@@ -0,0 +1,184 @@
<template>
<div>
<app-settings-content :header-text="$strings.HeaderRSSFeeds">
<template #header-items>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
<a href="https://www.audiobookshelf.org/guides/rss_feeds" target="_blank" class="inline-flex">
<span class="material-icons text-xl w-5 text-gray-200">help_outline</span>
</a>
</ui-tooltip>
</template>
<div v-if="feeds.length" class="block max-w-full pt-2">
<table class="rssFeedsTable text-xs">
<tr class="bg-primary bg-opacity-40 h-12">
<th class="w-16 min-w-16"></th>
<th class="w-48 max-w-64 min-w-24 text-left truncate">{{ $strings.LabelTitle }}</th>
<th class="w-48 min-w-24 text-left hidden xl:table-cell">{{ $strings.LabelSlug }}</th>
<th class="w-24 min-w-16 text-left hidden md:table-cell">{{ $strings.LabelType }}</th>
<th class="w-16 min-w-16 text-center">{{ $strings.HeaderEpisodes }}</th>
<th class="w-16 min-w-16 text-center hidden lg:table-cell">{{ $strings.LabelRSSFeedPreventIndexing }}</th>
<th class="w-48 min-w-24 flex-grow hidden md:table-cell">{{ $strings.LabelLastUpdate }}</th>
<th class="w-16 text-left"></th>
</tr>
<tr v-for="feed in feeds" :key="feed.id" class="cursor-pointer h-12" @click="showFeed(feed)">
<!-- -->
<td>
<img :src="coverUrl(feed)" class="h-full w-full" />
</td>
<!-- -->
<td class="w-48 max-w-64 min-w-24 text-left truncate">
<p class="truncate">{{ feed.meta.title }}</p>
</td>
<!-- -->
<td class="hidden xl:table-cell">
<p class="truncate">{{ feed.slug }}</p>
</td>
<!-- -->
<td class="hidden md:table-cell">
<p class="">{{ getEntityType(feed.entityType) }}</p>
</td>
<!-- -->
<td class="text-center">
<p class="">{{ feed.episodes.length }}</p>
</td>
<!-- -->
<td class="text-center leading-none hidden lg:table-cell">
<p v-if="feed.meta.preventIndexing" class="">
<span class="material-icons text-2xl">check</span>
</p>
</td>
<!-- -->
<td class="text-center hidden md:table-cell">
<ui-tooltip v-if="feed.updatedAt" direction="top" :text="$formatDatetime(feed.updatedAt, dateFormat, timeFormat)">
<p class="text-gray-200">{{ $dateDistanceFromNow(feed.updatedAt) }}</p>
</ui-tooltip>
</td>
<!-- -->
<td class="text-center">
<ui-icon-btn icon="delete" class="mx-0.5" :size="7" bg-color="error" outlined @click.stop="deleteFeedClick(feed)" />
</td>
</tr>
</table>
</div>
</app-settings-content>
<modals-rssfeed-view-feed-modal v-model="showFeedModal" :feed="selectedFeed" />
</div>
</template>
<script>
export default {
data() {
return {
showFeedModal: false,
selectedFeed: null,
feeds: []
}
},
computed: {
dateFormat() {
return this.$store.state.serverSettings.dateFormat
},
timeFormat() {
return this.$store.state.serverSettings.timeFormat
}
},
methods: {
showFeed(feed) {
this.selectedFeed = feed
this.showFeedModal = true
},
deleteFeedClick(feed) {
const payload = {
message: this.$strings.MessageConfirmCloseFeed,
callback: (confirmed) => {
if (confirmed) {
this.deleteFeed(feed)
}
},
type: 'yesNo'
}
this.$store.commit('globals/setConfirmPrompt', payload)
},
deleteFeed(feed) {
this.processing = true
this.$axios
.$post(`/api/feeds/${feed.id}/close`)
.then(() => {
this.$toast.success(this.$strings.ToastRSSFeedCloseSuccess)
this.show = false
this.loadFeeds()
})
.catch((error) => {
console.error('Failed to close RSS feed', error)
this.$toast.error(this.$strings.ToastRSSFeedCloseFailed)
})
.finally(() => {
this.processing = false
})
},
getEntityType(entityType) {
if (entityType === 'libraryItem') return this.$strings.LabelItem
else if (entityType === 'series') return this.$strings.LabelSeries
else if (entityType === 'collection') return this.$strings.LabelCollection
return this.$strings.LabelUnknown
},
coverUrl(feed) {
if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
return `${feed.feedUrl}/cover`
},
async loadFeeds() {
const data = await this.$axios.$get(`/api/feeds`).catch((err) => {
console.error('Failed to load RSS feeds', err)
return null
})
if (!data) {
this.$toast.error('Failed to load RSS feeds')
return
}
this.feeds = data.feeds
},
init() {
this.loadFeeds()
}
},
mounted() {
this.init()
}
}
</script>
<style scoped>
.rssFeedsTable {
border-collapse: collapse;
width: 100%;
max-width: 100%;
border: 1px solid #474747;
}
.rssFeedsTable tr:first-child {
background-color: #272727;
}
.rssFeedsTable tr:not(:first-child) {
background-color: #373838;
}
.rssFeedsTable tr:not(:first-child):nth-child(odd) {
background-color: #2f2f2f;
}
.rssFeedsTable tr:hover:not(:first-child) {
background-color: #474747;
}
.rssFeedsTable td {
padding: 4px 8px;
}
.rssFeedsTable th {
padding: 4px 8px;
font-size: 0.75rem;
}
</style>
+7 -6
View File
@@ -53,8 +53,10 @@
</div> </div>
<p v-else class="text-white text-opacity-50">{{ $strings.MessageNoListeningSessions }}</p> <p v-else class="text-white text-opacity-50">{{ $strings.MessageNoListeningSessions }}</p>
<div class="w-full my-8 h-px bg-white/10" />
<!-- open listening sessions table --> <!-- open listening sessions table -->
<p v-if="openListeningSessions.length" class="text-lg mb-4 mt-8">Open Listening Sessions</p> <p v-if="openListeningSessions.length" class="text-lg my-4">Open Listening Sessions</p>
<div v-if="openListeningSessions.length" class="block max-w-full"> <div v-if="openListeningSessions.length" class="block max-w-full">
<table class="userSessionsTable"> <table class="userSessionsTable">
<tr class="bg-primary bg-opacity-40"> <tr class="bg-primary bg-opacity-40">
@@ -73,8 +75,7 @@
<p class="text-xs text-gray-400 truncate">{{ session.displayAuthor }}</p> <p class="text-xs text-gray-400 truncate">{{ session.displayAuthor }}</p>
</td> </td>
<td class="hidden md:table-cell"> <td class="hidden md:table-cell">
<p v-if="filteredUserUsername" class="text-xs">{{ filteredUserUsername }}</p> <p class="text-xs">{{ session.user ? session.user.username : 'N/A' }}</p>
<p v-else class="text-xs">{{ session.user ? session.user.username : 'N/A' }}</p>
</td> </td>
<td class="hidden md:table-cell"> <td class="hidden md:table-cell">
<p class="text-xs">{{ getPlayMethodName(session.playMethod) }}</p> <p class="text-xs">{{ getPlayMethodName(session.playMethod) }}</p>
@@ -153,8 +154,8 @@ export default {
}, },
filteredUserUsername() { filteredUserUsername() {
if (!this.userFilter) return null if (!this.userFilter) return null
var user = this.users.find((u) => u.id === this.userFilter) const user = this.users.find((u) => u.id === this.userFilter)
return user ? user.username : null return user?.username || null
}, },
dateFormat() { dateFormat() {
return this.$store.state.serverSettings.dateFormat return this.$store.state.serverSettings.dateFormat
@@ -273,7 +274,7 @@ export default {
return 'Unknown' return 'Unknown'
}, },
async loadSessions(page) { async loadSessions(page) {
var userFilterQuery = this.selectedUser ? `&user=${this.selectedUser}` : '' const userFilterQuery = this.selectedUser ? `&user=${this.selectedUser}` : ''
const data = await this.$axios.$get(`/api/sessions?page=${page}&itemsPerPage=${this.itemsPerPage}${userFilterQuery}`).catch((err) => { const data = await this.$axios.$get(`/api/sessions?page=${page}&itemsPerPage=${this.itemsPerPage}${userFilterQuery}`).catch((err) => {
console.error('Failed to load listening sessions', err) console.error('Failed to load listening sessions', err)
return null return null
+6 -14
View File
@@ -47,7 +47,7 @@
<div class="py-2"> <div class="py-2">
<h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderSavedMediaProgress }}</h1> <h1 class="text-lg mb-2 text-white text-opacity-90 px-2 sm:px-0">{{ $strings.HeaderSavedMediaProgress }}</h1>
<table v-if="mediaProgressWithMedia.length" class="userAudiobooksTable"> <table v-if="mediaProgress.length" class="userAudiobooksTable">
<tr class="bg-primary bg-opacity-40"> <tr class="bg-primary bg-opacity-40">
<th class="w-16 text-left">{{ $strings.LabelItem }}</th> <th class="w-16 text-left">{{ $strings.LabelItem }}</th>
<th class="text-left"></th> <th class="text-left"></th>
@@ -55,19 +55,14 @@
<th class="w-40 hidden sm:table-cell">{{ $strings.LabelStartedAt }}</th> <th class="w-40 hidden sm:table-cell">{{ $strings.LabelStartedAt }}</th>
<th class="w-40 hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th> <th class="w-40 hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
</tr> </tr>
<tr v-for="item in mediaProgressWithMedia" :key="item.id" :class="!item.isFinished ? '' : 'isFinished'"> <tr v-for="item in mediaProgress" :key="item.id" :class="!item.isFinished ? '' : 'isFinished'">
<td> <td>
<covers-book-cover :width="50" :library-item="item" :book-cover-aspect-ratio="bookCoverAspectRatio" /> <covers-preview-cover v-if="item.coverPath" :width="50" :src="$store.getters['globals/getLibraryItemCoverSrcById'](item.libraryItemId, item.mediaUpdatedAt)" :book-cover-aspect-ratio="bookCoverAspectRatio" :show-resolution="false" />
<div v-else class="bg-primary flex items-center justify-center text-center text-xs text-gray-400 p-1" :style="{ width: '50px', height: 50 * bookCoverAspectRatio + 'px' }">No Cover</div>
</td> </td>
<td> <td>
<template v-if="item.media && item.media.metadata && item.episode"> <p>{{ item.displayTitle || 'Unknown' }}</p>
<p>{{ item.episode.title || 'Unknown' }}</p> <p v-if="item.displaySubtitle" class="text-white text-opacity-50 text-sm font-sans">{{ item.displaySubtitle }}</p>
<p class="text-white text-opacity-50 text-sm font-sans">{{ item.media.metadata.title }}</p>
</template>
<template v-else-if="item.media && item.media.metadata">
<p>{{ item.media.metadata.title || 'Unknown' }}</p>
<p v-if="item.media.metadata.authorName" class="text-white text-opacity-50 text-sm font-sans">by {{ item.media.metadata.authorName }}</p>
</template>
</td> </td>
<td class="text-center"> <td class="text-center">
<p class="text-sm">{{ Math.floor(item.progress * 100) }}%</p> <p class="text-sm">{{ Math.floor(item.progress * 100) }}%</p>
@@ -124,9 +119,6 @@ export default {
mediaProgress() { mediaProgress() {
return this.user.mediaProgress.sort((a, b) => b.lastUpdate - a.lastUpdate) return this.user.mediaProgress.sort((a, b) => b.lastUpdate - a.lastUpdate)
}, },
mediaProgressWithMedia() {
return this.mediaProgress.filter((mp) => mp.media)
},
totalListeningTime() { totalListeningTime() {
return this.listeningStats.totalTime || 0 return this.listeningStats.totalTime || 0
}, },
+14 -2
View File
@@ -1,7 +1,19 @@
<template> <template>
<div> <div>
<app-settings-content :header-text="$strings.HeaderUsers" show-add-button @clicked="setShowUserModal"> <app-settings-content :header-text="$strings.HeaderUsers">
<tables-users-table /> <template #header-items>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
<a href="https://www.audiobookshelf.org/guides/users" target="_blank" class="inline-flex">
<span class="material-icons text-xl w-5 text-gray-200">help_outline</span>
</a>
</ui-tooltip>
<div class="flex-grow" />
<ui-btn color="primary" small @click="setShowUserModal()">{{ $strings.ButtonAddUser }}</ui-btn>
</template>
<tables-users-table class="pt-2" @edit="setShowUserModal" />
</app-settings-content> </app-settings-content>
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" /> <modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
</div> </div>
+14 -10
View File
@@ -3,21 +3,21 @@
<div class="w-full h-full overflow-y-auto px-2 py-6 lg:p-8"> <div class="w-full h-full overflow-y-auto px-2 py-6 lg:p-8">
<div class="flex flex-col lg:flex-row max-w-6xl mx-auto"> <div class="flex flex-col lg:flex-row max-w-6xl mx-auto">
<div class="w-full flex justify-center lg:block lg:w-52" style="min-width: 208px"> <div class="w-full flex justify-center lg:block lg:w-52" style="min-width: 208px">
<div class="relative" style="height: fit-content"> <div class="relative group" style="height: fit-content">
<covers-book-cover :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" /> <covers-book-cover class="relative group-hover:brightness-75 transition cursor-pointer" expand-on-click :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
<!-- Item Progress Bar --> <!-- Item Progress Bar -->
<div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 208 * progressPercent + 'px' }"></div> <div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 208 * progressPercent + 'px' }"></div>
<!-- Item Cover Overlay --> <!-- Item Cover Overlay -->
<div class="absolute top-0 left-0 w-full h-full z-10 bg-black bg-opacity-30 opacity-0 hover:opacity-100 transition-opacity" @mousedown.prevent @mouseup.prevent> <div class="absolute top-0 left-0 w-full h-full z-10 opacity-0 group-hover:opacity-100 pointer-events-none">
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none"> <div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
<div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="playItem"> <div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="playItem">
<span class="material-icons text-4xl">play_circle_filled</span> <span class="material-icons text-4xl">play_circle_filled</span>
</div> </div>
</div> </div>
<span class="absolute bottom-2.5 right-2.5 z-10 material-icons text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200" @click="showEditCover">edit</span> <span class="absolute bottom-2.5 right-2.5 z-10 material-icons text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200 pointer-events-auto" @click="showEditCover">edit</span>
</div> </div>
</div> </div>
</div> </div>
@@ -42,7 +42,7 @@
<nuxt-link v-for="(artist, index) in musicArtists" :key="index" :to="`/artist/${$encode(artist)}`" class="hover:underline">{{ artist }}<span v-if="index < musicArtists.length - 1">,&nbsp;</span></nuxt-link> <nuxt-link v-for="(artist, index) in musicArtists" :key="index" :to="`/artist/${$encode(artist)}`" class="hover:underline">{{ artist }}<span v-if="index < musicArtists.length - 1">,&nbsp;</span></nuxt-link>
</p> </p>
<p v-else-if="authors.length" class="mb-2 mt-0.5 text-gray-200 text-lg md:text-xl max-w-[calc(100vw-2rem)] overflow-hidden overflow-ellipsis"> <p v-else-if="authors.length" class="mb-2 mt-0.5 text-gray-200 text-lg md:text-xl max-w-[calc(100vw-2rem)] overflow-hidden overflow-ellipsis">
by <nuxt-link v-for="(author, index) in authors" :key="index" :to="`/author/${author.id}?library=${libraryItem.libraryId}`" class="hover:underline">{{ author.name }}<span v-if="index < authors.length - 1">,&nbsp;</span></nuxt-link> by <nuxt-link v-for="(author, index) in authors" :key="index" :to="`/author/${author.id}`" class="hover:underline">{{ author.name }}<span v-if="index < authors.length - 1">,&nbsp;</span></nuxt-link>
</p> </p>
<p v-else class="mb-2 mt-0.5 text-gray-200 text-xl">by Unknown</p> <p v-else class="mb-2 mt-0.5 text-gray-200 text-xl">by Unknown</p>
</template> </template>
@@ -124,7 +124,7 @@
</ui-context-menu-dropdown> </ui-context-menu-dropdown>
</div> </div>
<div class="my-4 max-w-2xl"> <div class="my-4 w-full">
<p class="text-base text-gray-100 whitespace-pre-line">{{ description }}</p> <p class="text-base text-gray-100 whitespace-pre-line">{{ description }}</p>
</div> </div>
@@ -160,7 +160,7 @@ export default {
} }
// Include episode downloads for podcasts // Include episode downloads for podcasts
var item = await app.$axios.$get(`/api/items/${params.id}?expanded=1&include=authors,downloads,rssfeed`).catch((error) => { var item = await app.$axios.$get(`/api/items/${params.id}?expanded=1&include=downloads,rssfeed`).catch((error) => {
console.error('Failed', error) console.error('Failed', error)
return false return false
}) })
@@ -682,13 +682,15 @@ export default {
}, },
deleteLibraryItem() { deleteLibraryItem() {
const payload = { const payload = {
message: 'This will delete the library item from the database and your file system. Are you sure?', message: this.$strings.MessageConfirmDeleteLibraryItem,
checkboxLabel: 'Delete from file system. Uncheck to only remove from database.', checkboxLabel: this.$strings.LabelDeleteFromFileSystemCheckbox,
yesButtonText: this.$strings.ButtonDelete, yesButtonText: this.$strings.ButtonDelete,
yesButtonColor: 'error', yesButtonColor: 'error',
checkboxDefaultValue: true, checkboxDefaultValue: !Number(localStorage.getItem('softDeleteDefault') || 0),
callback: (confirmed, hardDelete) => { callback: (confirmed, hardDelete) => {
if (confirmed) { if (confirmed) {
localStorage.setItem('softDeleteDefault', hardDelete ? 0 : 1)
this.$axios this.$axios
.$delete(`/api/items/${this.libraryItemId}?hard=${hardDelete ? 1 : 0}`) .$delete(`/api/items/${this.libraryItemId}?hard=${hardDelete ? 1 : 0}`)
.then(() => { .then(() => {
@@ -761,6 +763,7 @@ export default {
if (this.libraryId) { if (this.libraryId) {
this.$store.commit('libraries/setCurrentLibrary', this.libraryId) this.$store.commit('libraries/setCurrentLibrary', this.libraryId)
} }
this.$eventBus.$on(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
this.$root.socket.on('item_updated', this.libraryItemUpdated) this.$root.socket.on('item_updated', this.libraryItemUpdated)
this.$root.socket.on('rss_feed_open', this.rssFeedOpen) this.$root.socket.on('rss_feed_open', this.rssFeedOpen)
this.$root.socket.on('rss_feed_closed', this.rssFeedClosed) this.$root.socket.on('rss_feed_closed', this.rssFeedClosed)
@@ -769,6 +772,7 @@ export default {
this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished) this.$root.socket.on('episode_download_finished', this.episodeDownloadFinished)
}, },
beforeDestroy() { beforeDestroy() {
this.$eventBus.$off(`${this.libraryItem.id}_updated`, this.libraryItemUpdated)
this.$root.socket.off('item_updated', this.libraryItemUpdated) this.$root.socket.off('item_updated', this.libraryItemUpdated)
this.$root.socket.off('rss_feed_open', this.rssFeedOpen) this.$root.socket.off('rss_feed_open', this.rssFeedOpen)
this.$root.socket.off('rss_feed_closed', this.rssFeedClosed) this.$root.socket.off('rss_feed_closed', this.rssFeedClosed)
+68 -13
View File
@@ -25,9 +25,12 @@
</div> </div>
<div v-else-if="isInit" class="w-full max-w-md px-8 pb-8 pt-4 -mt-40"> <div v-else-if="isInit" class="w-full max-w-md px-8 pb-8 pt-4 -mt-40">
<p class="text-3xl text-white text-center mb-4">{{ $strings.HeaderLogin }}</p> <p class="text-3xl text-white text-center mb-4">{{ $strings.HeaderLogin }}</p>
<div class="w-full h-px bg-white bg-opacity-10 my-4" /> <div class="w-full h-px bg-white bg-opacity-10 my-4" />
<p v-if="error" class="text-error text-center py-2">{{ error }}</p> <p v-if="error" class="text-error text-center py-2">{{ error }}</p>
<form @submit.prevent="submitForm">
<form v-show="login_local" @submit.prevent="submitForm">
<label class="text-xs text-gray-300 uppercase">{{ $strings.LabelUsername }}</label> <label class="text-xs text-gray-300 uppercase">{{ $strings.LabelUsername }}</label>
<ui-text-input v-model="username" :disabled="processing" class="mb-3 w-full" /> <ui-text-input v-model="username" :disabled="processing" class="mb-3 w-full" />
@@ -37,6 +40,14 @@
<ui-btn type="submit" :disabled="processing" color="primary" class="leading-none">{{ processing ? 'Checking...' : $strings.ButtonSubmit }}</ui-btn> <ui-btn type="submit" :disabled="processing" color="primary" class="leading-none">{{ processing ? 'Checking...' : $strings.ButtonSubmit }}</ui-btn>
</div> </div>
</form> </form>
<div v-if="login_local && login_openid" class="w-full h-px bg-white bg-opacity-10 my-4" />
<div class="w-full flex py-3">
<a v-if="login_openid" :href="openidAuthUri" class="w-full abs-btn outline-none rounded-md shadow-md relative border border-gray-600 text-center bg-primary text-white px-8 py-2 leading-none">
{{ openIDButtonText }}
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -60,7 +71,10 @@ export default {
}, },
confirmPassword: '', confirmPassword: '',
ConfigPath: '', ConfigPath: '',
MetadataPath: '' MetadataPath: '',
login_local: true,
login_openid: false,
authFormData: null
} }
}, },
watch: { watch: {
@@ -93,6 +107,12 @@ export default {
computed: { computed: {
user() { user() {
return this.$store.state.user.user return this.$store.state.user.user
},
openidAuthUri() {
return `${process.env.serverUrl}/auth/openid?callback=${location.href.split('?').shift()}`
},
openIDButtonText() {
return this.authFormData?.authOpenIDButtonText || 'Login with OpenId'
} }
}, },
methods: { methods: {
@@ -162,6 +182,7 @@ export default {
else this.error = 'Unknown Error' else this.error = 'Unknown Error'
return false return false
}) })
if (authRes?.error) { if (authRes?.error) {
this.error = authRes.error this.error = authRes.error
} else if (authRes) { } else if (authRes) {
@@ -196,28 +217,62 @@ export default {
this.processing = true this.processing = true
this.$axios this.$axios
.$get('/status') .$get('/status')
.then((res) => { .then((data) => {
this.processing = false this.isInit = data.isInit
this.isInit = res.isInit this.showInitScreen = !data.isInit
this.showInitScreen = !res.isInit this.$setServerLanguageCode(data.language)
this.$setServerLanguageCode(res.language)
if (this.showInitScreen) { if (this.showInitScreen) {
this.ConfigPath = res.ConfigPath || '' this.ConfigPath = data.ConfigPath || ''
this.MetadataPath = res.MetadataPath || '' this.MetadataPath = data.MetadataPath || ''
} else {
this.authFormData = data.authFormData
this.updateLoginVisibility(data.authMethods || [])
} }
}) })
.catch((error) => { .catch((error) => {
console.error('Status check failed', error) console.error('Status check failed', error)
this.processing = false
this.criticalError = 'Status check failed' this.criticalError = 'Status check failed'
}) })
.finally(() => {
this.processing = false
})
},
updateLoginVisibility(authMethods) {
if (this.$route.query?.error) {
this.error = this.$route.query.error
// Remove error query string
const newurl = new URL(location.href)
newurl.searchParams.delete('error')
window.history.replaceState({ path: newurl.href }, '', newurl.href)
}
if (authMethods.includes('local') || !authMethods.length) {
this.login_local = true
} else {
this.login_local = false
}
if (authMethods.includes('openid')) {
// Auto redirect unless query string ?autoLaunch=0
if (this.authFormData?.authOpenIDAutoLaunch && this.$route.query?.autoLaunch !== '0') {
window.location.href = this.openidAuthUri
}
this.login_openid = true
} else {
this.login_openid = false
}
} }
}, },
async mounted() { async mounted() {
if (localStorage.getItem('token')) { if (this.$route.query?.setToken) {
var userfound = await this.checkAuth() localStorage.setItem('token', this.$route.query.setToken)
if (userfound) return // if valid user no need to check status
} }
if (localStorage.getItem('token')) {
if (await this.checkAuth()) return // if valid user no need to check status
}
this.checkStatus() this.checkStatus()
} }
} }
+5
View File
@@ -5,15 +5,20 @@ import { supplant } from './utils'
const defaultCode = 'en-us' const defaultCode = 'en-us'
const languageCodeMap = { const languageCodeMap = {
'cs': { label: 'Čeština', dateFnsLocale: 'cs' },
'da': { label: 'Dansk', dateFnsLocale: 'da' },
'de': { label: 'Deutsch', dateFnsLocale: 'de' }, 'de': { label: 'Deutsch', dateFnsLocale: 'de' },
'en-us': { label: 'English', dateFnsLocale: 'enUS' }, 'en-us': { label: 'English', dateFnsLocale: 'enUS' },
'es': { label: 'Español', dateFnsLocale: 'es' }, 'es': { label: 'Español', dateFnsLocale: 'es' },
'fr': { label: 'Français', dateFnsLocale: 'fr' }, 'fr': { label: 'Français', dateFnsLocale: 'fr' },
'hr': { label: 'Hrvatski', dateFnsLocale: 'hr' }, 'hr': { label: 'Hrvatski', dateFnsLocale: 'hr' },
'it': { label: 'Italiano', dateFnsLocale: 'it' }, 'it': { label: 'Italiano', dateFnsLocale: 'it' },
'lt': { label: 'Lietuvių', dateFnsLocale: 'lt' },
'nl': { label: 'Nederlands', dateFnsLocale: 'nl' }, 'nl': { label: 'Nederlands', dateFnsLocale: 'nl' },
'no': { label: 'Norsk', dateFnsLocale: 'no' },
'pl': { label: 'Polski', dateFnsLocale: 'pl' }, 'pl': { label: 'Polski', dateFnsLocale: 'pl' },
'ru': { label: 'Русский', dateFnsLocale: 'ru' }, 'ru': { label: 'Русский', dateFnsLocale: 'ru' },
'sv': { label: 'Svenska', dateFnsLocale: 'sv' },
'zh-cn': { label: '简体中文 (Simplified Chinese)', dateFnsLocale: 'zhCN' }, 'zh-cn': { label: '简体中文 (Simplified Chinese)', dateFnsLocale: 'zhCN' },
} }
Vue.prototype.$languageCodeOptions = Object.keys(languageCodeMap).map(code => { Vue.prototype.$languageCodeOptions = Object.keys(languageCodeMap).map(code => {
+7 -2
View File
@@ -54,7 +54,7 @@ Vue.prototype.$secondsToTimestamp = (seconds, includeMs = false, alwaysIncludeHo
return `${_hours}:${_minutes.toString().padStart(2, '0')}:${_seconds.toString().padStart(2, '0')}${msString}` return `${_hours}:${_minutes.toString().padStart(2, '0')}:${_seconds.toString().padStart(2, '0')}${msString}`
} }
Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true) => { Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true, showSeconds = true) => {
if (isNaN(seconds) || seconds === null) return '' if (isNaN(seconds) || seconds === null) return ''
seconds = Math.round(seconds) seconds = Math.round(seconds)
@@ -69,11 +69,16 @@ Vue.prototype.$elapsedPrettyExtended = (seconds, useDays = true) => {
hours -= days * 24 hours -= days * 24
} }
// If not showing seconds then round minutes up
if (minutes && seconds && !showSeconds) {
if (seconds >= 30) minutes++
}
const strs = [] const strs = []
if (days) strs.push(`${days}d`) if (days) strs.push(`${days}d`)
if (hours) strs.push(`${hours}h`) if (hours) strs.push(`${hours}h`)
if (minutes) strs.push(`${minutes}m`) if (minutes) strs.push(`${minutes}m`)
if (seconds) strs.push(`${seconds}s`) if (seconds && showSeconds) strs.push(`${seconds}s`)
return strs.join(' ') return strs.join(' ')
} }
+11 -2
View File
@@ -11,6 +11,7 @@ export const state = () => ({
showViewPodcastEpisodeModal: false, showViewPodcastEpisodeModal: false,
showRSSFeedOpenCloseModal: false, showRSSFeedOpenCloseModal: false,
showConfirmPrompt: false, showConfirmPrompt: false,
showRawCoverPreviewModal: false,
confirmPromptOptions: null, confirmPromptOptions: null,
showEditAuthorModal: false, showEditAuthorModal: false,
rssFeedEntity: null, rssFeedEntity: null,
@@ -20,6 +21,7 @@ export const state = () => ({
selectedCollection: null, selectedCollection: null,
selectedAuthor: null, selectedAuthor: null,
selectedMediaItems: [], selectedMediaItems: [],
selectedLibraryItemId: null,
isCasting: false, // Actively casting isCasting: false, // Actively casting
isChromecastInitialized: false, // Script loadeds isChromecastInitialized: false, // Script loadeds
showBatchQuickMatchModal: false, showBatchQuickMatchModal: false,
@@ -80,7 +82,7 @@ export const state = () => ({
}) })
export const getters = { export const getters = {
getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = null) => { getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = null, raw = false) => {
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg` if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
if (!libraryItem) return placeholder if (!libraryItem) return placeholder
const media = libraryItem.media const media = libraryItem.media
@@ -94,7 +96,7 @@ export const getters = {
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
if (process.env.NODE_ENV !== 'production') { // Testing if (process.env.NODE_ENV !== 'production') { // Testing
return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}` return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
} }
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}` return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}`
@@ -156,6 +158,13 @@ export const mutations = {
state.confirmPromptOptions = options state.confirmPromptOptions = options
state.showConfirmPrompt = true state.showConfirmPrompt = true
}, },
setShowRawCoverPreviewModal(state, val) {
state.showRawCoverPreviewModal = val
},
setRawCoverPreviewModal(state, libraryItemId) {
state.selectedLibraryItemId = libraryItemId
state.showRawCoverPreviewModal = true
},
setEditCollection(state, collection) { setEditCollection(state, collection) {
state.selectedCollection = collection state.selectedCollection = collection
state.showEditCollectionModal = true state.showEditCollectionModal = true
+1 -1
View File
@@ -66,7 +66,7 @@ export const getters = {
export const actions = { export const actions = {
updateServerSettings({ commit }, payload) { updateServerSettings({ commit }, payload) {
var updatePayload = { const updatePayload = {
...payload ...payload
} }
return this.$axios.$patch('/api/settings', updatePayload).then((result) => { return this.$axios.$patch('/api/settings', updatePayload).then((result) => {
+4
View File
@@ -234,6 +234,10 @@ export const mutations = {
setNumUserPlaylists(state, numUserPlaylists) { setNumUserPlaylists(state, numUserPlaylists) {
state.numUserPlaylists = numUserPlaylists state.numUserPlaylists = numUserPlaylists
}, },
removeSeriesFromFilterData(state, seriesId) {
if (!seriesId || !state.filterData) return
state.filterData.series = state.filterData.series.filter(se => se.id !== seriesId)
},
updateFilterDataWithItem(state, libraryItem) { updateFilterDataWithItem(state, libraryItem) {
if (!libraryItem || !state.filterData) return if (!libraryItem || !state.filterData) return
if (state.currentLibraryId !== libraryItem.libraryId) return if (state.currentLibraryId !== libraryItem.libraryId) return
+3 -22
View File
@@ -1,5 +1,4 @@
export const state = () => ({ export const state = () => ({
libraryScans: [],
providers: [ providers: [
{ {
text: 'Google Books', text: 'Google Books',
@@ -72,26 +71,8 @@ export const state = () => ({
] ]
}) })
export const getters = { export const getters = {}
getLibraryScan: state => id => {
return state.libraryScans.find(ls => ls.id === id)
}
}
export const actions = { export const actions = {}
} export const mutations = {}
export const mutations = {
addUpdate(state, data) {
var index = state.libraryScans.findIndex(lib => lib.id === data.id)
if (index >= 0) {
state.libraryScans.splice(index, 1, data)
} else {
state.libraryScans.push(data)
}
},
remove(state, data) {
state.libraryScans = state.libraryScans.filter(scan => scan.id !== data.id)
}
}
+5 -1
View File
@@ -6,7 +6,11 @@ export const state = () => ({
export const getters = { export const getters = {
getTasksByLibraryItemId: (state) => (libraryItemId) => { getTasksByLibraryItemId: (state) => (libraryItemId) => {
return state.tasks.filter(t => t.data && t.data.libraryItemId === libraryItemId) return state.tasks.filter(t => t.data?.libraryItemId === libraryItemId)
},
getRunningLibraryScanTask: (state) => (libraryId) => {
const libraryScanActions = ['library-scan', 'library-match-all']
return state.tasks.find(t => libraryScanActions.includes(t.action) && t.data?.libraryId === libraryId && !t.isFinished)
} }
} }
+741
View File
@@ -0,0 +1,741 @@
{
"ButtonAdd": "Přidat",
"ButtonAddChapters": "Přidat kapitoly",
"ButtonAddDevice": "Přidat zařízení",
"ButtonAddLibrary": "Přidat knihovnu",
"ButtonAddPodcasts": "Přidat podcasty",
"ButtonAddUser": "Přidat uživatele",
"ButtonAddYourFirstLibrary": "Vytvořte svou první knihovnu",
"ButtonApply": "Aplikovat",
"ButtonApplyChapters": "Aplikovat kapitoly",
"ButtonAuthors": "Autoři",
"ButtonBrowseForFolder": "Vyhledat složku",
"ButtonCancel": "Zrušit",
"ButtonCancelEncode": "Zrušit kódování",
"ButtonChangeRootPassword": "Změnit 'Root' heslo",
"ButtonCheckAndDownloadNewEpisodes": "Zkontrolovat & stáhnout nové epizody",
"ButtonChooseAFolder": "Vybrat složku",
"ButtonChooseFiles": "Vybrat soubory",
"ButtonClearFilter": "Vymazat filtr",
"ButtonCloseFeed": "Zavřít kanál",
"ButtonCollections": "Kolekce",
"ButtonConfigureScanner": "Konfigurovat Prohledávání",
"ButtonCreate": "Vytvořit",
"ButtonCreateBackup": "Vytvořit zálohu",
"ButtonDelete": "Smazat",
"ButtonDownloadQueue": "Fronta",
"ButtonEdit": "Upravit",
"ButtonEditChapters": "Upravit kapitoly",
"ButtonEditPodcast": "Upravit podcast",
"ButtonForceReScan": "Vynutit opětovné prohledání",
"ButtonFullPath": "Úplná cesta",
"ButtonHide": "Skrýt",
"ButtonHome": "Domů",
"ButtonIssues": "Problémy",
"ButtonLatest": "Nejnovější",
"ButtonLibrary": "Knihovna",
"ButtonLogout": "Odhlásit",
"ButtonLookup": "Vyhledat",
"ButtonManageTracks": "Správa stop",
"ButtonMapChapterTitles": "Mapovat názvy kapitol",
"ButtonMatchAllAuthors": "Spárovat všechny autory",
"ButtonMatchBooks": "Spárovat Knihy",
"ButtonNevermind": "Nevadí",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Otevřít kanál",
"ButtonOpenManager": "Otevřít správce",
"ButtonPlay": "Přehrát",
"ButtonPlaying": "Hraje",
"ButtonPlaylists": "Seznamy skladeb",
"ButtonPurgeAllCache": "Vyčistit veškerou mezipaměť",
"ButtonPurgeItemsCache": "Vyčistit mezipaměť položek",
"ButtonPurgeMediaProgress": "Vyčistit průběh médií",
"ButtonQueueAddItem": "Přidat do fronty",
"ButtonQueueRemoveItem": "Odstranit z fronty",
"ButtonQuickMatch": "Rychlé přiřazení",
"ButtonRead": "Číst",
"ButtonRemove": "Odstranit",
"ButtonRemoveAll": "Odstranit vše",
"ButtonRemoveAllLibraryItems": "Odstranit všechny položky knihovny",
"ButtonRemoveFromContinueListening": "Odstranit z Pokračovat v poslechu",
"ButtonRemoveFromContinueReading": "Odstranit z Pokračovat ve čtení",
"ButtonRemoveSeriesFromContinueSeries": "Odstranit sérii z Pokračovat v sérii",
"ButtonReScan": "Znovu prohledat",
"ButtonReset": "Resetovat",
"ButtonResetToDefault": "Obnovit výchozí",
"ButtonRestore": "Obnovit",
"ButtonSave": "Uložit",
"ButtonSaveAndClose": "Uložit a zavřít",
"ButtonSaveTracklist": "Uložit seznam skladeb",
"ButtonScan": "Prohledat",
"ButtonScanLibrary": "Prohledat Knihovnu",
"ButtonSearch": "Hledat",
"ButtonSelectFolderPath": "Vybrat cestu ke složce",
"ButtonSeries": "Série",
"ButtonSetChaptersFromTracks": "Nastavit kapitoly ze stop",
"ButtonShiftTimes": "Časy posunu",
"ButtonShow": "Zobrazit",
"ButtonStartM4BEncode": "Spustit kódování M4B",
"ButtonStartMetadataEmbed": "Spustit vkládání metadat",
"ButtonSubmit": "Odeslat",
"ButtonTest": "Test",
"ButtonUpload": "Nahrát",
"ButtonUploadBackup": "Nahrát zálohu",
"ButtonUploadCover": "Nahrát obálku",
"ButtonUploadOPMLFile": "Nahrát soubor OPML",
"ButtonUserDelete": "Smazat uživatelský {0}",
"ButtonUserEdit": "Upravit uživatelské {0}",
"ButtonViewAll": "Zobrazit vše",
"ButtonYes": "Ano",
"HeaderAccount": "Účet",
"HeaderAdvanced": "Pokročilé",
"HeaderAppriseNotificationSettings": "Nastavení oznámení Apprise",
"HeaderAudiobookTools": "Nástroje pro správu souborů audioknih",
"HeaderAudioTracks": "Zvukové stopy",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Zálohy",
"HeaderChangePassword": "Změnit heslo",
"HeaderChapters": "Kapitoly",
"HeaderChooseAFolder": "Zvolte složku",
"HeaderCollection": "Kolekce",
"HeaderCollectionItems": "Položky kolekce",
"HeaderCover": "Obálka",
"HeaderCurrentDownloads": "Aktuální stahování",
"HeaderDetails": "Podrobnosti",
"HeaderDownloadQueue": "Fronta stahování",
"HeaderEbookFiles": "Soubory elektronických knih",
"HeaderEmail": "E-mail",
"HeaderEmailSettings": "Nastavení e-mailu",
"HeaderEpisodes": "Epizody",
"HeaderEreaderDevices": "Čtečky elektronických knih",
"HeaderEreaderSettings": "Nastavení čtečky elektronických knih",
"HeaderFiles": "Soubory",
"HeaderFindChapters": "Najít kapitoly",
"HeaderIgnoredFiles": "Ignorované soubory",
"HeaderItemFiles": "Soubory položek",
"HeaderItemMetadataUtils": "Nástroje metadat položek",
"HeaderLastListeningSession": "Poslední poslechová relace",
"HeaderLatestEpisodes": "Poslední epizody",
"HeaderLibraries": "Knihovny",
"HeaderLibraryFiles": "Soubory knihovny",
"HeaderLibraryStats": "Statistiky knihovny",
"HeaderListeningSessions": "Poslechové relace",
"HeaderListeningStats": "Statistiky poslechu",
"HeaderLogin": "Přihlásit",
"HeaderLogs": "Záznamy",
"HeaderManageGenres": "Spravovat žánry",
"HeaderManageTags": "Spravovat štítky",
"HeaderMapDetails": "Podrobnosti mapování",
"HeaderMatch": "Shoda",
"HeaderMetadataOrderOfPrecedence": "Pořadí priorit metadat",
"HeaderMetadataToEmbed": "Metadata k vložení",
"HeaderNewAccount": "Nový účet",
"HeaderNewLibrary": "Nová knihovna",
"HeaderNotifications": "Oznámení",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Otevřít RSS kanál",
"HeaderOtherFiles": "Ostatní soubory",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Oprávnění",
"HeaderPlayerQueue": "Fronta přehrávače",
"HeaderPlaylist": "Seznam skladeb",
"HeaderPlaylistItems": "Položky seznamu přehrávání",
"HeaderPodcastsToAdd": "Podcasty k přidání",
"HeaderPreviewCover": "Náhled obálky",
"HeaderRemoveEpisode": "Odstranit epizodu",
"HeaderRemoveEpisodes": "Odstranit {0} epizody",
"HeaderRSSFeedGeneral": "Podrobnosti o RSS",
"HeaderRSSFeedIsOpen": "Informační kanál RSS je otevřený",
"HeaderRSSFeeds": "RSS kanály",
"HeaderSavedMediaProgress": "Průběh uložených médií",
"HeaderSchedule": "Plán",
"HeaderScheduleLibraryScans": "Naplánovat automatické prohledávání knihoven",
"HeaderSession": "Relace",
"HeaderSetBackupSchedule": "Nastavit plán zálohování",
"HeaderSettings": "Nastavení",
"HeaderSettingsDisplay": "Zobrazit",
"HeaderSettingsExperimental": "Experimentální funkce",
"HeaderSettingsGeneral": "Obecné",
"HeaderSettingsScanner": "Skener",
"HeaderSleepTimer": "Časovač vypnutí",
"HeaderStatsLargestItems": "Největší položky",
"HeaderStatsLongestItems": "Nejdelší položky (hod.)",
"HeaderStatsMinutesListeningChart": "Počet minut poslechu (posledních 7 dní)",
"HeaderStatsRecentSessions": "Poslední relace",
"HeaderStatsTop10Authors": "Top 10 autorů",
"HeaderStatsTop5Genres": "Top 5 žánrů",
"HeaderTableOfContents": "Obsah",
"HeaderTools": "Nástroje",
"HeaderUpdateAccount": "Aktualizovat účet",
"HeaderUpdateAuthor": "Aktualizovat autora",
"HeaderUpdateDetails": "Aktualizovat podrobnosti",
"HeaderUpdateLibrary": "Aktualizovat knihovnu",
"HeaderUsers": "Uživatelé",
"HeaderYourStats": "Vaše statistiky",
"LabelAbridged": "Zkráceno",
"LabelAccountType": "Typ účtu",
"LabelAccountTypeAdmin": "Správce",
"LabelAccountTypeGuest": "Host",
"LabelAccountTypeUser": "Uživatel",
"LabelActivity": "Aktivita",
"LabelAdded": "Přidáno",
"LabelAddedAt": "Přidáno v",
"LabelAddToCollection": "Přidat do kolekce",
"LabelAddToCollectionBatch": "Přidat {0} knihy do kolekce",
"LabelAddToPlaylist": "Přidat do seznamu přehrávání",
"LabelAddToPlaylistBatch": "Přidat {0} položky do seznamu přehrávání",
"LabelAdminUsersOnly": "Pouze administrátoři",
"LabelAll": "Vše",
"LabelAllUsers": "Všichni uživatelé",
"LabelAllUsersExcludingGuests": "Všichni uživatelé kromě hostů",
"LabelAllUsersIncludingGuests": "Všichni uživatelé včetně hostů",
"LabelAlreadyInYourLibrary": "Již ve vaší knihovně",
"LabelAppend": "Připojit",
"LabelAuthor": "Autor",
"LabelAuthorFirstLast": "Autor (jméno a příjmení)",
"LabelAuthorLastFirst": "Autor (příjmení a jméno)",
"LabelAuthors": "Autoři",
"LabelAutoDownloadEpisodes": "Automaticky stahovat epizody",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Zpět k uživateli",
"LabelBackupLocation": "Umístění zálohy",
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
"LabelBackupsEnableAutomaticBackupsHelp": "Zálohy uložené v /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximální velikost zálohy (v GB)",
"LabelBackupsMaxBackupSizeHelp": "Ochrana proti chybné konfiguraci: Zálohování se nezdaří, pokud překročí nastavenou velikost.",
"LabelBackupsNumberToKeep": "Počet záloh, které se mají uchovat",
"LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.",
"LabelBitrate": "Datový tok",
"LabelBooks": "Knihy",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Změnit heslo",
"LabelChannels": "Kanály",
"LabelChapters": "Kapitoly",
"LabelChaptersFound": "Kapitoly nalezeny",
"LabelChapterTitle": "Název kapitoly",
"LabelClickForMoreInfo": "Klikněte pro více informací",
"LabelClosePlayer": "Zavřít přehrávač",
"LabelCodec": "Kodek",
"LabelCollapseSeries": "Sbalit sérii",
"LabelCollection": "Kolekce",
"LabelCollections": "Kolekce",
"LabelComplete": "Dokončeno",
"LabelConfirmPassword": "Potvrdit heslo",
"LabelContinueListening": "Pokračovat v poslechu",
"LabelContinueReading": "Pokračovat ve čtení",
"LabelContinueSeries": "Pokračovat v sérii",
"LabelCover": "Obálka",
"LabelCoverImageURL": "URL obrázku obálky",
"LabelCreatedAt": "Vytvořeno v",
"LabelCronExpression": "Výraz Cronu",
"LabelCurrent": "Aktuální",
"LabelCurrently": "Aktuálně:",
"LabelCustomCronExpression": "Vlastní výraz cronu:",
"LabelDatetime": "Datum a čas",
"LabelDeleteFromFileSystemCheckbox": "Smazat ze souborového systému (zrušte zaškrtnutí pro odstranění pouze z databáze)",
"LabelDescription": "Popis",
"LabelDeselectAll": "Odznačit vše",
"LabelDevice": "Zařízení",
"LabelDeviceInfo": "Informace o zařízení",
"LabelDeviceIsAvailableTo": "Zařízení je dostupné pro...",
"LabelDirectory": "Adresář",
"LabelDiscFromFilename": "Disk z názvu souboru",
"LabelDiscFromMetadata": "Disk z metadat",
"LabelDiscover": "Objevit",
"LabelDownload": "Stáhnout",
"LabelDownloadNEpisodes": "Stáhnout {0} epizody",
"LabelDuration": "Doba trvání",
"LabelDurationFound": "Doba trvání nalezena:",
"LabelEbook": "Elektronická kniha",
"LabelEbooks": "Elektronické knihy",
"LabelEdit": "Upravit",
"LabelEmail": "E-mail",
"LabelEmailSettingsFromAddress": "Z adresy",
"LabelEmailSettingsSecure": "Zabezpečené",
"LabelEmailSettingsSecureHelp": "Pokud je true, připojení bude při připojování k serveru používat TLS. Pokud je false, použije se protokol TLS, pokud server podporuje rozšíření STARTTLS. Ve většině případů nastavte tuto hodnotu na true, pokud se připojujete k portu 465. Pro port 587 nebo 25 ponechte hodnotu false. (z nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Testovací adresa",
"LabelEmbeddedCover": "Vložená obálka",
"LabelEnable": "Povolit",
"LabelEnd": "Konec",
"LabelEpisode": "Epizoda",
"LabelEpisodeTitle": "Název epizody",
"LabelEpisodeType": "Typ epizody",
"LabelExample": "Příklad",
"LabelExplicit": "Explicitní",
"LabelFeedURL": "URL zdroje",
"LabelFile": "Soubor",
"LabelFileBirthtime": "Čas vzniku souboru",
"LabelFileModified": "Soubor změněn",
"LabelFilename": "Název souboru",
"LabelFilterByUser": "Filtrovat podle uživatele",
"LabelFindEpisodes": "Najít epizody",
"LabelFinished": "Dokončeno",
"LabelFolder": "Složka",
"LabelFolders": "Složky",
"LabelFontFamily": "Rodina písem",
"LabelFontScale": "Měřítko písma",
"LabelFormat": "Formát",
"LabelGenre": "Žánr",
"LabelGenres": "Žánry",
"LabelHardDeleteFile": "Trvale smazat soubor",
"LabelHasEbook": "Obsahuje elektronickou knihu",
"LabelHasSupplementaryEbook": "Obsahuje doplňkovou elektronickou knihu",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Hostitel",
"LabelHour": "Hodina",
"LabelIcon": "Ikona",
"LabelImageURLFromTheWeb": "URL obrázku z webu",
"LabelIncludeInTracklist": "Zahrnout do seznamu stop",
"LabelIncomplete": "Neúplné",
"LabelInProgress": "Probíhá",
"LabelInterval": "Interval",
"LabelIntervalCustomDailyWeekly": "Vlastní denně/týdně",
"LabelIntervalEvery12Hours": "Každých 12 hodin",
"LabelIntervalEvery15Minutes": "Každých 15 minut",
"LabelIntervalEvery2Hours": "Každé 2 hodiny",
"LabelIntervalEvery30Minutes": "Každých 30 minut",
"LabelIntervalEvery6Hours": "Každých 6 hodin",
"LabelIntervalEveryDay": "Každý den",
"LabelIntervalEveryHour": "Každou hodinu",
"LabelInvalidParts": "Neplatné části",
"LabelInvert": "Invertovat",
"LabelItem": "Položka",
"LabelLanguage": "Jazyk",
"LabelLanguageDefaultServer": "Výchozí jazyk serveru",
"LabelLastBookAdded": "Poslední kniha přidána",
"LabelLastBookUpdated": "Poslední kniha aktualizována",
"LabelLastSeen": "Naposledy viděno",
"LabelLastTime": "Naposledy",
"LabelLastUpdate": "Poslední aktualizace",
"LabelLayout": "Rozvržení",
"LabelLayoutSinglePage": "Jedna stránka",
"LabelLayoutSplitPage": "Rozdělit stránku",
"LabelLess": "Méně",
"LabelLibrariesAccessibleToUser": "Knihovny přístupné uživateli",
"LabelLibrary": "Knihovna",
"LabelLibraryItem": "Položka knihovny",
"LabelLibraryName": "Název knihovny",
"LabelLimit": "Omezit",
"LabelLineSpacing": "Řádkování",
"LabelListenAgain": "Poslouchat znovu",
"LabelLogLevelDebug": "Ladit",
"LabelLogLevelInfo": "Informace",
"LabelLogLevelWarn": "Varovat",
"LabelLookForNewEpisodesAfterDate": "Hledat nové epizody po tomto datu",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Přehrávač médií",
"LabelMediaType": "Typ média",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Poskytovatel metadat",
"LabelMetaTag": "Metaznačka",
"LabelMetaTags": "Metaznačky",
"LabelMinute": "Minuta",
"LabelMissing": "Chybějící",
"LabelMissingParts": "Chybějící díly",
"LabelMore": "Více",
"LabelMoreInfo": "Více informací",
"LabelName": "Jméno",
"LabelNarrator": "Interpret",
"LabelNarrators": "Interpreti",
"LabelNew": "Nový",
"LabelNewestAuthors": "Nejnovější autoři",
"LabelNewestEpisodes": "Nejnovější epizody",
"LabelNewPassword": "Nové heslo",
"LabelNextBackupDate": "Datum příští zálohy",
"LabelNextScheduledRun": "Další naplánované spuštění",
"LabelNoEpisodesSelected": "Nebyly vybrány žádné epizody",
"LabelNotes": "Poznámky",
"LabelNotFinished": "Nedokončeno",
"LabelNotificationAppriseURL": "URL adresy Apprise",
"LabelNotificationAvailableVariables": "Dostupné proměnné",
"LabelNotificationBodyTemplate": "Šablona těla",
"LabelNotificationEvent": "Událost oznámení",
"LabelNotificationsMaxFailedAttempts": "Maximální počet neúspěšných pokusů",
"LabelNotificationsMaxFailedAttemptsHelp": "Oznámení jsou vypnuta, pokud se jim to nepodaří odeslat",
"LabelNotificationsMaxQueueSize": "Maximální velikost fronty pro oznamovací události",
"LabelNotificationsMaxQueueSizeHelp": "Události jsou omezeny na 1 za sekundu. Události budou ignorovány, pokud je fronta v maximální velikosti. Tím se zabrání spamování oznámení.",
"LabelNotificationTitleTemplate": "Šablona názvu",
"LabelNotStarted": "Nezahájeno",
"LabelNumberOfBooks": "Počet knih",
"LabelNumberOfEpisodes": "Počet epizod",
"LabelOpenRSSFeed": "Otevřít RSS kanál",
"LabelOverwrite": "Přepsat",
"LabelPassword": "Heslo",
"LabelPath": "Cesta",
"LabelPermissionsAccessAllLibraries": "Má přístup ke všem knihovnám",
"LabelPermissionsAccessAllTags": "Má přístup ke všem značkám",
"LabelPermissionsAccessExplicitContent": "Má přístup k explicitnímu obsahu",
"LabelPermissionsDelete": "Může mazat",
"LabelPermissionsDownload": "Může stahovat",
"LabelPermissionsUpdate": "Může aktualizovat",
"LabelPermissionsUpload": "Může nahrávat",
"LabelPhotoPathURL": "Cesta k fotografii/URL",
"LabelPlaylists": "Seznamy skladeb",
"LabelPlayMethod": "Metoda přehrávání",
"LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasty",
"LabelPodcastType": "Typ podcastu",
"LabelPort": "Port",
"LabelPrefixesToIgnore": "Předpony, které se mají ignorovat (nerozlišují se malá a velká písmena)",
"LabelPreventIndexing": "Zabránit indexování vašeho kanálu v adresářích podcastů iTunes a Google",
"LabelPrimaryEbook": "Hlavní e-kniha",
"LabelProgress": "Průběh",
"LabelProvider": "Poskytovatel",
"LabelPubDate": "Datum vydání",
"LabelPublisher": "Vydavatel",
"LabelPublishYear": "Rok vydání",
"LabelRead": "Číst",
"LabelReadAgain": "Číst znovu",
"LabelReadEbookWithoutProgress": "Číst e-knihu bez zachování průběhu",
"LabelRecentlyAdded": "Nedávno přidané",
"LabelRecentSeries": "Nedávné série",
"LabelRecommended": "Doporučeno",
"LabelRegion": "Region",
"LabelReleaseDate": "Datum vydání",
"LabelRemoveCover": "Odstranit obálku",
"LabelRSSFeedCustomOwnerEmail": "Vlastní e-mail vlastníka",
"LabelRSSFeedCustomOwnerName": "Vlastní jméno vlastníka",
"LabelRSSFeedOpen": "Otevření RSS kanálu",
"LabelRSSFeedPreventIndexing": "Zabránit indexování",
"LabelRSSFeedSlug": "RSS kanál Slug",
"LabelRSSFeedURL": "URL RSS kanálu",
"LabelSearchTerm": "Vyhledat termín",
"LabelSearchTitle": "Vyhledat název",
"LabelSearchTitleOrASIN": "Vyhledat název nebo ASIN",
"LabelSeason": "Sezóna",
"LabelSelectAllEpisodes": "Vybrat všechny epizody",
"LabelSelectEpisodesShowing": "Vyberte {0} epizody, které se zobrazují",
"LabelSelectUsers": "Vybrat uživatele",
"LabelSendEbookToDevice": "Odeslat e-knihu do...",
"LabelSequence": "Sekvence",
"LabelSeries": "Série",
"LabelSeriesName": "Název série",
"LabelSeriesProgress": "Průběh série",
"LabelSetEbookAsPrimary": "Nastavit jako primární",
"LabelSetEbookAsSupplementary": "Nastavit jako doplňkové",
"LabelSettingsAudiobooksOnly": "Pouze audioknihy",
"LabelSettingsAudiobooksOnlyHelp": "Povolením tohoto nastavení budou soubory e-knih ignorovány, pokud nejsou ve složce audioknih, v takovém případě budou nastaveny jako doplňkové e-knihy",
"LabelSettingsBookshelfViewHelp": "Skeumorfní design s dřevěnými policemi",
"LabelSettingsChromecastSupport": "Podpora Chromecastu",
"LabelSettingsDateFormat": "Formát data",
"LabelSettingsDisableWatcher": "Zakázat sledování",
"LabelSettingsDisableWatcherForLibrary": "Zakázat sledování složky pro knihovnu",
"LabelSettingsDisableWatcherHelp": "Zakáže automatické přidávání/aktualizaci položek při zjištění změn v souboru. *Vyžaduje restart serveru",
"LabelSettingsEnableWatcher": "Povolit sledování",
"LabelSettingsEnableWatcherForLibrary": "Povolit sledování složky pro knihovnu",
"LabelSettingsEnableWatcherHelp": "Povoluje automatické přidávání/aktualizaci položek, když jsou zjištěny změny souborů. *Vyžaduje restart serveru",
"LabelSettingsExperimentalFeatures": "Experimentální funkce",
"LabelSettingsExperimentalFeaturesHelp": "Funkce ve vývoji, které by mohly využít vaši zpětnou vazbu a pomoc s testováním. Kliknutím otevřete diskuzi na githubu.",
"LabelSettingsFindCovers": "Najít obálky",
"LabelSettingsFindCoversHelp": "Pokud vaše audiokniha nemá vloženou obálku nebo obrázek obálky uvnitř složky, skener se pokusí obálku najít.<br>Poznámka: Tím se prodlouží doba prohledávání",
"LabelSettingsHideSingleBookSeries": "Skrýt sérii s jedinou knihou",
"LabelSettingsHideSingleBookSeriesHelp": "Série, které mají jedinou knihu, budou skryty na stránce série a na domovské stránce.",
"LabelSettingsHomePageBookshelfView": "Domovská stránka používá zobrazení police s knihami",
"LabelSettingsLibraryBookshelfView": "Knihovna používá zobrazení police s knihami",
"LabelSettingsParseSubtitles": "Analzyovat podtitul",
"LabelSettingsParseSubtitlesHelp": "Rozparsovat podtitul z názvů složek audioknih.<br>Podtiul musí být oddělen znakem \" - \"<br>tj. \"Název knihy - Zde Podtitul\" má podtitul \"Zde podtitul\"",
"LabelSettingsPreferMatchedMetadata": "Preferovat spárovaná metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Spárovaná data budou mít při použití funkce Rychlé párování přednost před údaji o položce. Ve výchozím nastavení funkce Rychlé párování pouze doplní chybějící údaje.",
"LabelSettingsSkipMatchingBooksWithASIN": "Přeskočit párování knih, které již mají ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Přeskočit párování knih, které již mají ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignorovat předpony při třídění",
"LabelSettingsSortingIgnorePrefixesHelp": "tj. pro předponu \"the\" název knihy \"Název knihy\" by se třídil jako \"Název knihy, The\"",
"LabelSettingsSquareBookCovers": "Použít čtvercové obálky knih",
"LabelSettingsSquareBookCoversHelp": "Preferovat použití čtvercových obálek před standardními obálkami 1.6:1",
"LabelSettingsStoreCoversWithItem": "Uložit obálky s položkou",
"LabelSettingsStoreCoversWithItemHelp": "Ve výchozím nastavení jsou obálky uloženy v adresáři /metadata/items, povolením tohoto nastavení se obálky uloží do složky položek knihovny. Zůstane zachován pouze jeden soubor s názvem \"cover\"",
"LabelSettingsStoreMetadataWithItem": "Uložit metadata s položkou",
"LabelSettingsStoreMetadataWithItemHelp": "Ve výchozím nastavení jsou soubory metadat uloženy v adresáři /metadata/items, povolením tohoto nastavení budou soubory metadat uloženy ve složkách položek knihovny",
"LabelSettingsTimeFormat": "Formát času",
"LabelShowAll": "Zobrazit vše",
"LabelSize": "Velikost",
"LabelSleepTimer": "Časovač vypnutí",
"LabelSlug": "Slug",
"LabelStart": "Spustit",
"LabelStarted": "Spuštěno",
"LabelStartedAt": "Spuštěno v",
"LabelStartTime": "Čas Spuštění",
"LabelStatsAudioTracks": "Zvukové stopy",
"LabelStatsAuthors": "Autoři",
"LabelStatsBestDay": "Nejlepší den",
"LabelStatsDailyAverage": "Denní průměr",
"LabelStatsDays": "Dny",
"LabelStatsDaysListened": "Dny poslechu",
"LabelStatsHours": "Hodiny",
"LabelStatsInARow": "v řadě",
"LabelStatsItemsFinished": "Dokončené Položky",
"LabelStatsItemsInLibrary": "Položky v knihovně",
"LabelStatsMinutes": "minut",
"LabelStatsMinutesListening": "Minuty poslechu",
"LabelStatsOverallDays": "Celkový počet dní",
"LabelStatsOverallHours": "Celkový počet hodin",
"LabelStatsWeekListening": "Týdenní poslech",
"LabelSubtitle": "Podtitul",
"LabelSupportedFileTypes": "Podporované typy souborů",
"LabelTag": "Značka",
"LabelTags": "Značky",
"LabelTagsAccessibleToUser": "Značky přístupné uživateli",
"LabelTagsNotAccessibleToUser": "Značky nepřístupné uživateli",
"LabelTasks": "Spuštěné Úlohy",
"LabelTheme": "Téma",
"LabelThemeDark": "Tmavé",
"LabelThemeLight": "Světlé",
"LabelTimeBase": "Časová základna",
"LabelTimeListened": "Čas poslechu",
"LabelTimeListenedToday": "Čas poslechu dnes",
"LabelTimeRemaining": "{0} zbývá",
"LabelTimeToShift": "Čas posunu v sekundách",
"LabelTitle": "Název",
"LabelToolsEmbedMetadata": "Vložit metadata",
"LabelToolsEmbedMetadataDescription": "Vložit metadata do zvukových souborů včetně obálky a kapitol.",
"LabelToolsMakeM4b": "Vytvořit soubor audioknihy M4B",
"LabelToolsMakeM4bDescription": "Vygenerovat soubor audioknihy M4B s vloženými metadaty, obálkou a kapitolami.",
"LabelToolsSplitM4b": "Rozdělit M4B na MP3",
"LabelToolsSplitM4bDescription": "Vytvořit soubory MP3 z M4B rozděleného podle kapitol s vloženými metadaty, obrázku obálky a kapitol.",
"LabelTotalDuration": "Celková doba trvání",
"LabelTotalTimeListened": "Celkový čas poslechu",
"LabelTrackFromFilename": "Stopa z názvu souboru",
"LabelTrackFromMetadata": "Stopa z metadat",
"LabelTracks": "Stopy",
"LabelTracksMultiTrack": "Více stop",
"LabelTracksNone": "Žádné stopy",
"LabelTracksSingleTrack": "Jedna stopa",
"LabelType": "Typ",
"LabelUnabridged": "Nezkráceno",
"LabelUnknown": "Neznámý",
"LabelUpdateCover": "Aktualizovat obálku",
"LabelUpdateCoverHelp": "Povolit přepsání existujících obálek pro vybrané knihy, pokud je nalezena shoda",
"LabelUpdatedAt": "Aktualizováno v",
"LabelUpdateDetails": "Aktualizovat podrobnosti",
"LabelUpdateDetailsHelp": "Povolit přepsání existujících údajů o vybraných knihách, když je nalezena shoda",
"LabelUploaderDragAndDrop": "Přetáhnout soubory nebo složky",
"LabelUploaderDropFiles": "Odstranit soubory",
"LabelUseChapterTrack": "Použít stopu kapitoly",
"LabelUseFullTrack": "Použít celou stopu",
"LabelUser": "Uživatel",
"LabelUsername": "Uživatelské jméno",
"LabelValue": "Hodnota",
"LabelVersion": "Verze",
"LabelViewBookmarks": "Zobrazit záložky",
"LabelViewChapters": "Zobrazit kapitoly",
"LabelViewQueue": "Zobrazit frontu přehrávače",
"LabelVolume": "Hlasitost",
"LabelWeekdaysToRun": "Dny v týdnu ke spuštění",
"LabelYourAudiobookDuration": "Doba trvání vaší audioknihy",
"LabelYourBookmarks": "Vaše záložky",
"LabelYourPlaylists": "Vaše seznamy přehrávání",
"LabelYourProgress": "Váš pokrok",
"MessageAddToPlayerQueue": "Přidat do fronty přehrávače",
"MessageAppriseDescription": "Abyste mohli používat tuto funkci, musíte mít spuštěnou instanci <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> nebo API, které bude zpracovávat stejné požadavky. <br />Adresa URL API Apprise by měla být úplná URL cesta pro odeslání oznámení, např. pokud je vaše instance API obsluhována na adrese <code>http://192.168.1.1:8337</code> pak byste měli zadat <code>http://192.168.1.1:8337/notify</code>.",
"MessageBackupsDescription": "Zálohy zahrnují uživatele, průběh uživatele, podrobnosti o položkách knihovny, nastavení serveru a obrázky uložené v <code>/metadata/items</code> a <code>/metadata/authors</code>. Zálohy <strong>ne</strong> zahrnují všechny soubory uložené ve složkách knihovny.",
"MessageBatchQuickMatchDescription": "Rychlá párování se pokusí přidat chybějící obálky a metadata pro vybrané položky. Povolením níže uvedených možností umožníte funkci Rychlé párování přepsat stávající obálky a/nebo metadata.",
"MessageBookshelfNoCollections": "Ještě jste nevytvořili žádnou sbírku",
"MessageBookshelfNoResultsForFilter": "Filtr \"{0}: {1}\"",
"MessageBookshelfNoRSSFeeds": "Nejsou otevřeny žádné RSS kanály",
"MessageBookshelfNoSeries": "Nemáte žádnou sérii",
"MessageChapterEndIsAfter": "Konec kapitoly přesahuje konec audioknihy",
"MessageChapterErrorFirstNotZero": "První kapitola musí začínat na 0",
"MessageChapterErrorStartGteDuration": "Neplatný čas začátku, musí být kratší než doba trvání audioknihy",
"MessageChapterErrorStartLtPrev": "Neplatný čas začátku, musí být větší nebo roven času začátku předchozí kapitoly",
"MessageChapterStartIsAfter": "Začátek kapitoly přesahuje konec audioknihy",
"MessageCheckingCron": "Kontrola cronu...",
"MessageConfirmCloseFeed": "Opravdu chcete zavřít tento kanál?",
"MessageConfirmDeleteBackup": "Opravdu chcete smazat zálohu pro {0}?",
"MessageConfirmDeleteFile": "Tento krok smaže soubor ze souborového systému. Jsi si jisti?",
"MessageConfirmDeleteLibrary": "Opravdu chcete trvale smazat knihovnu \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "Tento krok odstraní položku knihovny z databáze a vašeho souborového systému. Jste si jisti?",
"MessageConfirmDeleteLibraryItems": "Tímto smažete {0} položkek knihovny z databáze a vašeho souborového systému. Jsi si jisti?",
"MessageConfirmDeleteSession": "Opravdu chcete smazat tuto relaci?",
"MessageConfirmForceReScan": "Opravdu chcete vynutit opětovné prohledání?",
"MessageConfirmMarkAllEpisodesFinished": "Opravdu chcete označit všechny epizody jako dokončené?",
"MessageConfirmMarkAllEpisodesNotFinished": "Opravdu chcete označit všechny epizody jako nedokončené?",
"MessageConfirmMarkSeriesFinished": "Opravdu chcete označit všechny knihy z této série jako dokončené?",
"MessageConfirmMarkSeriesNotFinished": "Opravdu chcete označit všechny knihy z této série jako nedokončené?",
"MessageConfirmQuickEmbed": "Varování! Rychlé vložení nezálohuje vaše zvukové soubory. Ujistěte se, že máte zálohu zvukových souborů. <br><br>Chcete pokračovat?",
"MessageConfirmRemoveAllChapters": "Opravdu chcete odstranit všechny kapitoly?",
"MessageConfirmRemoveAuthor": "Opravdu chcete odstranit autora \"{0}\"?",
"MessageConfirmRemoveCollection": "Opravdu chcete odstranit kolekci \"{0}\"?",
"MessageConfirmRemoveEpisode": "Opravdu chcete odstranit epizodu \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Opravdu chcete odstranit {0} epizody?",
"MessageConfirmRemoveNarrator": "Opravdu chcete odebrat předčítání \"{0}\"?",
"MessageConfirmRemovePlaylist": "Opravdu chcete odstranit svůj playlist \"{0}\"?",
"MessageConfirmRenameGenre": "Opravdu chcete přejmenovat žánr \"{0}\" na \"{1}\" pro všechny položky?",
"MessageConfirmRenameGenreMergeNote": "Poznámka: Tento žánr již existuje, takže budou sloučeny.",
"MessageConfirmRenameGenreWarning": "Varování! Podobný žánr s jiným obalem již existuje \"{0}\".",
"MessageConfirmRenameTag": "Opravdu chcete přejmenovat tag \"{0}\" na \"{1}\" pro všechny položky?",
"MessageConfirmRenameTagMergeNote": "Poznámka: Tato značka již existuje, takže budou sloučeny.",
"MessageConfirmRenameTagWarning": "Varování! Podobná značka s jinými velkými a malými písmeny již existuje \"{0}\".",
"MessageConfirmReScanLibraryItems": "Opravdu chcete znovu prohledat {0} položky?",
"MessageConfirmSendEbookToDevice": "Opravdu chcete odeslat e-knihu {0} {1}\" do zařízení \"{2}\"?",
"MessageDownloadingEpisode": "Stahuji epizodu",
"MessageDragFilesIntoTrackOrder": "Přetáhněte soubory do správného pořadí stop",
"MessageEmbedFinished": "Vložení dokončeno!",
"MessageEpisodesQueuedForDownload": "{0} epizody zařazené do fronty ke stažení",
"MessageFeedURLWillBe": "URL zdroje bude {0}",
"MessageFetching": "Stahování...",
"MessageForceReScanDescription": "znovu prohledá všechny soubory jako při novém skenování. ID3 tagy zvukových souborů OPF soubory a textové soubory budou skenovány jako nové.",
"MessageImportantNotice": "Důležité upozornění!",
"MessageInsertChapterBelow": "Vložit kapitolu níže",
"MessageItemsSelected": "{0} vybraných položek",
"MessageItemsUpdated": "{0} položky byly aktualizovány",
"MessageJoinUsOn": "Přidejte se k nám",
"MessageListeningSessionsInTheLastYear": "{0} poslechových relací za poslední rok",
"MessageLoading": "Načítá se...",
"MessageLoadingFolders": "Načítám složky...",
"MessageM4BFailed": "M4B se nezdařil!",
"MessageM4BFinished": "M4B dokončen!",
"MessageMapChapterTitles": "Mapování názvů kapitol ke stávajícím kapitolám audioknihy bez úpravy časových razítek",
"MessageMarkAllEpisodesFinished": "Označit všechny epizody za dokončené",
"MessageMarkAllEpisodesNotFinished": "Označit všechny epizody jako nedokončené",
"MessageMarkAsFinished": "Označit jako dokončené",
"MessageMarkAsNotFinished": "Označit jako nedokončené",
"MessageMatchBooksDescription": "pokusí se spárovat knihy v knihovně s knihou od vybraného vyhledávače a vyplnit prázdné údaje a obálku. Nepřepisuje detaily.",
"MessageNoAudioTracks": "Žádné zvukové stopy",
"MessageNoAuthors": "Žádní autoři",
"MessageNoBackups": "Žádné zálohy",
"MessageNoBookmarks": "Žádné záložky",
"MessageNoChapters": "Žádné kapitoly",
"MessageNoCollections": "Žádné kolekce",
"MessageNoCoversFound": "Nebyly nalezeny žádné obálky",
"MessageNoDescription": "Bez popisu",
"MessageNoDownloadsInProgress": "Momentálně neprobíhá žádné stahování",
"MessageNoDownloadsQueued": "Žádné stahování ve frontě",
"MessageNoEpisodeMatchesFound": "Nebyly nalezeny žádné odpovídající epizody",
"MessageNoEpisodes": "Žádné epizody",
"MessageNoFoldersAvailable": "Nejsou k dispozici žádné složky",
"MessageNoGenres": "Žádné žánry",
"MessageNoIssues": "Žádné výtisk",
"MessageNoItems": "Žádné položky",
"MessageNoItemsFound": "Nebyly nalezeny žádné položky",
"MessageNoListeningSessions": "Žádné poslechové relace",
"MessageNoLogs": "Žádné protokoly",
"MessageNoMediaProgress": "Žádný průběh médií",
"MessageNoNotifications": "Žádná oznámení",
"MessageNoPodcastsFound": "Nebyly nalezeny žádné podcasty",
"MessageNoResults": "Žádné výsledky",
"MessageNoSearchResultsFor": "Nebyly nalezeny žádné výsledky hledání pro \"{0}\"",
"MessageNoSeries": "Žádné série",
"MessageNoTags": "Žádné značky",
"MessageNoTasksRunning": "Nejsou spuštěny žádné úlohy",
"MessageNotYetImplemented": "Ještě není implementováno",
"MessageNoUpdateNecessary": "Není nutná žádná aktualizace",
"MessageNoUpdatesWereNecessary": "Nebyly nutné žádné aktualizace",
"MessageNoUserPlaylists": "Nemáte žádné seznamy skladeb",
"MessageOr": "nebo",
"MessagePauseChapter": "Pozastavit přehrávání kapitoly",
"MessagePlayChapter": "Poslechnout si začátek kapitoly",
"MessagePlaylistCreateFromCollection": "Vytvořit seznam skladeb z kolekce",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nemá žádnou adresu URL kanálu RSS, kterou by mohl použít pro porovnávání",
"MessageQuickMatchDescription": "Vyplňte prázdné detaily položky a obálku prvním výsledkem shody z '{0}'. Nepřepisuje podrobnosti, pokud není povoleno nastavení serveru \"Preferovat párování metadata\".",
"MessageRemoveChapter": "Odstranit kapitolu",
"MessageRemoveEpisodes": "Odstranit {0} epizodu",
"MessageRemoveFromPlayerQueue": "Odstranit z fronty přehrávače",
"MessageRemoveUserWarning": "Opravdu chcete trvale smazat uživatele \"{0}\"?",
"MessageReportBugsAndContribute": "Hlásit chyby, žádat o funkce a přispívat",
"MessageResetChaptersConfirm": "Opravdu chcete resetovat kapitoly a vrátit zpět provedené změny?",
"MessageRestoreBackupConfirm": "Opravdu chcete obnovit zálohu vytvořenou dne?",
"MessageRestoreBackupWarning": "Obnovení zálohy přepíše celou databázi umístěnou v /config a obálku obrázků v /metadata/items & /metadata/authors.<br /><br />Backups nezmění žádné soubory ve složkách knihovny. Pokud jste povolili nastavení serveru pro ukládání obrázků obalu a metadat do složek knihovny, nebudou zálohovány ani přepsány.<br /><br />Všichni klienti používající váš server budou automaticky obnoveni.",
"MessageSearchResultsFor": "Výsledky hledání pro",
"MessageServerCouldNotBeReached": "Server je nedostupný",
"MessageSetChaptersFromTracksDescription": "Nastavit kapitoly jako kapitolu a název kapitoly jako název zvukového souboru",
"MessageStartPlaybackAtTime": "Spustit přehrávání pro \"{0}\" v {1}?",
"MessageThinking": "Přemýšlení...",
"MessageUploaderItemFailed": "Nahrávání se nezdařilo",
"MessageUploaderItemSuccess": "Nahráno bylo úspěšně!",
"MessageUploading": "Odesílám...",
"MessageValidCronExpression": "Platný výraz cronu",
"MessageWatcherIsDisabledGlobally": "Hlídač je globálně zakázán v nastavení serveru",
"MessageXLibraryIsEmpty": "{0} knihovna je prázdná!",
"MessageYourAudiobookDurationIsLonger": "Doba trvání audioknihy je delší než nalezená délka",
"MessageYourAudiobookDurationIsShorter": "Délka audioknihy je kratší, než byla nalezena.",
"NoteChangeRootPassword": "Uživatel root je jediný uživatel, který může mít prázdné heslo",
"NoteChapterEditorTimes": "Poznámka: Čas začátku první kapitoly musí zůstat v 0:00 a čas začátku poslední kapitoly nesmí překročit tuto dobu trvání audioknihy.",
"NoteFolderPicker": "Poznámka: složky, které jsou již namapovány, nebudou zobrazeny",
"NoteFolderPickerDebian": "Poznámka: Výběr složek pro instalaci debianu není plně implementován. Cestu ke své knihovně byste měli zadat přímo.",
"NoteRSSFeedPodcastAppsHttps": "Upozornění: Většina aplikací pro podcasty bude vyžadovat, aby adresa URL kanálu RSS používala protokol HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Upozornění: 1 nebo více epizod nemá datum vydání. Některé podcastové aplikace to vyžadují.",
"NoteUploaderFoldersWithMediaFiles": "Se složkami s multimediálními soubory bude zacházeno jako se samostatnými položkami knihovny.",
"NoteUploaderOnlyAudioFiles": "Pokud nahráváte pouze zvukové soubory, bude s každým zvukovým souborem zacházeno jako se samostatnou audioknihou.",
"NoteUploaderUnsupportedFiles": "Nepodporované soubory jsou ignorovány. Při výběru nebo přetažení složky jsou ostatní soubory, které nejsou ve složce položek, ignorovány.",
"PlaceholderNewCollection": "Nový název kolekce",
"PlaceholderNewFolderPath": "Nová cesta ke složce",
"PlaceholderNewPlaylist": "Nový název seznamu přehrávání",
"PlaceholderSearch": "Hledat..",
"PlaceholderSearchEpisode": "Hledat epizodu..",
"ToastAccountUpdateFailed": "Aktualizace účtu se nezdařila",
"ToastAccountUpdateSuccess": "Účet aktualizován",
"ToastAuthorImageRemoveFailed": "Nepodařilo se odstranit obrázek",
"ToastAuthorImageRemoveSuccess": "Obrázek autora odstraněn",
"ToastAuthorUpdateFailed": "Aktualizace autora se nezdařila",
"ToastAuthorUpdateMerged": "Autor sloučen",
"ToastAuthorUpdateSuccess": "Autor aktualizován",
"ToastAuthorUpdateSuccessNoImageFound": "Autor aktualizován (nebyl nalezen žádný obrázek)",
"ToastBackupCreateFailed": "Vytvoření zálohy se nezdařilo",
"ToastBackupCreateSuccess": "Záloha vytvořena",
"ToastBackupDeleteFailed": "Nepodařilo se smazat zálohu",
"ToastBackupDeleteSuccess": "Záloha smazána",
"ToastBackupRestoreFailed": "Nepodařilo se obnovit zálohu",
"ToastBackupUploadFailed": "Nepodařilo se nahrát zálohu",
"ToastBackupUploadSuccess": "Záloha nahrána",
"ToastBatchUpdateFailed": "Dávková aktualizace se nezdařila",
"ToastBatchUpdateSuccess": "Dávková aktualizace proběhla úspěšně",
"ToastBookmarkCreateFailed": "Vytvoření záložky se nezdařilo",
"ToastBookmarkCreateSuccess": "Přidána záložka",
"ToastBookmarkRemoveFailed": "Nepodařilo se odstranit záložku",
"ToastBookmarkRemoveSuccess": "Záložka odstraněna",
"ToastBookmarkUpdateFailed": "Aktualizace záložky se nezdařila",
"ToastBookmarkUpdateSuccess": "Záložka aktualizována",
"ToastChaptersHaveErrors": "Kapitoly obsahují chyby",
"ToastChaptersMustHaveTitles": "Kapitoly musí mít názvy",
"ToastCollectionItemsRemoveFailed": "Nepodařilo se odstranit položky z kolekce",
"ToastCollectionItemsRemoveSuccess": "Položky odstraněny z kolekce",
"ToastCollectionRemoveFailed": "Nepodařilo se odstranit kolekci",
"ToastCollectionRemoveSuccess": "Kolekce odstraněna",
"ToastCollectionUpdateFailed": "Aktualizace kolekce se nezdařila",
"ToastCollectionUpdateSuccess": "Kolekce aktualizována",
"ToastItemCoverUpdateFailed": "Aktualizace obálky se nezdařila",
"ToastItemCoverUpdateSuccess": "Obálka předmětu byl aktualizována",
"ToastItemDetailsUpdateFailed": "Nepodařilo se aktualizovat podrobnosti o položce",
"ToastItemDetailsUpdateSuccess": "Podrobnosti o položce byly aktualizovány",
"ToastItemDetailsUpdateUnneeded": "Podrobnosti o položce nejsou potřeba aktualizovat",
"ToastItemMarkedAsFinishedFailed": "Nepodařilo se označit jako dokončené",
"ToastItemMarkedAsFinishedSuccess": "Položka označena jako dokončená",
"ToastItemMarkedAsNotFinishedFailed": "Nepodařilo se označit jako nedokončené",
"ToastItemMarkedAsNotFinishedSuccess": "Položka označena jako nedokončená",
"ToastLibraryCreateFailed": "Vytvoření knihovny se nezdařilo",
"ToastLibraryCreateSuccess": "Knihovna \"{0}\" vytvořena",
"ToastLibraryDeleteFailed": "Nepodařilo se smazat knihovnu",
"ToastLibraryDeleteSuccess": "Knihovna smazána",
"ToastLibraryScanFailedToStart": "Nepodařilo se spustit kontrolu",
"ToastLibraryScanStarted": "Kontrola knihovny spuštěna",
"ToastLibraryUpdateFailed": "Aktualizace knihovny se nezdařila",
"ToastLibraryUpdateSuccess": "Knihovna \"{0}\" aktualizována",
"ToastPlaylistCreateFailed": "Vytvoření seznamu přehrávání se nezdařilo",
"ToastPlaylistCreateSuccess": "Seznam přehrávání vytvořen",
"ToastPlaylistRemoveFailed": "Nepodařilo se odstranit seznamu přehrávání",
"ToastPlaylistRemoveSuccess": "Seznam přehrávání odstraněn",
"ToastPlaylistUpdateFailed": "Aktualizace seznamu přehrávání se nezdařila",
"ToastPlaylistUpdateSuccess": "Seznam přehrávání aktualizován",
"ToastPodcastCreateFailed": "Vytvoření podcastu se nezdařilo",
"ToastPodcastCreateSuccess": "Podcast byl úspěšně vytvořen",
"ToastRemoveItemFromCollectionFailed": "Nepodařilo se odebrat položku z kolekce",
"ToastRemoveItemFromCollectionSuccess": "Položka odstraněna z kolekce",
"ToastRSSFeedCloseFailed": "Nepodařilo se zavřít RSS kanál",
"ToastRSSFeedCloseSuccess": "RSS kanál uzavřen",
"ToastSendEbookToDeviceFailed": "Odeslání e-knihy do zařízení se nezdařilo",
"ToastSendEbookToDeviceSuccess": "E-kniha odeslána do zařízení \"{0}\"",
"ToastSeriesUpdateFailed": "Aktualizace série se nezdařila",
"ToastSeriesUpdateSuccess": "Aktualizace série byla úspěšná",
"ToastSessionDeleteFailed": "Nepodařilo se smazat relaci",
"ToastSessionDeleteSuccess": "Relace smazána",
"ToastSocketConnected": "Socket připojen",
"ToastSocketDisconnected": "Socket odpojen",
"ToastSocketFailedToConnect": "Socket se nepodařilo připojit",
"ToastUserDeleteFailed": "Nepodařilo se smazat uživatele",
"ToastUserDeleteSuccess": "Uživatel smazán"
}
+741
View File
@@ -0,0 +1,741 @@
{
"ButtonAdd": "Tilføj",
"ButtonAddChapters": "Tilføj kapitler",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Tilføj podcasts",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Tilføj din første bibliotek",
"ButtonApply": "Anvend",
"ButtonApplyChapters": "Anvend kapitler",
"ButtonAuthors": "Forfattere",
"ButtonBrowseForFolder": "Gennemse mappe",
"ButtonCancel": "Annuller",
"ButtonCancelEncode": "Annuller kodning",
"ButtonChangeRootPassword": "Ændr rodadgangskode",
"ButtonCheckAndDownloadNewEpisodes": "Tjek og download nye episoder",
"ButtonChooseAFolder": "Vælg en mappe",
"ButtonChooseFiles": "Vælg filer",
"ButtonClearFilter": "Ryd filter",
"ButtonCloseFeed": "Luk feed",
"ButtonCollections": "Samlinger",
"ButtonConfigureScanner": "Konfigurer scanner",
"ButtonCreate": "Opret",
"ButtonCreateBackup": "Opret sikkerhedskopi",
"ButtonDelete": "Slet",
"ButtonDownloadQueue": "Kø",
"ButtonEdit": "Rediger",
"ButtonEditChapters": "Rediger kapitler",
"ButtonEditPodcast": "Rediger podcast",
"ButtonForceReScan": "Tvungen genindlæsning",
"ButtonFullPath": "Fuld sti",
"ButtonHide": "Skjul",
"ButtonHome": "Hjem",
"ButtonIssues": "Problemer",
"ButtonLatest": "Seneste",
"ButtonLibrary": "Bibliotek",
"ButtonLogout": "Log ud",
"ButtonLookup": "Slå op",
"ButtonManageTracks": "Administrer spor",
"ButtonMapChapterTitles": "Kortlæg kapiteloverskrifter",
"ButtonMatchAllAuthors": "Match alle forfattere",
"ButtonMatchBooks": "Match bøger",
"ButtonNevermind": "Glem det",
"ButtonOk": "OK",
"ButtonOpenFeed": "Åbn feed",
"ButtonOpenManager": "Åbn manager",
"ButtonPlay": "Afspil",
"ButtonPlaying": "Afspiller",
"ButtonPlaylists": "Afspilningslister",
"ButtonPurgeAllCache": "Ryd al cache",
"ButtonPurgeItemsCache": "Ryd elementcache",
"ButtonPurgeMediaProgress": "Ryd Medieforløb",
"ButtonQueueAddItem": "Tilføj til kø",
"ButtonQueueRemoveItem": "Fjern fra kø",
"ButtonQuickMatch": "Hurtig Match",
"ButtonRead": "Læs",
"ButtonRemove": "Fjern",
"ButtonRemoveAll": "Fjern Alle",
"ButtonRemoveAllLibraryItems": "Fjern Alle Bibliotekselementer",
"ButtonRemoveFromContinueListening": "Fjern fra Fortsæt Lytning",
"ButtonRemoveFromContinueReading": "Fjern fra Fortsæt Læsning",
"ButtonRemoveSeriesFromContinueSeries": "Fjern Serie fra Fortsæt Serie",
"ButtonReScan": "Gen-scan",
"ButtonReset": "Nulstil",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Gendan",
"ButtonSave": "Gem",
"ButtonSaveAndClose": "Gem & Luk",
"ButtonSaveTracklist": "Gem Sporliste",
"ButtonScan": "Scan",
"ButtonScanLibrary": "Scan Bibliotek",
"ButtonSearch": "Søg",
"ButtonSelectFolderPath": "Vælg Mappen Sti",
"ButtonSeries": "Serie",
"ButtonSetChaptersFromTracks": "Sæt kapitler fra spor",
"ButtonShiftTimes": "Skift Tider",
"ButtonShow": "Vis",
"ButtonStartM4BEncode": "Start M4B Kode",
"ButtonStartMetadataEmbed": "Start Metadata Indlejring",
"ButtonSubmit": "Send",
"ButtonTest": "Test",
"ButtonUpload": "Upload",
"ButtonUploadBackup": "Upload Backup",
"ButtonUploadCover": "Upload Omslag",
"ButtonUploadOPMLFile": "Upload OPML Fil",
"ButtonUserDelete": "Slet bruger {0}",
"ButtonUserEdit": "Rediger bruger {0}",
"ButtonViewAll": "Vis Alle",
"ButtonYes": "Ja",
"HeaderAccount": "Konto",
"HeaderAdvanced": "Avanceret",
"HeaderAppriseNotificationSettings": "Apprise Notifikationsindstillinger",
"HeaderAudiobookTools": "Audiobog Filhåndteringsværktøjer",
"HeaderAudioTracks": "Lydspor",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Sikkerhedskopier",
"HeaderChangePassword": "Skift Adgangskode",
"HeaderChapters": "Kapitler",
"HeaderChooseAFolder": "Vælg en Mappe",
"HeaderCollection": "Samling",
"HeaderCollectionItems": "Samlingselementer",
"HeaderCover": "Omslag",
"HeaderCurrentDownloads": "Nuværende Downloads",
"HeaderDetails": "Detaljer",
"HeaderDownloadQueue": "Download Kø",
"HeaderEbookFiles": "E-bogsfiler",
"HeaderEmail": "Email",
"HeaderEmailSettings": "Email Indstillinger",
"HeaderEpisodes": "Episoder",
"HeaderEreaderDevices": "E-læser Enheder",
"HeaderEreaderSettings": "E-læser Indstillinger",
"HeaderFiles": "Filer",
"HeaderFindChapters": "Find Kapitler",
"HeaderIgnoredFiles": "Ignorerede Filer",
"HeaderItemFiles": "Emnefiler",
"HeaderItemMetadataUtils": "Emne Metadata Værktøjer",
"HeaderLastListeningSession": "Seneste Lyttesession",
"HeaderLatestEpisodes": "Seneste episoder",
"HeaderLibraries": "Biblioteker",
"HeaderLibraryFiles": "Biblioteksfiler",
"HeaderLibraryStats": "Biblioteksstatistik",
"HeaderListeningSessions": "Lyttesessioner",
"HeaderListeningStats": "Lyttestatistik",
"HeaderLogin": "Log ind",
"HeaderLogs": "Logs",
"HeaderManageGenres": "Administrer Genrer",
"HeaderManageTags": "Administrer Tags",
"HeaderMapDetails": "Kort Detaljer",
"HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadata til indlejring",
"HeaderNewAccount": "Ny Konto",
"HeaderNewLibrary": "Nyt Bibliotek",
"HeaderNotifications": "Meddelelser",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Åbn RSS Feed",
"HeaderOtherFiles": "Andre Filer",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Tilladelser",
"HeaderPlayerQueue": "Afspilningskø",
"HeaderPlaylist": "Afspilningsliste",
"HeaderPlaylistItems": "Afspilningsliste Elementer",
"HeaderPodcastsToAdd": "Podcasts til Tilføjelse",
"HeaderPreviewCover": "Forhåndsvis Omslag",
"HeaderRemoveEpisode": "Fjern Episode",
"HeaderRemoveEpisodes": "Fjern {0} Episoder",
"HeaderRSSFeedGeneral": "RSS Detaljer",
"HeaderRSSFeedIsOpen": "RSS Feed er Åben",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Gemt Medieforløb",
"HeaderSchedule": "Planlæg",
"HeaderScheduleLibraryScans": "Planlæg Automatiske Biblioteksscanninger",
"HeaderSession": "Session",
"HeaderSetBackupSchedule": "Indstil Sikkerhedskopieringsplan",
"HeaderSettings": "Indstillinger",
"HeaderSettingsDisplay": "Skærm",
"HeaderSettingsExperimental": "Eksperimentelle Funktioner",
"HeaderSettingsGeneral": "Generelt",
"HeaderSettingsScanner": "Scanner",
"HeaderSleepTimer": "Søvntimer",
"HeaderStatsLargestItems": "Største Elementer",
"HeaderStatsLongestItems": "Længste Elementer (timer)",
"HeaderStatsMinutesListeningChart": "Minutter Lyttet (sidste 7 dage)",
"HeaderStatsRecentSessions": "Seneste Sessions",
"HeaderStatsTop10Authors": "Top 10 Forfattere",
"HeaderStatsTop5Genres": "Top 5 Genrer",
"HeaderTableOfContents": "Indholdsfortegnelse",
"HeaderTools": "Værktøjer",
"HeaderUpdateAccount": "Opdater Konto",
"HeaderUpdateAuthor": "Opdater Forfatter",
"HeaderUpdateDetails": "Opdater Detaljer",
"HeaderUpdateLibrary": "Opdater Bibliotek",
"HeaderUsers": "Brugere",
"HeaderYourStats": "Dine Statistikker",
"LabelAbridged": "Abridged",
"LabelAccountType": "Kontotype",
"LabelAccountTypeAdmin": "Administrator",
"LabelAccountTypeGuest": "Gæst",
"LabelAccountTypeUser": "Bruger",
"LabelActivity": "Aktivitet",
"LabelAdded": "Tilføjet",
"LabelAddedAt": "Tilføjet Kl.",
"LabelAddToCollection": "Tilføj til Samling",
"LabelAddToCollectionBatch": "Tilføj {0} Bøger til Samling",
"LabelAddToPlaylist": "Tilføj til Afspilningsliste",
"LabelAddToPlaylistBatch": "Tilføj {0} Elementer til Afspilningsliste",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "Alle",
"LabelAllUsers": "Alle Brugere",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Allerede i dit bibliotek",
"LabelAppend": "Tilføj",
"LabelAuthor": "Forfatter",
"LabelAuthorFirstLast": "Forfatter (Fornavn Efternavn)",
"LabelAuthorLastFirst": "Forfatter (Efternavn, Fornavn)",
"LabelAuthors": "Forfattere",
"LabelAutoDownloadEpisodes": "Auto Download Episoder",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Tilbage til Bruger",
"LabelBackupLocation": "Backup Placering",
"LabelBackupsEnableAutomaticBackups": "Aktivér automatisk sikkerhedskopiering",
"LabelBackupsEnableAutomaticBackupsHelp": "Sikkerhedskopier gemt i /metadata/backups",
"LabelBackupsMaxBackupSize": "Maksimal sikkerhedskopistørrelse (i GB)",
"LabelBackupsMaxBackupSizeHelp": "Som en beskyttelse mod fejlkonfiguration fejler sikkerhedskopier, hvis de overstiger den konfigurerede størrelse.",
"LabelBackupsNumberToKeep": "Antal sikkerhedskopier at beholde",
"LabelBackupsNumberToKeepHelp": "Kun 1 sikkerhedskopi fjernes ad gangen, så hvis du allerede har flere sikkerhedskopier end dette, skal du fjerne dem manuelt.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Bøger",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Ændre Adgangskode",
"LabelChannels": "Kanaler",
"LabelChapters": "Kapitler",
"LabelChaptersFound": "fundne kapitler",
"LabelChapterTitle": "Kapitel Titel",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Luk afspiller",
"LabelCodec": "Codec",
"LabelCollapseSeries": "Fold Serie Sammen",
"LabelCollection": "Samling",
"LabelCollections": "Samlinger",
"LabelComplete": "Fuldfør",
"LabelConfirmPassword": "Bekræft Adgangskode",
"LabelContinueListening": "Fortsæt Lytning",
"LabelContinueReading": "Fortsæt Læsning",
"LabelContinueSeries": "Fortsæt Serie",
"LabelCover": "Omslag",
"LabelCoverImageURL": "Omslagsbillede URL",
"LabelCreatedAt": "Oprettet Kl.",
"LabelCronExpression": "Cron Udtryk",
"LabelCurrent": "Aktuel",
"LabelCurrently": "Aktuelt:",
"LabelCustomCronExpression": "Brugerdefineret Cron Udtryk:",
"LabelDatetime": "Dato og Tid",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Beskrivelse",
"LabelDeselectAll": "Fravælg Alle",
"LabelDevice": "Enheds",
"LabelDeviceInfo": "Enhedsinformation",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Mappe",
"LabelDiscFromFilename": "Disk fra Filnavn",
"LabelDiscFromMetadata": "Disk fra Metadata",
"LabelDiscover": "Opdag",
"LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episoder",
"LabelDuration": "Varighed",
"LabelDurationFound": "Fundet varighed:",
"LabelEbook": "E-bog",
"LabelEbooks": "E-bøger",
"LabelEdit": "Rediger",
"LabelEmail": "Email",
"LabelEmailSettingsFromAddress": "Fra Adresse",
"LabelEmailSettingsSecure": "Sikker",
"LabelEmailSettingsSecureHelp": "Hvis sandt, vil forbindelsen bruge TLS ved tilslutning til serveren. Hvis falsk, bruges TLS, hvis serveren understøtter STARTTLS-udvidelsen. I de fleste tilfælde skal denne værdi sættes til sandt, hvis du tilslutter til port 465. Til port 587 eller 25 skal du holde det falsk. (fra nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Test Adresse",
"LabelEmbeddedCover": "Indlejret Omslag",
"LabelEnable": "Aktivér",
"LabelEnd": "Slut",
"LabelEpisode": "Episode",
"LabelEpisodeTitle": "Episodetitel",
"LabelEpisodeType": "Episodetype",
"LabelExample": "Eksempel",
"LabelExplicit": "Eksplisit",
"LabelFeedURL": "Feed URL",
"LabelFile": "Fil",
"LabelFileBirthtime": "Fødselstidspunkt for fil",
"LabelFileModified": "Fil ændret",
"LabelFilename": "Filnavn",
"LabelFilterByUser": "Filtrér efter bruger",
"LabelFindEpisodes": "Find episoder",
"LabelFinished": "Færdig",
"LabelFolder": "Mappe",
"LabelFolders": "Mapper",
"LabelFontFamily": "Fontfamilie",
"LabelFontScale": "Skriftstørrelse",
"LabelFormat": "Format",
"LabelGenre": "Genre",
"LabelGenres": "Genrer",
"LabelHardDeleteFile": "Permanent slet fil",
"LabelHasEbook": "Har e-bog",
"LabelHasSupplementaryEbook": "Har supplerende e-bog",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Vært",
"LabelHour": "Time",
"LabelIcon": "Ikon",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Inkluder i afspilningsliste",
"LabelIncomplete": "Ufuldstændig",
"LabelInProgress": "I gang",
"LabelInterval": "Interval",
"LabelIntervalCustomDailyWeekly": "Tilpasset dagligt/ugentligt",
"LabelIntervalEvery12Hours": "Hver 12. time",
"LabelIntervalEvery15Minutes": "Hver 15. minut",
"LabelIntervalEvery2Hours": "Hver 2. time",
"LabelIntervalEvery30Minutes": "Hver 30. minut",
"LabelIntervalEvery6Hours": "Hver 6. time",
"LabelIntervalEveryDay": "Hver dag",
"LabelIntervalEveryHour": "Hver time",
"LabelInvalidParts": "Ugyldige dele",
"LabelInvert": "Inverter",
"LabelItem": "Element",
"LabelLanguage": "Sprog",
"LabelLanguageDefaultServer": "Standard server sprog",
"LabelLastBookAdded": "Senest tilføjede bog",
"LabelLastBookUpdated": "Senest opdaterede bog",
"LabelLastSeen": "Sidst set",
"LabelLastTime": "Sidste gang",
"LabelLastUpdate": "Seneste opdatering",
"LabelLayout": "Layout",
"LabelLayoutSinglePage": "Enkeltside",
"LabelLayoutSplitPage": "Opdelt side",
"LabelLess": "Mindre",
"LabelLibrariesAccessibleToUser": "Biblioteker tilgængelige for bruger",
"LabelLibrary": "Bibliotek",
"LabelLibraryItem": "Bibliotekselement",
"LabelLibraryName": "Biblioteksnavn",
"LabelLimit": "Grænse",
"LabelLineSpacing": "Linjeafstand",
"LabelListenAgain": "Lyt igen",
"LabelLogLevelDebug": "Fejlsøgning",
"LabelLogLevelInfo": "Information",
"LabelLogLevelWarn": "Advarsel",
"LabelLookForNewEpisodesAfterDate": "Søg efter nye episoder efter denne dato",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Medieafspiller",
"LabelMediaType": "Medietype",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadataudbyder",
"LabelMetaTag": "Meta-tag",
"LabelMetaTags": "Meta-tags",
"LabelMinute": "Minut",
"LabelMissing": "Mangler",
"LabelMissingParts": "Manglende dele",
"LabelMore": "Mere",
"LabelMoreInfo": "Mere info",
"LabelName": "Navn",
"LabelNarrator": "Fortæller",
"LabelNarrators": "Fortællere",
"LabelNew": "Ny",
"LabelNewestAuthors": "Nyeste forfattere",
"LabelNewestEpisodes": "Nyeste episoder",
"LabelNewPassword": "Nyt kodeord",
"LabelNextBackupDate": "Næste sikkerhedskopi dato",
"LabelNextScheduledRun": "Næste planlagte kørsel",
"LabelNoEpisodesSelected": "Ingen episoder valgt",
"LabelNotes": "Noter",
"LabelNotFinished": "Ikke færdig",
"LabelNotificationAppriseURL": "Apprise URL'er",
"LabelNotificationAvailableVariables": "Tilgængelige variabler",
"LabelNotificationBodyTemplate": "Kropsskabelon",
"LabelNotificationEvent": "Meddelelseshændelse",
"LabelNotificationsMaxFailedAttempts": "Maksimalt antal mislykkede forsøg",
"LabelNotificationsMaxFailedAttemptsHelp": "Meddelelser deaktiveres, når de mislykkes med at sende så mange gange",
"LabelNotificationsMaxQueueSize": "Maksimal køstørrelse for meddelelseshændelser",
"LabelNotificationsMaxQueueSizeHelp": "Hændelser begrænses til at udløse en gang pr. sekund. Hændelser ignoreres, hvis køen er fyldt. Dette forhindrer meddelelsesspam.",
"LabelNotificationTitleTemplate": "Titelskabelon",
"LabelNotStarted": "Ikke påbegyndt",
"LabelNumberOfBooks": "Antal bøger",
"LabelNumberOfEpisodes": "Antal episoder",
"LabelOpenRSSFeed": "Åbn RSS-feed",
"LabelOverwrite": "Overskriv",
"LabelPassword": "Kodeord",
"LabelPath": "Sti",
"LabelPermissionsAccessAllLibraries": "Kan få adgang til alle biblioteker",
"LabelPermissionsAccessAllTags": "Kan få adgang til alle tags",
"LabelPermissionsAccessExplicitContent": "Kan få adgang til eksplicit indhold",
"LabelPermissionsDelete": "Kan slette",
"LabelPermissionsDownload": "Kan downloade",
"LabelPermissionsUpdate": "Kan opdatere",
"LabelPermissionsUpload": "Kan uploade",
"LabelPhotoPathURL": "Foto sti/URL",
"LabelPlaylists": "Afspilningslister",
"LabelPlayMethod": "Afspilningsmetode",
"LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasts",
"LabelPodcastType": "Podcast type",
"LabelPort": "Port",
"LabelPrefixesToIgnore": "Præfikser der skal ignoreres (skal ikke skelne mellem store og små bogstaver)",
"LabelPreventIndexing": "Forhindrer, at dit feed bliver indekseret af iTunes og Google podcastkataloger",
"LabelPrimaryEbook": "Primær e-bog",
"LabelProgress": "Fremskridt",
"LabelProvider": "Udbyder",
"LabelPubDate": "Udgivelsesdato",
"LabelPublisher": "Forlag",
"LabelPublishYear": "Udgivelsesår",
"LabelRead": "Læst",
"LabelReadAgain": "Læs igen",
"LabelReadEbookWithoutProgress": "Læs e-bog uden at følge fremskridt",
"LabelRecentlyAdded": "Senest tilføjet",
"LabelRecentSeries": "Seneste serie",
"LabelRecommended": "Anbefalet",
"LabelRegion": "Region",
"LabelReleaseDate": "Udgivelsesdato",
"LabelRemoveCover": "Fjern omslag",
"LabelRSSFeedCustomOwnerEmail": "Brugerdefineret ejerens e-mail",
"LabelRSSFeedCustomOwnerName": "Brugerdefineret ejerens navn",
"LabelRSSFeedOpen": "Åben RSS-feed",
"LabelRSSFeedPreventIndexing": "Forhindrer indeksering",
"LabelRSSFeedSlug": "RSS-feed-slug",
"LabelRSSFeedURL": "RSS-feed-URL",
"LabelSearchTerm": "Søgeterm",
"LabelSearchTitle": "Søg efter titel",
"LabelSearchTitleOrASIN": "Søg efter titel eller ASIN",
"LabelSeason": "Sæson",
"LabelSelectAllEpisodes": "Vælg alle episoder",
"LabelSelectEpisodesShowing": "Vælg {0} episoder vist",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send e-bog til...",
"LabelSequence": "Sekvens",
"LabelSeries": "Serie",
"LabelSeriesName": "Serienavn",
"LabelSeriesProgress": "Seriefremskridt",
"LabelSetEbookAsPrimary": "Indstil som primær",
"LabelSetEbookAsSupplementary": "Indstil som supplerende",
"LabelSettingsAudiobooksOnly": "Kun lydbøger",
"LabelSettingsAudiobooksOnlyHelp": "Aktivering af denne indstilling vil ignorere e-bogsfiler, medmindre de er inde i en lydbogmappe, hvor de vil blive indstillet som supplerende e-bøger",
"LabelSettingsBookshelfViewHelp": "Skeumorfisk design med træhylder",
"LabelSettingsChromecastSupport": "Chromecast-understøttelse",
"LabelSettingsDateFormat": "Datoformat",
"LabelSettingsDisableWatcher": "Deaktiver overvågning",
"LabelSettingsDisableWatcherForLibrary": "Deaktiver mappeovervågning for bibliotek",
"LabelSettingsDisableWatcherHelp": "Deaktiverer automatisk tilføjelse/opdatering af elementer, når der registreres filændringer. *Kræver servergenstart",
"LabelSettingsEnableWatcher": "Aktiver overvågning",
"LabelSettingsEnableWatcherForLibrary": "Aktiver mappeovervågning for bibliotek",
"LabelSettingsEnableWatcherHelp": "Aktiverer automatisk tilføjelse/opdatering af elementer, når filændringer registreres. *Kræver servergenstart",
"LabelSettingsExperimentalFeatures": "Eksperimentelle funktioner",
"LabelSettingsExperimentalFeaturesHelp": "Funktioner under udvikling, der kunne bruge din feedback og hjælp til test. Klik for at åbne Github-diskussionen.",
"LabelSettingsFindCovers": "Find omslag",
"LabelSettingsFindCoversHelp": "Hvis din lydbog ikke har et indlejret omslag eller et omslagsbillede i mappen, vil skanneren forsøge at finde et omslag.<br>Bemærk: Dette vil forlænge scanntiden",
"LabelSettingsHideSingleBookSeries": "Skjul enkeltbogsserier",
"LabelSettingsHideSingleBookSeriesHelp": "Serier med en enkelt bog vil blive skjult fra serie-siden og hjemmesidehylder.",
"LabelSettingsHomePageBookshelfView": "Brug bogreolvisning på startside",
"LabelSettingsLibraryBookshelfView": "Brug bogreolvisning i biblioteket",
"LabelSettingsParseSubtitles": "Fortolk undertekster",
"LabelSettingsParseSubtitlesHelp": "Udtræk undertekster fra lydbogsmappenavne.<br>Undertitler skal adskilles af \" - \"<br>f.eks. \"Bogtitel - En undertitel her\" har undertitlen \"En undertitel her\"",
"LabelSettingsPreferMatchedMetadata": "Foretræk matchede metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Matchede data vil tilsidesætte elementdetaljer ved brug af Hurtig Match. Som standard udfylder Hurtig Match kun manglende detaljer.",
"LabelSettingsSkipMatchingBooksWithASIN": "Spring over matchende bøger, der allerede har en ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Spring over matchende bøger, der allerede har en ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignorer præfikser ved sortering",
"LabelSettingsSortingIgnorePrefixesHelp": "f.eks. for præfikset \"the\" vil bogtitlen \"The Book Title\" blive sorteret som \"Book Title, The\"",
"LabelSettingsSquareBookCovers": "Brug kvadratiske bogomslag",
"LabelSettingsSquareBookCoversHelp": "Foretræk at bruge kvadratiske omslag frem for standard 1,6:1 bogomslag",
"LabelSettingsStoreCoversWithItem": "Gem omslag med element",
"LabelSettingsStoreCoversWithItemHelp": "Som standard gemmes omslag i /metadata/items, aktivering af denne indstilling vil gemme omslag i mappen for dit bibliotekselement. Kun én fil med navnet \"cover\" vil blive bevaret",
"LabelSettingsStoreMetadataWithItem": "Gem metadata med element",
"LabelSettingsStoreMetadataWithItemHelp": "Som standard gemmes metadatafiler i /metadata/items, aktivering af denne indstilling vil gemme metadatafiler i dine bibliotekselementmapper",
"LabelSettingsTimeFormat": "Tidsformat",
"LabelShowAll": "Vis alle",
"LabelSize": "Størrelse",
"LabelSleepTimer": "Søvntimer",
"LabelSlug": "Slug",
"LabelStart": "Start",
"LabelStarted": "Startet",
"LabelStartedAt": "Startet klokken",
"LabelStartTime": "Starttid",
"LabelStatsAudioTracks": "Lydspor",
"LabelStatsAuthors": "Forfattere",
"LabelStatsBestDay": "Bedste dag",
"LabelStatsDailyAverage": "Daglig gennemsnit",
"LabelStatsDays": "Dage",
"LabelStatsDaysListened": "Dage hørt",
"LabelStatsHours": "Timer",
"LabelStatsInARow": "i træk",
"LabelStatsItemsFinished": "Elementer færdige",
"LabelStatsItemsInLibrary": "Elementer i biblioteket",
"LabelStatsMinutes": "minutter",
"LabelStatsMinutesListening": "Minutter hørt",
"LabelStatsOverallDays": "Samlede dage",
"LabelStatsOverallHours": "Samlede timer",
"LabelStatsWeekListening": "Ugens lytning",
"LabelSubtitle": "Undertekst",
"LabelSupportedFileTypes": "Understøttede filtyper",
"LabelTag": "Mærke",
"LabelTags": "Mærker",
"LabelTagsAccessibleToUser": "Mærker tilgængelige for bruger",
"LabelTagsNotAccessibleToUser": "Mærker ikke tilgængelige for bruger",
"LabelTasks": "Kører opgaver",
"LabelTheme": "Tema",
"LabelThemeDark": "Mørk",
"LabelThemeLight": "Lys",
"LabelTimeBase": "Tidsbase",
"LabelTimeListened": "Tid hørt",
"LabelTimeListenedToday": "Tid hørt i dag",
"LabelTimeRemaining": "{0} tilbage",
"LabelTimeToShift": "Tid til skift i sekunder",
"LabelTitle": "Titel",
"LabelToolsEmbedMetadata": "Indlejre metadata",
"LabelToolsEmbedMetadataDescription": "Indlejr metadata i lydfiler, inklusive omslag og kapitler.",
"LabelToolsMakeM4b": "Lav M4B lydbogsfil",
"LabelToolsMakeM4bDescription": "Generer en .M4B lydbogsfil med indlejret metadata, omslag og kapitler.",
"LabelToolsSplitM4b": "Opdel M4B til MP3'er",
"LabelToolsSplitM4bDescription": "Opret MP3'er fra en M4B opdelt efter kapitler med indlejret metadata, omslag og kapitler.",
"LabelTotalDuration": "Samlet varighed",
"LabelTotalTimeListened": "Samlet lyttetid",
"LabelTrackFromFilename": "Spor fra filnavn",
"LabelTrackFromMetadata": "Spor fra metadata",
"LabelTracks": "Spor",
"LabelTracksMultiTrack": "Flerspors",
"LabelTracksNone": "Ingen spor",
"LabelTracksSingleTrack": "Enkeltspors",
"LabelType": "Type",
"LabelUnabridged": "Uforkortet",
"LabelUnknown": "Ukendt",
"LabelUpdateCover": "Opdater omslag",
"LabelUpdateCoverHelp": "Tillad overskrivning af eksisterende omslag for de valgte bøger, når der findes en match",
"LabelUpdatedAt": "Opdateret ved",
"LabelUpdateDetails": "Opdater detaljer",
"LabelUpdateDetailsHelp": "Tillad overskrivning af eksisterende detaljer for de valgte bøger, når der findes en match",
"LabelUploaderDragAndDrop": "Træk og slip filer eller mapper",
"LabelUploaderDropFiles": "Smid filer",
"LabelUseChapterTrack": "Brug kapitel-spor",
"LabelUseFullTrack": "Brug fuldt spor",
"LabelUser": "Bruger",
"LabelUsername": "Brugernavn",
"LabelValue": "Værdi",
"LabelVersion": "Version",
"LabelViewBookmarks": "Se bogmærker",
"LabelViewChapters": "Se kapitler",
"LabelViewQueue": "Se afspilningskø",
"LabelVolume": "Volumen",
"LabelWeekdaysToRun": "Ugedage til kørsel",
"LabelYourAudiobookDuration": "Din lydbogsvarighed",
"LabelYourBookmarks": "Dine bogmærker",
"LabelYourPlaylists": "Dine spillelister",
"LabelYourProgress": "Din fremgang",
"MessageAddToPlayerQueue": "Tilføj til afspilningskø",
"MessageAppriseDescription": "For at bruge denne funktion skal du have en instans af <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> kørende eller en API, der håndterer de samme anmodninger. <br /> Apprise API-webadressen skal være den fulde URL-sti for at sende underretningen, f.eks. hvis din API-instans er tilgængelig på <code>http://192.168.1.1:8337</code>, så skal du bruge <code>http://192.168.1.1:8337/notify</code>.",
"MessageBackupsDescription": "Backups inkluderer brugere, brugerfremskridt, biblioteksvareoplysninger, serverindstillinger og billeder gemt i <code>/metadata/items</code> og <code>/metadata/authors</code>. Backups inkluderer <strong>ikke</strong> nogen filer gemt i dine biblioteksmapper.",
"MessageBatchQuickMatchDescription": "Quick Match vil forsøge at tilføje manglende omslag og metadata til de valgte elementer. Aktivér indstillingerne nedenfor for at tillade Quick Match at overskrive eksisterende omslag og/eller metadata.",
"MessageBookshelfNoCollections": "Du har ikke oprettet nogen samlinger endnu",
"MessageBookshelfNoResultsForFilter": "Ingen resultater for filter \"{0}: {1}\"",
"MessageBookshelfNoRSSFeeds": "Ingen RSS-feeds er åbne",
"MessageBookshelfNoSeries": "Du har ingen serier",
"MessageChapterEndIsAfter": "Kapitelslutningen er efter slutningen af din lydbog",
"MessageChapterErrorFirstNotZero": "Første kapitel skal starte ved 0",
"MessageChapterErrorStartGteDuration": "Ugyldig starttid skal være mindre end lydbogens varighed",
"MessageChapterErrorStartLtPrev": "Ugyldig starttid skal være større end eller lig med den foregående kapitels starttid",
"MessageChapterStartIsAfter": "Kapitelstarten er efter slutningen af din lydbog",
"MessageCheckingCron": "Tjekker cron...",
"MessageConfirmCloseFeed": "Er du sikker på, at du vil lukke dette feed?",
"MessageConfirmDeleteBackup": "Er du sikker på, at du vil slette backup for {0}?",
"MessageConfirmDeleteFile": "Dette vil slette filen fra dit filsystem. Er du sikker?",
"MessageConfirmDeleteLibrary": "Er du sikker på, at du vil slette biblioteket permanent \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Er du sikker på, at du vil slette denne session?",
"MessageConfirmForceReScan": "Er du sikker på, at du vil tvinge en genindlæsning?",
"MessageConfirmMarkAllEpisodesFinished": "Er du sikker på, at du vil markere alle episoder som afsluttet?",
"MessageConfirmMarkAllEpisodesNotFinished": "Er du sikker på, at du vil markere alle episoder som ikke afsluttet?",
"MessageConfirmMarkSeriesFinished": "Er du sikker på, at du vil markere alle bøger i denne serie som afsluttet?",
"MessageConfirmMarkSeriesNotFinished": "Er du sikker på, at du vil markere alle bøger i denne serie som ikke afsluttet?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Er du sikker på, at du vil fjerne alle kapitler?",
"MessageConfirmRemoveAuthor": "Er du sikker på, at du vil fjerne forfatteren \"{0}\"?",
"MessageConfirmRemoveCollection": "Er du sikker på, at du vil fjerne samlingen \"{0}\"?",
"MessageConfirmRemoveEpisode": "Er du sikker på, at du vil fjerne episoden \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Er du sikker på, at du vil fjerne {0} episoder?",
"MessageConfirmRemoveNarrator": "Er du sikker på, at du vil fjerne fortælleren \"{0}\"?",
"MessageConfirmRemovePlaylist": "Er du sikker på, at du vil fjerne din spilleliste \"{0}\"?",
"MessageConfirmRenameGenre": "Er du sikker på, at du vil omdøbe genre \"{0}\" til \"{1}\" for alle elementer?",
"MessageConfirmRenameGenreMergeNote": "Bemærk: Denne genre findes allerede, så de vil blive fusioneret.",
"MessageConfirmRenameGenreWarning": "Advarsel! En lignende genre med en anden skrivemåde eksisterer allerede \"{0}\".",
"MessageConfirmRenameTag": "Er du sikker på, at du vil omdøbe tag \"{0}\" til \"{1}\" for alle elementer?",
"MessageConfirmRenameTagMergeNote": "Bemærk: Dette tag findes allerede, så de vil blive fusioneret.",
"MessageConfirmRenameTagWarning": "Advarsel! Et lignende tag med en anden skrivemåde eksisterer allerede \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Er du sikker på, at du vil sende {0} e-bog \"{1}\" til enhed \"{2}\"?",
"MessageDownloadingEpisode": "Downloader episode",
"MessageDragFilesIntoTrackOrder": "Træk filer ind i korrekt spororden",
"MessageEmbedFinished": "Indlejring færdig!",
"MessageEpisodesQueuedForDownload": "{0} episoder er sat i kø til download",
"MessageFeedURLWillBe": "Feed-URL vil være {0}",
"MessageFetching": "Henter...",
"MessageForceReScanDescription": "vil scanne alle filer igen som en frisk scanning. Lydfilens ID3-tags, OPF-filer og tekstfiler scannes som nye.",
"MessageImportantNotice": "Vigtig besked!",
"MessageInsertChapterBelow": "Indsæt kapitel nedenfor",
"MessageItemsSelected": "{0} elementer valgt",
"MessageItemsUpdated": "{0} elementer opdateret",
"MessageJoinUsOn": "Deltag i os på",
"MessageListeningSessionsInTheLastYear": "{0} lyttesessioner i det sidste år",
"MessageLoading": "Indlæser...",
"MessageLoadingFolders": "Indlæser mapper...",
"MessageM4BFailed": "M4B mislykkedes!",
"MessageM4BFinished": "M4B afsluttet!",
"MessageMapChapterTitles": "Tilknyt kapiteloverskrifter til dine eksisterende lydbogskapitler uden at justere tidsstempler",
"MessageMarkAllEpisodesFinished": "Markér alle episoder som afsluttet",
"MessageMarkAllEpisodesNotFinished": "Markér alle episoder som ikke afsluttet",
"MessageMarkAsFinished": "Markér som afsluttet",
"MessageMarkAsNotFinished": "Markér som ikke afsluttet",
"MessageMatchBooksDescription": "vil forsøge at matche bøger i biblioteket med en bog fra den valgte søgeudbyder og udfylde tomme detaljer og omslag. Overskriver ikke detaljer.",
"MessageNoAudioTracks": "Ingen lydspor",
"MessageNoAuthors": "Ingen forfattere",
"MessageNoBackups": "Ingen sikkerhedskopier",
"MessageNoBookmarks": "Ingen bogmærker",
"MessageNoChapters": "Ingen kapitler",
"MessageNoCollections": "Ingen samlinger",
"MessageNoCoversFound": "Ingen omslag fundet",
"MessageNoDescription": "Ingen beskrivelse",
"MessageNoDownloadsInProgress": "Ingen downloads i gang lige nu",
"MessageNoDownloadsQueued": "Ingen downloads i kø",
"MessageNoEpisodeMatchesFound": "Ingen episode-matcher fundet",
"MessageNoEpisodes": "Ingen episoder",
"MessageNoFoldersAvailable": "Ingen mapper tilgængelige",
"MessageNoGenres": "Ingen genrer",
"MessageNoIssues": "Ingen problemer",
"MessageNoItems": "Ingen elementer",
"MessageNoItemsFound": "Ingen elementer fundet",
"MessageNoListeningSessions": "Ingen lyttesessioner",
"MessageNoLogs": "Ingen logfiler",
"MessageNoMediaProgress": "Ingen medieforløb",
"MessageNoNotifications": "Ingen meddelelser",
"MessageNoPodcastsFound": "Ingen podcasts fundet",
"MessageNoResults": "Ingen resultater",
"MessageNoSearchResultsFor": "Ingen søgeresultater for \"{0}\"",
"MessageNoSeries": "Ingen serier",
"MessageNoTags": "Ingen tags",
"MessageNoTasksRunning": "Ingen opgaver kører",
"MessageNotYetImplemented": "Endnu ikke implementeret",
"MessageNoUpdateNecessary": "Ingen opdatering nødvendig",
"MessageNoUpdatesWereNecessary": "Ingen opdateringer var nødvendige",
"MessageNoUserPlaylists": "Du har ingen afspilningslister",
"MessageOr": "eller",
"MessagePauseChapter": "Pause kapitelafspilning",
"MessagePlayChapter": "Lyt til begyndelsen af kapitlet",
"MessagePlaylistCreateFromCollection": "Opret afspilningsliste fra samling",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast har ingen RSS-feed-URL at bruge til matchning",
"MessageQuickMatchDescription": "Udfyld tomme elementoplysninger og omslag med første matchresultat fra '{0}'. Overskriver ikke oplysninger, medmindre serverindstillingen 'Foretræk matchet metadata' er aktiveret.",
"MessageRemoveChapter": "Fjern kapitel",
"MessageRemoveEpisodes": "Fjern {0} episode(r)",
"MessageRemoveFromPlayerQueue": "Fjern fra afspillingskøen",
"MessageRemoveUserWarning": "Er du sikker på, at du vil slette brugeren permanent \"{0}\"?",
"MessageReportBugsAndContribute": "Rapporter fejl, anmod om funktioner og bidrag på",
"MessageResetChaptersConfirm": "Er du sikker på, at du vil nulstille kapitler og annullere ændringerne, du har foretaget?",
"MessageRestoreBackupConfirm": "Er du sikker på, at du vil gendanne sikkerhedskopien oprettet den",
"MessageRestoreBackupWarning": "Gendannelse af en sikkerhedskopi vil overskrive hele databasen, som er placeret på /config, og omslagsbilleder i /metadata/items & /metadata/authors.<br /><br />Sikkerhedskopier ændrer ikke nogen filer i dine biblioteksmapper. Hvis du har aktiveret serverindstillinger for at gemme omslagskunst og metadata i dine biblioteksmapper, sikkerhedskopieres eller overskrives disse ikke.<br /><br />Alle klienter, der bruger din server, opdateres automatisk.",
"MessageSearchResultsFor": "Søgeresultater for",
"MessageServerCouldNotBeReached": "Serveren kunne ikke nås",
"MessageSetChaptersFromTracksDescription": "Indstil kapitler ved at bruge hver lydfil som et kapitel og kapiteloverskrift som lydfilnavn",
"MessageStartPlaybackAtTime": "Start afspilning for \"{0}\" kl. {1}?",
"MessageThinking": "Tænker...",
"MessageUploaderItemFailed": "Fejl ved upload",
"MessageUploaderItemSuccess": "Uploadet med succes!",
"MessageUploading": "Uploader...",
"MessageValidCronExpression": "Gyldigt cron-udtryk",
"MessageWatcherIsDisabledGlobally": "Watcher er deaktiveret globalt i serverindstillinger",
"MessageXLibraryIsEmpty": "{0} bibliotek er tomt!",
"MessageYourAudiobookDurationIsLonger": "Din lydbogsvarighed er længere end den fundne varighed",
"MessageYourAudiobookDurationIsShorter": "Din lydbogsvarighed er kortere end den fundne varighed",
"NoteChangeRootPassword": "Root-brugeren er den eneste bruger, der kan have en tom adgangskode",
"NoteChapterEditorTimes": "Bemærk: Første kapitel starttidspunkt skal forblive kl. 0:00, og det sidste kapitel starttidspunkt må ikke overstige denne lydbogs varighed.",
"NoteFolderPicker": "Bemærk: Mapper, der allerede er mappet, vises ikke",
"NoteFolderPickerDebian": "Bemærk: Mappicker for Debian-installationen er ikke fuldt implementeret. Du bør indtaste stien til dit bibliotek direkte.",
"NoteRSSFeedPodcastAppsHttps": "Advarsel: De fleste podcast-apps kræver, at RSS-feedets URL bruger HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Advarsel: En eller flere af dine episoder har ikke en Pub Date. Nogle podcast-apps kræver dette.",
"NoteUploaderFoldersWithMediaFiles": "Mapper med mediefiler håndteres som separate bibliotekselementer.",
"NoteUploaderOnlyAudioFiles": "Hvis du kun uploader lydfiler, håndteres hver lydfil som en separat lydbog.",
"NoteUploaderUnsupportedFiles": "Ikke-understøttede filer ignoreres. Når du vælger eller slipper en mappe, ignoreres andre filer, der ikke er i en emnemappe.",
"PlaceholderNewCollection": "Nyt samlingnavn",
"PlaceholderNewFolderPath": "Ny mappes sti",
"PlaceholderNewPlaylist": "Nyt afspilningslistnavn",
"PlaceholderSearch": "Søg..",
"PlaceholderSearchEpisode": "Søg efter episode..",
"ToastAccountUpdateFailed": "Mislykkedes opdatering af konto",
"ToastAccountUpdateSuccess": "Konto opdateret",
"ToastAuthorImageRemoveFailed": "Mislykkedes fjernelse af forfatterbillede",
"ToastAuthorImageRemoveSuccess": "Forfatterbillede fjernet",
"ToastAuthorUpdateFailed": "Mislykkedes opdatering af forfatter",
"ToastAuthorUpdateMerged": "Forfatter fusioneret",
"ToastAuthorUpdateSuccess": "Forfatter opdateret",
"ToastAuthorUpdateSuccessNoImageFound": "Forfatter opdateret (ingen billede fundet)",
"ToastBackupCreateFailed": "Mislykkedes oprettelse af sikkerhedskopi",
"ToastBackupCreateSuccess": "Sikkerhedskopi oprettet",
"ToastBackupDeleteFailed": "Mislykkedes sletning af sikkerhedskopi",
"ToastBackupDeleteSuccess": "Sikkerhedskopi slettet",
"ToastBackupRestoreFailed": "Mislykkedes gendannelse af sikkerhedskopi",
"ToastBackupUploadFailed": "Mislykkedes upload af sikkerhedskopi",
"ToastBackupUploadSuccess": "Sikkerhedskopi uploadet",
"ToastBatchUpdateFailed": "Mislykkedes batchopdatering",
"ToastBatchUpdateSuccess": "Batchopdatering lykkedes",
"ToastBookmarkCreateFailed": "Mislykkedes oprettelse af bogmærke",
"ToastBookmarkCreateSuccess": "Bogmærke tilføjet",
"ToastBookmarkRemoveFailed": "Mislykkedes fjernelse af bogmærke",
"ToastBookmarkRemoveSuccess": "Bogmærke fjernet",
"ToastBookmarkUpdateFailed": "Mislykkedes opdatering af bogmærke",
"ToastBookmarkUpdateSuccess": "Bogmærke opdateret",
"ToastChaptersHaveErrors": "Kapitler har fejl",
"ToastChaptersMustHaveTitles": "Kapitler skal have titler",
"ToastCollectionItemsRemoveFailed": "Mislykkedes fjernelse af element(er) fra samlingen",
"ToastCollectionItemsRemoveSuccess": "Element(er) fjernet fra samlingen",
"ToastCollectionRemoveFailed": "Mislykkedes fjernelse af samling",
"ToastCollectionRemoveSuccess": "Samling fjernet",
"ToastCollectionUpdateFailed": "Mislykkedes opdatering af samling",
"ToastCollectionUpdateSuccess": "Samling opdateret",
"ToastItemCoverUpdateFailed": "Mislykkedes opdatering af varens omslag",
"ToastItemCoverUpdateSuccess": "Varens omslag opdateret",
"ToastItemDetailsUpdateFailed": "Mislykkedes opdatering af varedetaljer",
"ToastItemDetailsUpdateSuccess": "Varedetaljer opdateret",
"ToastItemDetailsUpdateUnneeded": "Ingen opdateringer er nødvendige for varedetaljer",
"ToastItemMarkedAsFinishedFailed": "Mislykkedes markering som afsluttet",
"ToastItemMarkedAsFinishedSuccess": "Vare markeret som afsluttet",
"ToastItemMarkedAsNotFinishedFailed": "Mislykkedes markering som ikke afsluttet",
"ToastItemMarkedAsNotFinishedSuccess": "Vare markeret som ikke afsluttet",
"ToastLibraryCreateFailed": "Mislykkedes oprettelse af bibliotek",
"ToastLibraryCreateSuccess": "Bibliotek \"{0}\" oprettet",
"ToastLibraryDeleteFailed": "Mislykkedes sletning af bibliotek",
"ToastLibraryDeleteSuccess": "Bibliotek slettet",
"ToastLibraryScanFailedToStart": "Mislykkedes start af skanning",
"ToastLibraryScanStarted": "Biblioteksskanning startet",
"ToastLibraryUpdateFailed": "Mislykkedes opdatering af bibliotek",
"ToastLibraryUpdateSuccess": "Bibliotek \"{0}\" opdateret",
"ToastPlaylistCreateFailed": "Mislykkedes oprettelse af afspilningsliste",
"ToastPlaylistCreateSuccess": "Afspilningsliste oprettet",
"ToastPlaylistRemoveFailed": "Mislykkedes fjernelse af afspilningsliste",
"ToastPlaylistRemoveSuccess": "Afspilningsliste fjernet",
"ToastPlaylistUpdateFailed": "Mislykkedes opdatering af afspilningsliste",
"ToastPlaylistUpdateSuccess": "Afspilningsliste opdateret",
"ToastPodcastCreateFailed": "Mislykkedes oprettelse af podcast",
"ToastPodcastCreateSuccess": "Podcast oprettet med succes",
"ToastRemoveItemFromCollectionFailed": "Mislykkedes fjernelse af element fra samling",
"ToastRemoveItemFromCollectionSuccess": "Element fjernet fra samling",
"ToastRSSFeedCloseFailed": "Mislykkedes lukning af RSS-feed",
"ToastRSSFeedCloseSuccess": "RSS-feed lukket",
"ToastSendEbookToDeviceFailed": "Mislykkedes afsendelse af e-bog til enhed",
"ToastSendEbookToDeviceSuccess": "E-bog afsendt til enhed \"{0}\"",
"ToastSeriesUpdateFailed": "Mislykkedes opdatering af serie",
"ToastSeriesUpdateSuccess": "Serieopdatering lykkedes",
"ToastSessionDeleteFailed": "Mislykkedes sletning af session",
"ToastSessionDeleteSuccess": "Session slettet",
"ToastSocketConnected": "Socket forbundet",
"ToastSocketDisconnected": "Socket afbrudt",
"ToastSocketFailedToConnect": "Socket kunne ikke oprettes",
"ToastUserDeleteFailed": "Mislykkedes sletning af bruger",
"ToastUserDeleteSuccess": "Bruger slettet"
}
+67 -31
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Hinzufügen", "ButtonAdd": "Hinzufügen",
"ButtonAddChapters": "Kapitel hinzufügen", "ButtonAddChapters": "Kapitel hinzufügen",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Podcasts hinzufügen", "ButtonAddPodcasts": "Podcasts hinzufügen",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Erstelle deine erste Bibliothek", "ButtonAddYourFirstLibrary": "Erstelle deine erste Bibliothek",
"ButtonApply": "Übernehmen", "ButtonApply": "Übernehmen",
"ButtonApplyChapters": "Kapitel anwenden", "ButtonApplyChapters": "Kapitel anwenden",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Lösche die Serie aus der Serienfortsetzungsliste", "ButtonRemoveSeriesFromContinueSeries": "Lösche die Serie aus der Serienfortsetzungsliste",
"ButtonReScan": "Neu scannen", "ButtonReScan": "Neu scannen",
"ButtonReset": "Zurücksetzen", "ButtonReset": "Zurücksetzen",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Wiederherstellen", "ButtonRestore": "Wiederherstellen",
"ButtonSave": "Speichern", "ButtonSave": "Speichern",
"ButtonSaveAndClose": "Speichern & Schließen", "ButtonSaveAndClose": "Speichern & Schließen",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise Benachrichtigungseinstellungen", "HeaderAppriseNotificationSettings": "Apprise Benachrichtigungseinstellungen",
"HeaderAudiobookTools": "Hörbuch-Dateiverwaltungstools", "HeaderAudiobookTools": "Hörbuch-Dateiverwaltungstools",
"HeaderAudioTracks": "Audiodateien", "HeaderAudioTracks": "Audiodateien",
"HeaderAuthentication": "Authentifizierung",
"HeaderBackups": "Sicherungen", "HeaderBackups": "Sicherungen",
"HeaderChangePassword": "Passwort ändern", "HeaderChangePassword": "Passwort ändern",
"HeaderChapters": "Kapitel", "HeaderChapters": "Kapitel",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Tags verwalten", "HeaderManageTags": "Tags verwalten",
"HeaderMapDetails": "Stapelverarbeitung", "HeaderMapDetails": "Stapelverarbeitung",
"HeaderMatch": "Metadaten", "HeaderMatch": "Metadaten",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Einzubettende Metadaten", "HeaderMetadataToEmbed": "Einzubettende Metadaten",
"HeaderNewAccount": "Neues Konto", "HeaderNewAccount": "Neues Konto",
"HeaderNewLibrary": "Neue Bibliothek", "HeaderNewLibrary": "Neue Bibliothek",
"HeaderNotifications": "Benachrichtigungen", "HeaderNotifications": "Benachrichtigungen",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
"HeaderOpenRSSFeed": "RSS-Feed öffnen", "HeaderOpenRSSFeed": "RSS-Feed öffnen",
"HeaderOtherFiles": "Sonstige Dateien", "HeaderOtherFiles": "Sonstige Dateien",
"HeaderPasswordAuthentication": "Password Authentifizierung",
"HeaderPermissions": "Berechtigungen", "HeaderPermissions": "Berechtigungen",
"HeaderPlayerQueue": "Spieler Warteschlange", "HeaderPlayerQueue": "Spieler Warteschlange",
"HeaderPlaylist": "Wiedergabeliste", "HeaderPlaylist": "Wiedergabeliste",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Lösche {0} Episoden", "HeaderRemoveEpisodes": "Lösche {0} Episoden",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS-Feed ist geöffnet", "HeaderRSSFeedIsOpen": "RSS-Feed ist geöffnet",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte", "HeaderSavedMediaProgress": "Gespeicherte Hörfortschritte",
"HeaderSchedule": "Zeitplan", "HeaderSchedule": "Zeitplan",
"HeaderScheduleLibraryScans": "Automatische Bibliotheksscans", "HeaderScheduleLibraryScans": "Automatische Bibliotheksscans",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Sammlung hinzu", "LabelAddToCollectionBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Sammlung hinzu",
"LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen", "LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen",
"LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu", "LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu",
"LabelAdminUsersOnly": "Nur Admin Benutzer",
"LabelAll": "Alle", "LabelAll": "Alle",
"LabelAllUsers": "Alle Benutzer", "LabelAllUsers": "Alle Benutzer",
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
"LabelAllUsersIncludingGuests": "All Benutzer und Gäste",
"LabelAlreadyInYourLibrary": "In der Bibliothek vorhanden", "LabelAlreadyInYourLibrary": "In der Bibliothek vorhanden",
"LabelAppend": "Anhängen", "LabelAppend": "Anhängen",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Autor (Nachname, Vorname)", "LabelAuthorLastFirst": "Autor (Nachname, Vorname)",
"LabelAuthors": "Autoren", "LabelAuthors": "Autoren",
"LabelAutoDownloadEpisodes": "Episoden automatisch herunterladen", "LabelAutoDownloadEpisodes": "Episoden automatisch herunterladen",
"LabelAutoLaunch": "Automatischer Start",
"LabelAutoLaunchDescription": "Automatische Weiterleitung zum Authentifizierungsanbieter beim Navigieren zur Anmeldeseite (manueller Überschreibungspfad <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Automatische Registrierung",
"LabelAutoRegisterDescription": "Automatische neue Neutzer anlegen nach dem Einloggen",
"LabelBackToUser": "Zurück zum Benutzer", "LabelBackToUser": "Zurück zum Benutzer",
"LabelBackupLocation": "Backup-Ort",
"LabelBackupsEnableAutomaticBackups": "Automatische Sicherung aktivieren", "LabelBackupsEnableAutomaticBackups": "Automatische Sicherung aktivieren",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups werden in /metadata/backups gespeichert", "LabelBackupsEnableAutomaticBackupsHelp": "Backups werden in /metadata/backups gespeichert",
"LabelBackupsMaxBackupSize": "Maximale Sicherungsgröße (in GB)", "LabelBackupsMaxBackupSize": "Maximale Sicherungsgröße (in GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn Sie bereits mehrere Sicherungen als die definierte max. Anzahl haben, sollten Sie diese manuell entfernen.", "LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn Sie bereits mehrere Sicherungen als die definierte max. Anzahl haben, sollten Sie diese manuell entfernen.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Bücher", "LabelBooks": "Bücher",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Passwort ändern", "LabelChangePassword": "Passwort ändern",
"LabelChannels": "Kanäle", "LabelChannels": "Kanäle",
"LabelChapters": "Kapitel", "LabelChapters": "Kapitel",
"LabelChaptersFound": "gefundene Kapitel", "LabelChaptersFound": "gefundene Kapitel",
"LabelChapterTitle": "Kapitelüberschrift", "LabelChapterTitle": "Kapitelüberschrift",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Player schließen", "LabelClosePlayer": "Player schließen",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Serien zusammenfassen", "LabelCollapseSeries": "Serien zusammenfassen",
"LabelCollection": "Sammlung",
"LabelCollections": "Sammlungen", "LabelCollections": "Sammlungen",
"LabelComplete": "Vollständig", "LabelComplete": "Vollständig",
"LabelConfirmPassword": "Passwort bestätigen", "LabelConfirmPassword": "Passwort bestätigen",
@@ -215,13 +235,16 @@
"LabelCurrently": "Aktuell:", "LabelCurrently": "Aktuell:",
"LabelCustomCronExpression": "Benutzerdefinierter Cron-Ausdruck", "LabelCustomCronExpression": "Benutzerdefinierter Cron-Ausdruck",
"LabelDatetime": "Datum & Uhrzeit", "LabelDatetime": "Datum & Uhrzeit",
"LabelDeleteFromFileSystemCheckbox": "Löschen von der Festplatte + Datenbank (deaktivieren um nur aus der Datenbank zu löschen)",
"LabelDescription": "Beschreibung", "LabelDescription": "Beschreibung",
"LabelDeselectAll": "Alles abwählen", "LabelDeselectAll": "Alles abwählen",
"LabelDevice": "Gerät", "LabelDevice": "Gerät",
"LabelDeviceInfo": "Geräteinformationen", "LabelDeviceInfo": "Geräteinformationen",
"LabelDeviceIsAvailableTo": "Dem Geärt ist es möglich zu ...",
"LabelDirectory": "Verzeichnis", "LabelDirectory": "Verzeichnis",
"LabelDiscFromFilename": "CD aus dem Dateinamen", "LabelDiscFromFilename": "CD aus dem Dateinamen",
"LabelDiscFromMetadata": "CD aus den Metadaten", "LabelDiscFromMetadata": "CD aus den Metadaten",
"LabelDiscover": "Entdecken",
"LabelDownload": "Herunterladen", "LabelDownload": "Herunterladen",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Laufzeit", "LabelDuration": "Laufzeit",
@@ -252,6 +275,7 @@
"LabelFinished": "beendet", "LabelFinished": "beendet",
"LabelFolder": "Ordner", "LabelFolder": "Ordner",
"LabelFolders": "Verzeichnisse", "LabelFolders": "Verzeichnisse",
"LabelFontFamily": "Schriftfamilie",
"LabelFontScale": "Schriftgröße", "LabelFontScale": "Schriftgröße",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Kategorie", "LabelGenre": "Kategorie",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Datei dauerhaft löschen", "LabelHardDeleteFile": "Datei dauerhaft löschen",
"LabelHasEbook": "mit E-Book", "LabelHasEbook": "mit E-Book",
"LabelHasSupplementaryEbook": "mit zusätlichem E-Book", "LabelHasSupplementaryEbook": "mit zusätlichem E-Book",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Stunde", "LabelHour": "Stunde",
"LabelIcon": "Symbol", "LabelIcon": "Symbol",
"LabelImageURLFromTheWeb": "Bild-URL vom Internet",
"LabelIncludeInTracklist": "In die Titelliste aufnehmen", "LabelIncludeInTracklist": "In die Titelliste aufnehmen",
"LabelIncomplete": "Unvollständig", "LabelIncomplete": "Unvollständig",
"LabelInProgress": "In Bearbeitung", "LabelInProgress": "In Bearbeitung",
@@ -299,8 +325,12 @@
"LabelLogLevelInfo": "Informationen", "LabelLogLevelInfo": "Informationen",
"LabelLogLevelWarn": "Warnungen", "LabelLogLevelWarn": "Warnungen",
"LabelLookForNewEpisodesAfterDate": "Suchen nach neuen Episoden nach diesem Datum", "LabelLookForNewEpisodesAfterDate": "Suchen nach neuen Episoden nach diesem Datum",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit",
"LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID von Ihrem SSO-Anbieter zugeordnet",
"LabelMediaPlayer": "Mediaplayer", "LabelMediaPlayer": "Mediaplayer",
"LabelMediaType": "Medientyp", "LabelMediaType": "Medientyp",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadatenanbieter", "LabelMetadataProvider": "Metadatenanbieter",
"LabelMetaTag": "Meta Schlagwort", "LabelMetaTag": "Meta Schlagwort",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Staffel", "LabelSeason": "Staffel",
"LabelSelectAllEpisodes": "Alle Episoden auswählen", "LabelSelectAllEpisodes": "Alle Episoden auswählen",
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt", "LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
"LabelSelectUsers": "Benutzer auswählen",
"LabelSendEbookToDevice": "E-Book senden an...", "LabelSendEbookToDevice": "E-Book senden an...",
"LabelSequence": "Reihenfolge", "LabelSequence": "Reihenfolge",
"LabelSeries": "Serien", "LabelSeries": "Serien",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Überwachung deaktivieren", "LabelSettingsDisableWatcher": "Überwachung deaktivieren",
"LabelSettingsDisableWatcherForLibrary": "Ordnerüberwachung für die Bibliothek deaktivieren", "LabelSettingsDisableWatcherForLibrary": "Ordnerüberwachung für die Bibliothek deaktivieren",
"LabelSettingsDisableWatcherHelp": "Deaktiviert das automatische Hinzufügen/Aktualisieren von Elementen, wenn Dateiänderungen erkannt werden. *Erfordert einen Server-Neustart", "LabelSettingsDisableWatcherHelp": "Deaktiviert das automatische Hinzufügen/Aktualisieren von Elementen, wenn Dateiänderungen erkannt werden. *Erfordert einen Server-Neustart",
"LabelSettingsEnableWatcher": "Überwachung aktivieren",
"LabelSettingsEnableWatcherForLibrary": "Ordnerüberwachung für die Bibliothek aktivieren",
"LabelSettingsEnableWatcherHelp": "Aktiviert das automatische Hinzufügen/Aktualisieren von Elementen, wenn Dateiänderungen erkannt werden. *Erfordert einen Server-Neustart",
"LabelSettingsExperimentalFeatures": "Experimentelle Funktionen", "LabelSettingsExperimentalFeatures": "Experimentelle Funktionen",
"LabelSettingsExperimentalFeaturesHelp": "Funktionen welche sich in der Entwicklung befinden, benötigen Ihr Feedback und Ihre Hilfe beim Testen. Klicken Sie hier, um die Github-Diskussion zu öffnen.", "LabelSettingsExperimentalFeaturesHelp": "Funktionen welche sich in der Entwicklung befinden, benötigen Ihr Feedback und Ihre Hilfe beim Testen. Klicken Sie hier, um die Github-Diskussion zu öffnen.",
"LabelSettingsFindCovers": "Suche Titelbilder", "LabelSettingsFindCovers": "Suche Titelbilder",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Serien, die ein einzelnes Buch enthalten, werden in den Regalen der Serienseite und der Startseite ausgeblendet.", "LabelSettingsHideSingleBookSeriesHelp": "Serien, die ein einzelnes Buch enthalten, werden in den Regalen der Serienseite und der Startseite ausgeblendet.",
"LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht", "LabelSettingsHomePageBookshelfView": "Startseite verwendet die Bücherregalansicht",
"LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht", "LabelSettingsLibraryBookshelfView": "Bibliothek verwendet die Bücherregalansicht",
"LabelSettingsOverdriveMediaMarkers": "Verwende Overdrive Media Marker für Kapitel",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3-Dateien von Overdrive werden mit eingebetteten Kapitel-Timings als benutzerdefinierte Metadaten geliefert. Wenn Sie dies aktivieren, werden diese Markierungen automatisch für die Kapiteltaktung verwendet",
"LabelSettingsParseSubtitles": "Analysiere Untertitel", "LabelSettingsParseSubtitles": "Analysiere Untertitel",
"LabelSettingsParseSubtitlesHelp": "Extrahiere den Untertitel von Medium-Ordnernamen.<br>Untertitel müssen vom eigentlichem Titel durch ein \" - \" getrennt sein. <br>Beispiel: \"Titel - Untertitel\"", "LabelSettingsParseSubtitlesHelp": "Extrahiere den Untertitel von Medium-Ordnernamen.<br>Untertitel müssen vom eigentlichem Titel durch ein \" - \" getrennt sein. <br>Beispiel: \"Titel - Untertitel\"",
"LabelSettingsPreferAudioMetadata": "Bevorzuge lokale ID3-Audiometadaten",
"LabelSettingsPreferAudioMetadataHelp": "In den Audiodateien eingebettete ID3 Tags werden anstelle der Ordnernamen für die Bereitstellung der Metadaten verwendet. Wenn keine ID3 Tags zur Verfügung stehen, werden die Ordnernamen verwendet.",
"LabelSettingsPreferMatchedMetadata": "Bevorzuge online abgestimmte Metadaten", "LabelSettingsPreferMatchedMetadata": "Bevorzuge online abgestimmte Metadaten",
"LabelSettingsPreferMatchedMetadataHelp": "Bei einem Schnellabgleich überschreiben online neu abgestimmte Metadaten alle schon vorhandenen Metadaten eines Mediums. Standardmäßig werden bei einem Schnellabgleich nur fehlende Metadaten ersetzt.", "LabelSettingsPreferMatchedMetadataHelp": "Bei einem Schnellabgleich überschreiben online neu abgestimmte Metadaten alle schon vorhandenen Metadaten eines Mediums. Standardmäßig werden bei einem Schnellabgleich nur fehlende Metadaten ersetzt.",
"LabelSettingsPreferOPFMetadata": "Bevorzuge OPF-Metadaten",
"LabelSettingsPreferOPFMetadataHelp": "In OPF-Dateien gespeicherte Metadaten werden anstelle der Ordnernamen für die Bereitstellung der Metadaten verwendet. OPF-Datein sind seperate \"Textdateien\" mit der Endung \".abs\" welche in dem gleichen Ordner liegen wie das Medium selber. In dieser sind verschiedene Metadaten (z.B. Titel, Autor, Jahr, Erzähler, Handlung, ISBN, ...) gespeichert. Wenn keine OPF Datei zur Verfügung steht, wird der Ordnername verwendet.",
"LabelSettingsSkipMatchingBooksWithASIN": "Überspringe beim Online-Abgleich alle Bücher die bereits eine ASIN haben", "LabelSettingsSkipMatchingBooksWithASIN": "Überspringe beim Online-Abgleich alle Bücher die bereits eine ASIN haben",
"LabelSettingsSkipMatchingBooksWithISBN": "Überspringe beim Online-Abgleich alle Bücher die bereits eine ISBN haben", "LabelSettingsSkipMatchingBooksWithISBN": "Überspringe beim Online-Abgleich alle Bücher die bereits eine ISBN haben",
"LabelSettingsSortingIgnorePrefixes": "Vorwort/Artikel beim Sortieren ignorieren", "LabelSettingsSortingIgnorePrefixes": "Vorwort/Artikel beim Sortieren ignorieren",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Titelbilder im Medienordner speichern", "LabelSettingsStoreCoversWithItem": "Titelbilder im Medienordner speichern",
"LabelSettingsStoreCoversWithItemHelp": "Standardmäßig werden die Titelbilder in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Titelbilder als jpg Datei in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet. Es wird immer nur eine Datei mit dem Namen \"cover.jpg\" gespeichert.", "LabelSettingsStoreCoversWithItemHelp": "Standardmäßig werden die Titelbilder in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Titelbilder als jpg Datei in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet. Es wird immer nur eine Datei mit dem Namen \"cover.jpg\" gespeichert.",
"LabelSettingsStoreMetadataWithItem": "Metadaten als OPF-Datei im Medienordner speichern", "LabelSettingsStoreMetadataWithItem": "Metadaten als OPF-Datei im Medienordner speichern",
"LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet. Es wird immer nur eine Datei mit dem Namen \"matadata.abs\" gespeichert.", "LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet",
"LabelSettingsTimeFormat": "Zeitformat", "LabelSettingsTimeFormat": "Zeitformat",
"LabelShowAll": "Alles anzeigen", "LabelShowAll": "Alles anzeigen",
"LabelSize": "Größe", "LabelSize": "Größe",
"LabelSleepTimer": "Einschlaf-Timer", "LabelSleepTimer": "Einschlaf-Timer",
"LabelSlug": "URL Teil",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStarted": "Gestartet", "LabelStarted": "Gestartet",
"LabelStartedAt": "Gestartet am", "LabelStartedAt": "Gestartet am",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Titel aus Metadaten", "LabelTrackFromMetadata": "Titel aus Metadaten",
"LabelTracks": "Dateien", "LabelTracks": "Dateien",
"LabelTracksMultiTrack": "Mehrfachdatei", "LabelTracksMultiTrack": "Mehrfachdatei",
"LabelTracksNone": "Keine Dateien",
"LabelTracksSingleTrack": "Einzeldatei", "LabelTracksSingleTrack": "Einzeldatei",
"LabelType": "Typ", "LabelType": "Typ",
"LabelUnabridged": "Ungekürzt", "LabelUnabridged": "Ungekürzt",
@@ -494,7 +524,7 @@
"LabelViewBookmarks": "Lesezeichen anzeigen", "LabelViewBookmarks": "Lesezeichen anzeigen",
"LabelViewChapters": "Kapitel anzeigen", "LabelViewChapters": "Kapitel anzeigen",
"LabelViewQueue": "Spieler-Warteschlange anzeigen", "LabelViewQueue": "Spieler-Warteschlange anzeigen",
"LabelVolume": "Volume", "LabelVolume": "Volumen",
"LabelWeekdaysToRun": "Wochentage für die Ausführung", "LabelWeekdaysToRun": "Wochentage für die Ausführung",
"LabelYourAudiobookDuration": "Laufzeit Ihres Mediums", "LabelYourAudiobookDuration": "Laufzeit Ihres Mediums",
"LabelYourBookmarks": "Lesezeichen", "LabelYourBookmarks": "Lesezeichen",
@@ -514,28 +544,34 @@
"MessageChapterErrorStartLtPrev": "Ungültige Kapitelstartzeit: Kapitelanfang < Kapitelanfang vorheriges Kapitel (Kapitelanfang liegt zeitlich vor dem Beginn des vorherigen Kapitels -> Lösung: Kapitelanfang >= Startzeit des vorherigen Kapitels)", "MessageChapterErrorStartLtPrev": "Ungültige Kapitelstartzeit: Kapitelanfang < Kapitelanfang vorheriges Kapitel (Kapitelanfang liegt zeitlich vor dem Beginn des vorherigen Kapitels -> Lösung: Kapitelanfang >= Startzeit des vorherigen Kapitels)",
"MessageChapterStartIsAfter": "Ungültige Kapitelstartzeit: Kapitelanfang > Mediumende (Kapitelanfang liegt nach dem Ende des Mediums)", "MessageChapterStartIsAfter": "Ungültige Kapitelstartzeit: Kapitelanfang > Mediumende (Kapitelanfang liegt nach dem Ende des Mediums)",
"MessageCheckingCron": "Überprüfe Cron...", "MessageCheckingCron": "Überprüfe Cron...",
"MessageConfirmDeleteBackup": "Sind Sie sicher, dass Sie die Sicherung für {0} löschen wollen?", "MessageConfirmCloseFeed": "Feed wird geschlossen! Sind Sie sicher?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteBackup": "Sicherung für {0} wird gelöscht! Sind Sie sicher?",
"MessageConfirmDeleteLibrary": "Sind Sie sicher, dass Sie die Bibliothek \"{0}\" dauerhaft löschen wollen?", "MessageConfirmDeleteFile": "Datei wird vom System gelöscht! Sind Sie sicher?",
"MessageConfirmDeleteSession": "Sind Sie sicher, dass Sie diese Sitzung löschen möchten?", "MessageConfirmDeleteLibrary": "Bibliothek \"{0}\" wird dauerhaft gelöscht! Sind Sie sicher?",
"MessageConfirmForceReScan": "Sind Sie sicher, dass Sie einen erneuten Scanvorgang erzwingen wollen?", "MessageConfirmDeleteLibraryItem": "Bibliothekselement wird aus der Datenbank + Festplatte gelöscht? Sind Sie sicher?",
"MessageConfirmMarkAllEpisodesFinished": "Sind Sie sicher, dass Sie alle Episoden als abgeschlossen markieren möchten?", "MessageConfirmDeleteLibraryItems": "{0} Bibliothekselemente werden aus der Datenbank + Festplatte gelöscht? Sind Sie sicher?",
"MessageConfirmMarkAllEpisodesNotFinished": "Sind Sie sicher, dass Sie alle Episoden als nicht abgeschlossen markieren möchten?", "MessageConfirmDeleteSession": "Sitzung wird gelöscht! Sind Sie sicher?",
"MessageConfirmMarkSeriesFinished": "Sind Sie sicher, dass Sie alle Medien dieser Reihe als abgeschlossen markieren wollen?", "MessageConfirmForceReScan": "Scanvorgang erzwingen! Sind Sie sicher?",
"MessageConfirmMarkSeriesNotFinished": "Sind Sie sicher, dass Sie alle Medien dieser Reihe als nicht abgeschlossen markieren wollen?", "MessageConfirmMarkAllEpisodesFinished": "Alle Episoden werden als abgeschlossen markiert! Sind Sie sicher?",
"MessageConfirmRemoveAllChapters": "Sind Sie sicher, dass Sie alle Kapitel entfernen möchten?", "MessageConfirmMarkAllEpisodesNotFinished": "Alle Episoden werden als nicht abgeschlossen markiert! Sind Sie sicher?",
"MessageConfirmRemoveCollection": "Sind Sie sicher, dass Sie die Sammlung \"{0}\" löschen wollen?", "MessageConfirmMarkSeriesFinished": "Alle Medien dieser Reihe werden als abgeschlossen markiert! Sind Sie sicher?",
"MessageConfirmRemoveEpisode": "Sind Sie sicher, dass Sie die Episode \"{0}\" löschen möchten?", "MessageConfirmMarkSeriesNotFinished": "Alle Medien dieser Reihe werden als nicht abgeschlossen markiert! Sind Sie sicher?",
"MessageConfirmRemoveEpisodes": "Sind Sie sicher, dass Sie {0} Episoden löschen wollen?", "MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achten Sie darauf, dass Sie eine Sicherungskopie der Audiodateien besitzen. <br><br>Möchten Sie fortfahren?",
"MessageConfirmRemoveNarrator": "Sind Sie sicher, dass Sie den Erzähler \"{0}\" löschen möchten?", "MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Sind Sie sicher?",
"MessageConfirmRemovePlaylist": "Sind Sie sicher, dass Sie die Wiedergabeliste \"{0}\" entfernen möchten?", "MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Sind Sie sicher?",
"MessageConfirmRenameGenre": "Sind Sie sicher, dass Sie die Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts umbenennen wollen?", "MessageConfirmRemoveCollection": "Sammlung \"{0}\" wird gelöscht! Sind Sie sicher?",
"MessageConfirmRemoveEpisode": "Episode \"{0}\" wird geloscht! Sind Sie sicher?",
"MessageConfirmRemoveEpisodes": "{0} Episoden werden gelöscht! Sind Sie sicher?",
"MessageConfirmRemoveNarrator": "Erzähler \"{0}\" wird gelöscht! Sind Sie sicher?",
"MessageConfirmRemovePlaylist": "Wiedergabeliste \"{0}\" wird entfernt! Sind Sie sicher?",
"MessageConfirmRenameGenre": "Kategorie \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Sind Sie sicher?",
"MessageConfirmRenameGenreMergeNote": "Hinweis: Kategorie existiert bereits -> Kategorien werden zusammengelegt.", "MessageConfirmRenameGenreMergeNote": "Hinweis: Kategorie existiert bereits -> Kategorien werden zusammengelegt.",
"MessageConfirmRenameGenreWarning": "Warnung! Ein ähnliche Kategorie mit einem anderen Wortlaut existiert bereits: \"{0}\".", "MessageConfirmRenameGenreWarning": "Warnung! Ein ähnliche Kategorie mit einem anderen Wortlaut existiert bereits: \"{0}\".",
"MessageConfirmRenameTag": "Sind Sie sicher, dass Sie den Tag \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts umbenennen wollen?", "MessageConfirmRenameTag": "Tag \"{0}\" in \"{1}\" für alle Hörbücher/Podcasts werden umbenannt! Sind Sie sicher?",
"MessageConfirmRenameTagMergeNote": "Hinweis: Tag existiert bereits -> Tags werden zusammengelegt.", "MessageConfirmRenameTagMergeNote": "Hinweis: Tag existiert bereits -> Tags werden zusammengelegt.",
"MessageConfirmRenameTagWarning": "Warnung! Ein ähnlicher Tag mit einem anderen Wortlaut existiert bereits: \"{0}\".", "MessageConfirmRenameTagWarning": "Warnung! Ein ähnlicher Tag mit einem anderen Wortlaut existiert bereits: \"{0}\".",
"MessageConfirmSendEbookToDevice": "Sind Sie sicher, dass sie {0} ebook \"{1}\" auf das Gerät \"{2}\" senden wollen?", "MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Sind Sie sicher?",
"MessageConfirmSendEbookToDevice": "{0} E-Book \"{1}\" werden auf das Gerät \"{2}\" gesendet! Sind Sie sicher?",
"MessageDownloadingEpisode": "Episode herunterladen", "MessageDownloadingEpisode": "Episode herunterladen",
"MessageDragFilesIntoTrackOrder": "Verschieben Sie die Dateien in die richtige Reihenfolge", "MessageDragFilesIntoTrackOrder": "Verschieben Sie die Dateien in die richtige Reihenfolge",
"MessageEmbedFinished": "Einbettung abgeschlossen!", "MessageEmbedFinished": "Einbettung abgeschlossen!",
@@ -558,7 +594,7 @@
"MessageMarkAllEpisodesNotFinished": "Alle Episoden als ungehört markieren", "MessageMarkAllEpisodesNotFinished": "Alle Episoden als ungehört markieren",
"MessageMarkAsFinished": "Als beendet markieren", "MessageMarkAsFinished": "Als beendet markieren",
"MessageMarkAsNotFinished": "Als nicht abgeschlossen markieren", "MessageMarkAsNotFinished": "Als nicht abgeschlossen markieren",
"MessageMatchBooksDescription": "versucht, Bücher in der Bibliothek mit einem Buch des ausgewählten Suchanbieters abzugleichen und leere Details und das Titelbild auszufüllen. Details werden nicht überschrieben.", "MessageMatchBooksDescription": "Es wird versucht die Bücher in der Bibliothek mit einem Buch des ausgewählten Suchanbieters abzugleichen um leere Details und das Titelbild auszufüllen. Vorhandene Details werden nicht überschrieben.",
"MessageNoAudioTracks": "Keine Audiodateien", "MessageNoAudioTracks": "Keine Audiodateien",
"MessageNoAuthors": "Keine Autoren", "MessageNoAuthors": "Keine Autoren",
"MessageNoBackups": "Keine Sicherungen", "MessageNoBackups": "Keine Sicherungen",
@@ -594,14 +630,14 @@
"MessagePauseChapter": "Kapitelwiedergabe pausieren", "MessagePauseChapter": "Kapitelwiedergabe pausieren",
"MessagePlayChapter": "Kapitelanfang anhören", "MessagePlayChapter": "Kapitelanfang anhören",
"MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung", "MessagePlaylistCreateFromCollection": "Erstelle eine Wiedergabeliste aus der Sammlung",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann", "MessagePodcastHasNoRSSFeedForMatching": "Der Podcast hat keine RSS-Feed-Url welche für den Online-Abgleich verwendet werden kann",
"MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.", "MessageQuickMatchDescription": "Füllt leere Details und Titelbilder mit dem ersten Treffer aus '{0}'. Überschreibt keine Details, es sei denn, die Server-Einstellung \"Passende Metadaten bevorzugen\" ist aktiviert.",
"MessageRemoveChapter": "Kapitel löschen", "MessageRemoveChapter": "Kapitel löschen",
"MessageRemoveEpisodes": "Entferne {0} Episode(n)", "MessageRemoveEpisodes": "Entferne {0} Episode(n)",
"MessageRemoveFromPlayerQueue": "Aus der Abspielwarteliste löschen", "MessageRemoveFromPlayerQueue": "Aus der Abspielwarteliste löschen",
"MessageRemoveUserWarning": "Sind Sie sicher, dass Sie den Benutzer \"{0}\" dauerhaft löschen wollen?", "MessageRemoveUserWarning": "Benutzer \"{0}\" wird dauerhaft gelöscht! Sind Sie sicher?",
"MessageReportBugsAndContribute": "Fehler melden, Funktionen anfordern und Beiträge leisten auf", "MessageReportBugsAndContribute": "Fehler melden, Funktionen anfordern und Beiträge leisten auf",
"MessageResetChaptersConfirm": "Sind Sie sicher, dass Sie die Kapitel zurücksetzen und die vorgenommenen Änderungen rückgängig machen wollen?", "MessageResetChaptersConfirm": "Kapitel und vorgenommenen Änderungen werden zurückgesetzt und rückgängig gemacht! Sind Sie sicher?",
"MessageRestoreBackupConfirm": "Sind Sie sicher, dass Sie die Sicherung wiederherstellen wollen, welche am", "MessageRestoreBackupConfirm": "Sind Sie sicher, dass Sie die Sicherung wiederherstellen wollen, welche am",
"MessageRestoreBackupWarning": "Bei der Wiederherstellung einer Sicherung wird die gesamte Datenbank unter /config und die Titelbilder in /metadata/items und /metadata/authors überschrieben.<br /><br />Bei der Sicherung werden keine Dateien in Ihren Bibliotheksordnern verändert. Wenn Sie die Servereinstellungen aktiviert haben, um Cover und Metadaten in Ihren Bibliotheksordnern zu speichern, werden diese nicht gesichert oder überschrieben.<br /><br />Alle Clients, die Ihren Server nutzen, werden automatisch aktualisiert.", "MessageRestoreBackupWarning": "Bei der Wiederherstellung einer Sicherung wird die gesamte Datenbank unter /config und die Titelbilder in /metadata/items und /metadata/authors überschrieben.<br /><br />Bei der Sicherung werden keine Dateien in Ihren Bibliotheksordnern verändert. Wenn Sie die Servereinstellungen aktiviert haben, um Cover und Metadaten in Ihren Bibliotheksordnern zu speichern, werden diese nicht gesichert oder überschrieben.<br /><br />Alle Clients, die Ihren Server nutzen, werden automatisch aktualisiert.",
"MessageSearchResultsFor": "Suchergebnisse für", "MessageSearchResultsFor": "Suchergebnisse für",
@@ -702,4 +738,4 @@
"ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen", "ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen",
"ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden", "ToastUserDeleteFailed": "Benutzer konnte nicht gelöscht werden",
"ToastUserDeleteSuccess": "Benutzer gelöscht" "ToastUserDeleteSuccess": "Benutzer gelöscht"
} }
+44 -8
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Add", "ButtonAdd": "Add",
"ButtonAddChapters": "Add Chapters", "ButtonAddChapters": "Add Chapters",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Add Podcasts", "ButtonAddPodcasts": "Add Podcasts",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Add your first library", "ButtonAddYourFirstLibrary": "Add your first library",
"ButtonApply": "Apply", "ButtonApply": "Apply",
"ButtonApplyChapters": "Apply Chapters", "ButtonApplyChapters": "Apply Chapters",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Remove Series from Continue Series", "ButtonRemoveSeriesFromContinueSeries": "Remove Series from Continue Series",
"ButtonReScan": "Re-Scan", "ButtonReScan": "Re-Scan",
"ButtonReset": "Reset", "ButtonReset": "Reset",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Restore", "ButtonRestore": "Restore",
"ButtonSave": "Save", "ButtonSave": "Save",
"ButtonSaveAndClose": "Save & Close", "ButtonSaveAndClose": "Save & Close",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise Notification Settings", "HeaderAppriseNotificationSettings": "Apprise Notification Settings",
"HeaderAudiobookTools": "Audiobook File Management Tools", "HeaderAudiobookTools": "Audiobook File Management Tools",
"HeaderAudioTracks": "Audio Tracks", "HeaderAudioTracks": "Audio Tracks",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Backups", "HeaderBackups": "Backups",
"HeaderChangePassword": "Change Password", "HeaderChangePassword": "Change Password",
"HeaderChapters": "Chapters", "HeaderChapters": "Chapters",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Manage Tags", "HeaderManageTags": "Manage Tags",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Map details",
"HeaderMatch": "Match", "HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadata to embed", "HeaderMetadataToEmbed": "Metadata to embed",
"HeaderNewAccount": "New Account", "HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library", "HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications", "HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed", "HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files", "HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions", "HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue", "HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Remove {0} Episodes", "HeaderRemoveEpisodes": "Remove {0} Episodes",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed is Open", "HeaderRSSFeedIsOpen": "RSS Feed is Open",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Saved Media Progress", "HeaderSavedMediaProgress": "Saved Media Progress",
"HeaderSchedule": "Schedule", "HeaderSchedule": "Schedule",
"HeaderScheduleLibraryScans": "Schedule Automatic Library Scans", "HeaderScheduleLibraryScans": "Schedule Automatic Library Scans",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Add {0} Books to Collection", "LabelAddToCollectionBatch": "Add {0} Books to Collection",
"LabelAddToPlaylist": "Add to Playlist", "LabelAddToPlaylist": "Add to Playlist",
"LabelAddToPlaylistBatch": "Add {0} Items to Playlist", "LabelAddToPlaylistBatch": "Add {0} Items to Playlist",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "All", "LabelAll": "All",
"LabelAllUsers": "All Users", "LabelAllUsers": "All Users",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Already in your library", "LabelAlreadyInYourLibrary": "Already in your library",
"LabelAppend": "Append", "LabelAppend": "Append",
"LabelAuthor": "Author", "LabelAuthor": "Author",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Author (Last, First)", "LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors", "LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes", "LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User", "LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups", "LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximum backup size (in GB)", "LabelBackupsMaxBackupSize": "Maximum backup size (in GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.", "LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Books", "LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password", "LabelChangePassword": "Change Password",
"LabelChannels": "Channels", "LabelChannels": "Channels",
"LabelChapters": "Chapters", "LabelChapters": "Chapters",
"LabelChaptersFound": "chapters found", "LabelChaptersFound": "chapters found",
"LabelChapterTitle": "Chapter Title", "LabelChapterTitle": "Chapter Title",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Close player", "LabelClosePlayer": "Close player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Collapse Series", "LabelCollapseSeries": "Collapse Series",
"LabelCollection": "Collection",
"LabelCollections": "Collections", "LabelCollections": "Collections",
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
@@ -215,13 +235,16 @@
"LabelCurrently": "Currently:", "LabelCurrently": "Currently:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Custom Cron Expression:",
"LabelDatetime": "Datetime", "LabelDatetime": "Datetime",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Description", "LabelDescription": "Description",
"LabelDeselectAll": "Deselect All", "LabelDeselectAll": "Deselect All",
"LabelDevice": "Device", "LabelDevice": "Device",
"LabelDeviceInfo": "Device Info", "LabelDeviceInfo": "Device Info",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Directory", "LabelDirectory": "Directory",
"LabelDiscFromFilename": "Disc from Filename", "LabelDiscFromFilename": "Disc from Filename",
"LabelDiscFromMetadata": "Disc from Metadata", "LabelDiscFromMetadata": "Disc from Metadata",
"LabelDiscover": "Discover",
"LabelDownload": "Download", "LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Duration", "LabelDuration": "Duration",
@@ -252,6 +275,7 @@
"LabelFinished": "Finished", "LabelFinished": "Finished",
"LabelFolder": "Folder", "LabelFolder": "Folder",
"LabelFolders": "Folders", "LabelFolders": "Folders",
"LabelFontFamily": "Font family",
"LabelFontScale": "Font scale", "LabelFontScale": "Font scale",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Genre", "LabelGenre": "Genre",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Hard delete file", "LabelHardDeleteFile": "Hard delete file",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Has ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Has supplementary ebook",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Hour", "LabelHour": "Hour",
"LabelIcon": "Icon", "LabelIcon": "Icon",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Include in Tracklist", "LabelIncludeInTracklist": "Include in Tracklist",
"LabelIncomplete": "Incomplete", "LabelIncomplete": "Incomplete",
"LabelInProgress": "In Progress", "LabelInProgress": "In Progress",
@@ -299,8 +325,12 @@
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn", "LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date", "LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadata Provider", "LabelMetadataProvider": "Metadata Provider",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Season", "LabelSeason": "Season",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Select all episodes",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Select {0} episodes showing",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSendEbookToDevice": "Send Ebook to...",
"LabelSequence": "Sequence", "LabelSequence": "Sequence",
"LabelSeries": "Series", "LabelSeries": "Series",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Disable Watcher", "LabelSettingsDisableWatcher": "Disable Watcher",
"LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library", "LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library",
"LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart", "LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsEnableWatcher": "Enable Watcher",
"LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
"LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Experimental features", "LabelSettingsExperimentalFeatures": "Experimental features",
"LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.", "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
"LabelSettingsFindCovers": "Find covers", "LabelSettingsFindCovers": "Find covers",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view", "LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view", "LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
"LabelSettingsOverdriveMediaMarkers": "Use Overdrive Media Markers for chapters",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically",
"LabelSettingsParseSubtitles": "Parse subtitles", "LabelSettingsParseSubtitles": "Parse subtitles",
"LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"", "LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"",
"LabelSettingsPreferAudioMetadata": "Prefer audio metadata",
"LabelSettingsPreferAudioMetadataHelp": "Audio file ID3 meta tags will be used for book details over folder names",
"LabelSettingsPreferMatchedMetadata": "Prefer matched metadata", "LabelSettingsPreferMatchedMetadata": "Prefer matched metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.", "LabelSettingsPreferMatchedMetadataHelp": "Matched data will override item details when using Quick Match. By default Quick Match will only fill in missing details.",
"LabelSettingsPreferOPFMetadata": "Prefer OPF metadata",
"LabelSettingsPreferOPFMetadataHelp": "OPF file metadata will be used for book details over folder names",
"LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting", "LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Store covers with item", "LabelSettingsStoreCoversWithItem": "Store covers with item",
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept", "LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
"LabelSettingsStoreMetadataWithItem": "Store metadata with item", "LabelSettingsStoreMetadataWithItem": "Store metadata with item",
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension", "LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders",
"LabelSettingsTimeFormat": "Time Format", "LabelSettingsTimeFormat": "Time Format",
"LabelShowAll": "Show All", "LabelShowAll": "Show All",
"LabelSize": "Size", "LabelSize": "Size",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSlug": "Slug",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStarted": "Started", "LabelStarted": "Started",
"LabelStartedAt": "Started At", "LabelStartedAt": "Started At",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Track from Metadata", "LabelTrackFromMetadata": "Track from Metadata",
"LabelTracks": "Tracks", "LabelTracks": "Tracks",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Single-track", "LabelTracksSingleTrack": "Single-track",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "Unabridged",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time", "MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time",
"MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook", "MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook",
"MessageCheckingCron": "Checking cron...", "MessageCheckingCron": "Checking cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?", "MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?",
"MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?", "MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Are you sure you want to delete this session?", "MessageConfirmDeleteSession": "Are you sure you want to delete this session?",
"MessageConfirmForceReScan": "Are you sure you want to force re-scan?", "MessageConfirmForceReScan": "Are you sure you want to force re-scan?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?",
"MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?", "MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?",
"MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?", "MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?", "MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?", "MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?",
"MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?", "MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?", "MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?",
@@ -535,6 +570,7 @@
"MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?", "MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?",
"MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.", "MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.",
"MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".", "MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?",
"MessageDownloadingEpisode": "Downloading episode", "MessageDownloadingEpisode": "Downloading episode",
"MessageDragFilesIntoTrackOrder": "Drag files into correct track order", "MessageDragFilesIntoTrackOrder": "Drag files into correct track order",
+253 -217
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Agregar", "ButtonAdd": "Agregar",
"ButtonAddChapters": "Agregar Capitulo", "ButtonAddChapters": "Agregar Capitulo",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Agregar Podcasts", "ButtonAddPodcasts": "Agregar Podcasts",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Agrega tu Primera Biblioteca", "ButtonAddYourFirstLibrary": "Agrega tu Primera Biblioteca",
"ButtonApply": "Aplicar", "ButtonApply": "Aplicar",
"ButtonApplyChapters": "Aplicar Capítulos", "ButtonApplyChapters": "Aplicar Capítulos",
@@ -20,11 +23,11 @@
"ButtonCreate": "Crear", "ButtonCreate": "Crear",
"ButtonCreateBackup": "Crear Respaldo", "ButtonCreateBackup": "Crear Respaldo",
"ButtonDelete": "Eliminar", "ButtonDelete": "Eliminar",
"ButtonDownloadQueue": "Queue", "ButtonDownloadQueue": "Fila",
"ButtonEdit": "Editar", "ButtonEdit": "Editar",
"ButtonEditChapters": "Editar Capitulo", "ButtonEditChapters": "Editar Capítulo",
"ButtonEditPodcast": "Editar Podcast", "ButtonEditPodcast": "Editar Podcast",
"ButtonForceReScan": "Forzar Re-Escanear", "ButtonForceReScan": "Forzar Re-Escaneo",
"ButtonFullPath": "Ruta de Acceso Completa", "ButtonFullPath": "Ruta de Acceso Completa",
"ButtonHide": "Esconder", "ButtonHide": "Esconder",
"ButtonHome": "Inicio", "ButtonHome": "Inicio",
@@ -34,13 +37,13 @@
"ButtonLogout": "Cerrar Sesión", "ButtonLogout": "Cerrar Sesión",
"ButtonLookup": "Buscar", "ButtonLookup": "Buscar",
"ButtonManageTracks": "Administrar Pistas de Audio", "ButtonManageTracks": "Administrar Pistas de Audio",
"ButtonMapChapterTitles": "Map Chapter Titles", "ButtonMapChapterTitles": "Asignar Títulos a Capítulos",
"ButtonMatchAllAuthors": "Encontrar Todos los Autores", "ButtonMatchAllAuthors": "Encontrar Todos los Autores",
"ButtonMatchBooks": "Encontrar Libros", "ButtonMatchBooks": "Encontrar Libros",
"ButtonNevermind": "Olvidar", "ButtonNevermind": "Olvidar",
"ButtonOk": "Ok", "ButtonOk": "Ok",
"ButtonOpenFeed": "Abrir Fuente", "ButtonOpenFeed": "Abrir Fuente",
"ButtonOpenManager": "Open Manager", "ButtonOpenManager": "Abrir Editor",
"ButtonPlay": "Reproducir", "ButtonPlay": "Reproducir",
"ButtonPlaying": "Reproduciendo", "ButtonPlaying": "Reproduciendo",
"ButtonPlaylists": "Listas de Reproducción", "ButtonPlaylists": "Listas de Reproducción",
@@ -55,10 +58,11 @@
"ButtonRemoveAll": "Remover Todos", "ButtonRemoveAll": "Remover Todos",
"ButtonRemoveAllLibraryItems": "Remover Todos los Elementos de la Biblioteca", "ButtonRemoveAllLibraryItems": "Remover Todos los Elementos de la Biblioteca",
"ButtonRemoveFromContinueListening": "Remover de Continuar Escuchando", "ButtonRemoveFromContinueListening": "Remover de Continuar Escuchando",
"ButtonRemoveFromContinueReading": "Remove from Continue Reading", "ButtonRemoveFromContinueReading": "Remover de Continuar Leyendo",
"ButtonRemoveSeriesFromContinueSeries": "Remover Serie de Continuar Series", "ButtonRemoveSeriesFromContinueSeries": "Remover Serie de Continuar Series",
"ButtonReScan": "Re-Escanear", "ButtonReScan": "Re-Escanear",
"ButtonReset": "Reiniciar", "ButtonReset": "Reiniciar",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Restaurar", "ButtonRestore": "Restaurar",
"ButtonSave": "Guardar", "ButtonSave": "Guardar",
"ButtonSaveAndClose": "Guardar y Cerrar", "ButtonSaveAndClose": "Guardar y Cerrar",
@@ -74,7 +78,7 @@
"ButtonStartM4BEncode": "Iniciar Codificación M4B", "ButtonStartM4BEncode": "Iniciar Codificación M4B",
"ButtonStartMetadataEmbed": "Iniciar la Inserción de Metadata", "ButtonStartMetadataEmbed": "Iniciar la Inserción de Metadata",
"ButtonSubmit": "Enviar", "ButtonSubmit": "Enviar",
"ButtonTest": "Test", "ButtonTest": "Prueba",
"ButtonUpload": "Subir", "ButtonUpload": "Subir",
"ButtonUploadBackup": "Subir Respaldo", "ButtonUploadBackup": "Subir Respaldo",
"ButtonUploadCover": "Subir Portada", "ButtonUploadCover": "Subir Portada",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Ajustes de Notificaciones de Apprise", "HeaderAppriseNotificationSettings": "Ajustes de Notificaciones de Apprise",
"HeaderAudiobookTools": "Herramientas de Gestión de Archivos de Audiolibro", "HeaderAudiobookTools": "Herramientas de Gestión de Archivos de Audiolibro",
"HeaderAudioTracks": "Pistas de Audio", "HeaderAudioTracks": "Pistas de Audio",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Respaldos", "HeaderBackups": "Respaldos",
"HeaderChangePassword": "Cambiar Contraseña", "HeaderChangePassword": "Cambiar Contraseña",
"HeaderChapters": "Capítulos", "HeaderChapters": "Capítulos",
@@ -98,12 +103,12 @@
"HeaderCurrentDownloads": "Descargando Actualmente", "HeaderCurrentDownloads": "Descargando Actualmente",
"HeaderDetails": "Detalles", "HeaderDetails": "Detalles",
"HeaderDownloadQueue": "Lista de Descarga", "HeaderDownloadQueue": "Lista de Descarga",
"HeaderEbookFiles": "Ebook Files", "HeaderEbookFiles": "Archivos de Ebook",
"HeaderEmail": "Email", "HeaderEmail": "Email",
"HeaderEmailSettings": "Email Settings", "HeaderEmailSettings": "Opciones de Email",
"HeaderEpisodes": "Episodios", "HeaderEpisodes": "Episodios",
"HeaderEreaderDevices": "Ereader Devices", "HeaderEreaderDevices": "Dispositivos Ereader",
"HeaderEreaderSettings": "Ereader Settings", "HeaderEreaderSettings": "Opciones de Ereader",
"HeaderFiles": "Elemento", "HeaderFiles": "Elemento",
"HeaderFindChapters": "Buscar Capitulo", "HeaderFindChapters": "Buscar Capitulo",
"HeaderIgnoredFiles": "Ignorar Elemento", "HeaderIgnoredFiles": "Ignorar Elemento",
@@ -120,16 +125,19 @@
"HeaderLogs": "Logs", "HeaderLogs": "Logs",
"HeaderManageGenres": "Administrar Géneros", "HeaderManageGenres": "Administrar Géneros",
"HeaderManageTags": "Administrar Etiquetas", "HeaderManageTags": "Administrar Etiquetas",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Asignar Detalles",
"HeaderMatch": "Encontrar", "HeaderMatch": "Encontrar",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadatos para Insertar", "HeaderMetadataToEmbed": "Metadatos para Insertar",
"HeaderNewAccount": "Nueva Cuenta", "HeaderNewAccount": "Nueva Cuenta",
"HeaderNewLibrary": "Nueva Biblioteca", "HeaderNewLibrary": "Nueva Biblioteca",
"HeaderNotifications": "Notificaciones", "HeaderNotifications": "Notificaciones",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Abrir fuente RSS", "HeaderOpenRSSFeed": "Abrir fuente RSS",
"HeaderOtherFiles": "Otros Archivos", "HeaderOtherFiles": "Otros Archivos",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permisos", "HeaderPermissions": "Permisos",
"HeaderPlayerQueue": "Player Queue", "HeaderPlayerQueue": "Fila del Reproductor",
"HeaderPlaylist": "Lista de Reproducción", "HeaderPlaylist": "Lista de Reproducción",
"HeaderPlaylistItems": "Elementos de Lista de Reproducción", "HeaderPlaylistItems": "Elementos de Lista de Reproducción",
"HeaderPodcastsToAdd": "Podcasts para agregar", "HeaderPodcastsToAdd": "Podcasts para agregar",
@@ -138,13 +146,14 @@
"HeaderRemoveEpisodes": "Remover {0} Episodios", "HeaderRemoveEpisodes": "Remover {0} Episodios",
"HeaderRSSFeedGeneral": "Detalles RSS", "HeaderRSSFeedGeneral": "Detalles RSS",
"HeaderRSSFeedIsOpen": "Fuente RSS esta abierta", "HeaderRSSFeedIsOpen": "Fuente RSS esta abierta",
"HeaderSavedMediaProgress": "Guardar Progreso de multimedia", "HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Guardar Progreso de Multimedia",
"HeaderSchedule": "Horario", "HeaderSchedule": "Horario",
"HeaderScheduleLibraryScans": "Programar Escaneo Automático de Biblioteca", "HeaderScheduleLibraryScans": "Programar Escaneo Automático de Biblioteca",
"HeaderSession": "Session", "HeaderSession": "Session",
"HeaderSetBackupSchedule": "Programar Respaldo", "HeaderSetBackupSchedule": "Programar Respaldo",
"HeaderSettings": "Configuraciones", "HeaderSettings": "Configuraciones",
"HeaderSettingsDisplay": "Display", "HeaderSettingsDisplay": "Interfaz",
"HeaderSettingsExperimental": "Funciones Experimentales", "HeaderSettingsExperimental": "Funciones Experimentales",
"HeaderSettingsGeneral": "General", "HeaderSettingsGeneral": "General",
"HeaderSettingsScanner": "Escáner", "HeaderSettingsScanner": "Escáner",
@@ -155,28 +164,31 @@
"HeaderStatsRecentSessions": "Sesiones Recientes", "HeaderStatsRecentSessions": "Sesiones Recientes",
"HeaderStatsTop10Authors": "Top 10 Autores", "HeaderStatsTop10Authors": "Top 10 Autores",
"HeaderStatsTop5Genres": "Top 5 Géneros", "HeaderStatsTop5Genres": "Top 5 Géneros",
"HeaderTableOfContents": "Table of Contents", "HeaderTableOfContents": "Tabla de Contenidos",
"HeaderTools": "Herramientas", "HeaderTools": "Herramientas",
"HeaderUpdateAccount": "Actualizar Cuenta", "HeaderUpdateAccount": "Actualizar Cuenta",
"HeaderUpdateAuthor": "Actualizar Autor", "HeaderUpdateAuthor": "Actualizar Autor",
"HeaderUpdateDetails": "Actualizar Detalles", "HeaderUpdateDetails": "Actualizar Detalles",
"HeaderUpdateLibrary": "Actualizar Biblioteca", "HeaderUpdateLibrary": "Actualizar Biblioteca",
"HeaderUsers": "Usuarios", "HeaderUsers": "Usuarios",
"HeaderYourStats": "Tus Estáticas", "HeaderYourStats": "Tus Estadísticas",
"LabelAbridged": "Abridged", "LabelAbridged": "Abreviado",
"LabelAccountType": "Tipo de Cuenta", "LabelAccountType": "Tipo de Cuenta",
"LabelAccountTypeAdmin": "Administrador", "LabelAccountTypeAdmin": "Administrador",
"LabelAccountTypeGuest": "Invitado", "LabelAccountTypeGuest": "Invitado",
"LabelAccountTypeUser": "Usuario", "LabelAccountTypeUser": "Usuario",
"LabelActivity": "Actividad", "LabelActivity": "Actividad",
"LabelAdded": "Added", "LabelAdded": "Añadido",
"LabelAddedAt": "Añadido", "LabelAddedAt": "Añadido",
"LabelAddToCollection": "Añadido a la Colección", "LabelAddToCollection": "Añadido a la Colección",
"LabelAddToCollectionBatch": "Se Añadieron {0} Libros a la Colección", "LabelAddToCollectionBatch": "Se Añadieron {0} Libros a la Colección",
"LabelAddToPlaylist": "Añadido a la Lista de Reproducción", "LabelAddToPlaylist": "Añadido a la Lista de Reproducción",
"LabelAddToPlaylistBatch": "Se Añadieron {0} Artículos a la Lista de Reproducción", "LabelAddToPlaylistBatch": "Se Añadieron {0} Artículos a la Lista de Reproducción",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "Todos", "LabelAll": "Todos",
"LabelAllUsers": "Todos los Usuarios", "LabelAllUsers": "Todos los Usuarios",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Ya en la Biblioteca", "LabelAlreadyInYourLibrary": "Ya en la Biblioteca",
"LabelAppend": "Adjuntar", "LabelAppend": "Adjuntar",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
@@ -184,56 +196,67 @@
"LabelAuthorLastFirst": "Autor (Apellido, Nombre)", "LabelAuthorLastFirst": "Autor (Apellido, Nombre)",
"LabelAuthors": "Autores", "LabelAuthors": "Autores",
"LabelAutoDownloadEpisodes": "Descargar Episodios Automáticamente", "LabelAutoDownloadEpisodes": "Descargar Episodios Automáticamente",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Regresar a Usuario", "LabelBackToUser": "Regresar a Usuario",
"LabelBackupLocation": "Ubicación del Respaldo",
"LabelBackupsEnableAutomaticBackups": "Habilitar Respaldo Automático", "LabelBackupsEnableAutomaticBackups": "Habilitar Respaldo Automático",
"LabelBackupsEnableAutomaticBackupsHelp": "Respaldo Guardado en /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Respaldo Guardado en /metadata/backups",
"LabelBackupsMaxBackupSize": "Tamaño Máximo de Respaldos (en GB)", "LabelBackupsMaxBackupSize": "Tamaño Máximo de Respaldos (en GB)",
"LabelBackupsMaxBackupSizeHelp": "Como protección contra una configuración errónea, los respaldos fallaran si se excede el tamaño configurado.", "LabelBackupsMaxBackupSizeHelp": "Como protección contra una configuración errónea, los respaldos fallarán si se excede el tamaño configurado.",
"LabelBackupsNumberToKeep": "Numero de respaldos para conservar", "LabelBackupsNumberToKeep": "Numero de respaldos para conservar",
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, necesita removerlos manualmente.", "LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Libros", "LabelBooks": "Libros",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Cambiar Contraseña", "LabelChangePassword": "Cambiar Contraseña",
"LabelChannels": "Canales", "LabelChannels": "Canales",
"LabelChapters": "Capitulos", "LabelChapters": "Capítulos",
"LabelChaptersFound": "Capitulo Encontrado", "LabelChaptersFound": "Capítulo Encontrado",
"LabelChapterTitle": "Titulo del Capitulo", "LabelChapterTitle": "Titulo del Capítulo",
"LabelClosePlayer": "Close player", "LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Cerrar Reproductor",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Colapsar Series", "LabelCollapseSeries": "Colapsar Serie",
"LabelCollection": "Colección",
"LabelCollections": "Colecciones", "LabelCollections": "Colecciones",
"LabelComplete": "Completo", "LabelComplete": "Completo",
"LabelConfirmPassword": "Confirmar Contraseña", "LabelConfirmPassword": "Confirmar Contraseña",
"LabelContinueListening": "Continuar Escuchando", "LabelContinueListening": "Continuar Escuchando",
"LabelContinueReading": "Continue Reading", "LabelContinueReading": "Continuar Leyendo",
"LabelContinueSeries": "Continuar Series", "LabelContinueSeries": "Continuar Serie",
"LabelCover": "Portada", "LabelCover": "Portada",
"LabelCoverImageURL": "URL de Imagen de Portada", "LabelCoverImageURL": "URL de Imagen de Portada",
"LabelCreatedAt": "Creado", "LabelCreatedAt": "Creado",
"LabelCronExpression": "Cron Expression", "LabelCronExpression": "Expresión de Cron",
"LabelCurrent": "Actual", "LabelCurrent": "Actual",
"LabelCurrently": "En este momento:", "LabelCurrently": "En este momento:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Expresión de Cron Personalizada:",
"LabelDatetime": "Datetime", "LabelDatetime": "Hora y Fecha",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Descripción", "LabelDescription": "Descripción",
"LabelDeselectAll": "Deseleccionar Todos", "LabelDeselectAll": "Deseleccionar Todos",
"LabelDevice": "Dispositivo", "LabelDevice": "Dispositivo",
"LabelDeviceInfo": "Información de Dispositivo", "LabelDeviceInfo": "Información de Dispositivo",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Directorio", "LabelDirectory": "Directorio",
"LabelDiscFromFilename": "Disco a partir del Nombre del Archivo", "LabelDiscFromFilename": "Disco a partir del Nombre del Archivo",
"LabelDiscFromMetadata": "Disco a partir de Metadata", "LabelDiscFromMetadata": "Disco a partir de Metadata",
"LabelDiscover": "Descubrir",
"LabelDownload": "Descargar", "LabelDownload": "Descargar",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Descargar {0} episodios",
"LabelDuration": "Duración", "LabelDuration": "Duración",
"LabelDurationFound": "Duración Comprobada:", "LabelDurationFound": "Duración Comprobada:",
"LabelEbook": "Ebook", "LabelEbook": "Ebook",
"LabelEbooks": "Ebooks", "LabelEbooks": "Ebooks",
"LabelEdit": "Editar", "LabelEdit": "Editar",
"LabelEmail": "Email", "LabelEmail": "Email",
"LabelEmailSettingsFromAddress": "From Address", "LabelEmailSettingsFromAddress": "Remitente",
"LabelEmailSettingsSecure": "Secure", "LabelEmailSettingsSecure": "Seguridad",
"LabelEmailSettingsSecureHelp": "If true the connection will use TLS when connecting to server. If false then TLS is used if server supports the STARTTLS extension. In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false. (from nodemailer.com/smtp/#authentication)", "LabelEmailSettingsSecureHelp": "Si está activado, se usará TLS para conectarse al servidor. Si está apagado, se usará TLS si su servidor tiene soporte para la extensión STARTTLS. En la mayoría de los casos, puede dejar esta opción activada si se está conectando al puerto 465. Apáguela en el caso de usar los puertos 587 o 25. (de nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Test Address", "LabelEmailSettingsTestAddress": "Probar Dirección",
"LabelEmbeddedCover": "Portada Integrada", "LabelEmbeddedCover": "Portada Integrada",
"LabelEnable": "Habilitar", "LabelEnable": "Habilitar",
"LabelEnd": "Fin", "LabelEnd": "Fin",
@@ -252,16 +275,19 @@
"LabelFinished": "Terminado", "LabelFinished": "Terminado",
"LabelFolder": "Carpeta", "LabelFolder": "Carpeta",
"LabelFolders": "Carpetas", "LabelFolders": "Carpetas",
"LabelFontScale": "Font scale", "LabelFontFamily": "Familia tipográfica",
"LabelFontScale": "Tamaño de Fuente",
"LabelFormat": "Formato", "LabelFormat": "Formato",
"LabelGenre": "Genero", "LabelGenre": "Genero",
"LabelGenres": "Géneros", "LabelGenres": "Géneros",
"LabelHardDeleteFile": "Eliminar Definitivamente", "LabelHardDeleteFile": "Eliminar Definitivamente",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Tiene Ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Tiene Ebook Suplementario",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Hora", "LabelHour": "Hora",
"LabelIcon": "Icono", "LabelIcon": "Icono",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Incluir en Tracklist", "LabelIncludeInTracklist": "Incluir en Tracklist",
"LabelIncomplete": "Incompleto", "LabelIncomplete": "Incompleto",
"LabelInProgress": "En Proceso", "LabelInProgress": "En Proceso",
@@ -272,43 +298,47 @@
"LabelIntervalEvery2Hours": "Cada 2 Horas", "LabelIntervalEvery2Hours": "Cada 2 Horas",
"LabelIntervalEvery30Minutes": "Cada 30 minutos", "LabelIntervalEvery30Minutes": "Cada 30 minutos",
"LabelIntervalEvery6Hours": "Cada 6 Horas", "LabelIntervalEvery6Hours": "Cada 6 Horas",
"LabelIntervalEveryDay": "Cada Dia", "LabelIntervalEveryDay": "Cada Día",
"LabelIntervalEveryHour": "Cada Hora", "LabelIntervalEveryHour": "Cada Hora",
"LabelInvalidParts": "Partes Invalidas", "LabelInvalidParts": "Partes Inválidas",
"LabelInvert": "Invert", "LabelInvert": "Invertir",
"LabelItem": "Elemento", "LabelItem": "Elemento",
"LabelLanguage": "Lenguaje", "LabelLanguage": "Lenguaje",
"LabelLanguageDefaultServer": "Lenguaje Predeterminado del Servidor", "LabelLanguageDefaultServer": "Lenguaje Predeterminado del Servidor",
"LabelLastBookAdded": "Last Book Added", "LabelLastBookAdded": "Último Libro Agregado",
"LabelLastBookUpdated": "Last Book Updated", "LabelLastBookUpdated": "Último Libro Actualizado",
"LabelLastSeen": "Ultima Vez Visto", "LabelLastSeen": "Última Vez Visto",
"LabelLastTime": "Ultima Vez", "LabelLastTime": "Última Vez",
"LabelLastUpdate": "Ultima Actualización", "LabelLastUpdate": "Última Actualización",
"LabelLayout": "Layout", "LabelLayout": "Distribución",
"LabelLayoutSinglePage": "Single page", "LabelLayoutSinglePage": "Una Página",
"LabelLayoutSplitPage": "Split page", "LabelLayoutSplitPage": "Dos Páginas",
"LabelLess": "Menos", "LabelLess": "Menos",
"LabelLibrariesAccessibleToUser": "Bibliotecas Disponibles para el Usuario", "LabelLibrariesAccessibleToUser": "Bibliotecas Disponibles para el Usuario",
"LabelLibrary": "Biblioteca", "LabelLibrary": "Biblioteca",
"LabelLibraryItem": "Elemento de Biblioteca", "LabelLibraryItem": "Elemento de Biblioteca",
"LabelLibraryName": "Nombre de Biblioteca", "LabelLibraryName": "Nombre de Biblioteca",
"LabelLimit": "Limites", "LabelLimit": "Limites",
"LabelLineSpacing": "Line spacing", "LabelLineSpacing": "Interlineado",
"LabelListenAgain": "Escuchar Otra Vez", "LabelListenAgain": "Escuchar Otra Vez",
"LabelLogLevelDebug": "Debug", "LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Información",
"LabelLogLevelWarn": "Advertencia", "LabelLogLevelWarn": "Advertencia",
"LabelLookForNewEpisodesAfterDate": "Buscar Nuevos Episodios a partir de esta Fecha", "LabelLookForNewEpisodesAfterDate": "Buscar Nuevos Episodios a partir de esta Fecha",
"LabelMediaPlayer": "Media Player", "LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Reproductor de Medios",
"LabelMediaType": "Tipo de Multimedia", "LabelMediaType": "Tipo de Multimedia",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Proveedor de Metadata", "LabelMetadataProvider": "Proveedor de Metadata",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
"LabelMinute": "Minuto", "LabelMinute": "Minuto",
"LabelMissing": "Ausente", "LabelMissing": "Ausente",
"LabelMissingParts": "Partes Ausentes", "LabelMissingParts": "Partes Ausentes",
"LabelMore": "Mas", "LabelMore": "Más",
"LabelMoreInfo": "Mas Información", "LabelMoreInfo": "Más Información",
"LabelName": "Nombre", "LabelName": "Nombre",
"LabelNarrator": "Narrador", "LabelNarrator": "Narrador",
"LabelNarrators": "Narradores", "LabelNarrators": "Narradores",
@@ -318,17 +348,17 @@
"LabelNewPassword": "Nueva Contraseña", "LabelNewPassword": "Nueva Contraseña",
"LabelNextBackupDate": "Fecha del Siguiente Respaldo", "LabelNextBackupDate": "Fecha del Siguiente Respaldo",
"LabelNextScheduledRun": "Próxima Ejecución Programada", "LabelNextScheduledRun": "Próxima Ejecución Programada",
"LabelNoEpisodesSelected": "No episodes selected", "LabelNoEpisodesSelected": "Ningún Episodio Seleccionado",
"LabelNotes": "Notas", "LabelNotes": "Notas",
"LabelNotFinished": "No Terminado", "LabelNotFinished": "No Terminado",
"LabelNotificationAppriseURL": "Apprise URL(s)", "LabelNotificationAppriseURL": "URL(s) de Apprise",
"LabelNotificationAvailableVariables": "Variables Disponibles", "LabelNotificationAvailableVariables": "Variables Disponibles",
"LabelNotificationBodyTemplate": "Plantilla de Cuerpo", "LabelNotificationBodyTemplate": "Plantilla de Cuerpo",
"LabelNotificationEvent": "Evento de Notificación", "LabelNotificationEvent": "Evento de Notificación",
"LabelNotificationsMaxFailedAttempts": "Máximo de Intentos Fallidos", "LabelNotificationsMaxFailedAttempts": "Máximo de Intentos Fallidos",
"LabelNotificationsMaxFailedAttemptsHelp": "Las notificaciones se desactivan después de fallar este numero de veces", "LabelNotificationsMaxFailedAttemptsHelp": "Las notificaciones se desactivan después de fallar este número de veces",
"LabelNotificationsMaxQueueSize": "Tamaño máximo de la cola de notificación", "LabelNotificationsMaxQueueSize": "Tamaño máximo de la cola de notificaciones",
"LabelNotificationsMaxQueueSizeHelp": "Las notificaciones están limitadas a 1 por segundo. Las notificaciones serán ignorados si llegan al numero máximo de cola para prevenir spam de eventos.", "LabelNotificationsMaxQueueSizeHelp": "Las notificaciones están limitadas a 1 por segundo. Las notificaciones serán ignoradas si llegan al numero máximo de cola para prevenir spam de eventos.",
"LabelNotificationTitleTemplate": "Plantilla de Titulo", "LabelNotificationTitleTemplate": "Plantilla de Titulo",
"LabelNotStarted": "Sin Iniciar", "LabelNotStarted": "Sin Iniciar",
"LabelNumberOfBooks": "Numero de Libros", "LabelNumberOfBooks": "Numero de Libros",
@@ -350,93 +380,92 @@
"LabelPodcast": "Podcast", "LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasts", "LabelPodcasts": "Podcasts",
"LabelPodcastType": "Tipo Podcast", "LabelPodcastType": "Tipo Podcast",
"LabelPort": "Port", "LabelPort": "Puerto",
"LabelPrefixesToIgnore": "Prefijos para Ignorar (no distingue entre mayúsculas y minúsculas.)", "LabelPrefixesToIgnore": "Prefijos para Ignorar (no distingue entre mayúsculas y minúsculas.)",
"LabelPreventIndexing": "Evite que su fuente sea indexado por iTunes y Google podcast directories", "LabelPreventIndexing": "Evite que su fuente sea indexada por los directorios de podcasts de iTunes y Google",
"LabelPrimaryEbook": "Primary ebook", "LabelPrimaryEbook": "Ebook principal",
"LabelProgress": "Progreso", "LabelProgress": "Progreso",
"LabelProvider": "Proveedor", "LabelProvider": "Proveedor",
"LabelPubDate": "Fecha de Publicación", "LabelPubDate": "Fecha de Publicación",
"LabelPublisher": "Editor", "LabelPublisher": "Editor",
"LabelPublishYear": "Año de Publicación", "LabelPublishYear": "Año de Publicación",
"LabelRead": "Read", "LabelRead": "Leído",
"LabelReadAgain": "Read Again", "LabelReadAgain": "Volver a leer",
"LabelReadEbookWithoutProgress": "Read ebook without keeping progress", "LabelReadEbookWithoutProgress": "Leer Ebook sin guardar progreso",
"LabelRecentlyAdded": "Agregado Reciente", "LabelRecentlyAdded": "Agregado Recientemente",
"LabelRecentSeries": "Series Recientes", "LabelRecentSeries": "Series Recientes",
"LabelRecommended": "Recomendados", "LabelRecommended": "Recomendados",
"LabelRegion": "Region", "LabelRegion": "Región",
"LabelReleaseDate": "Fecha de Estreno", "LabelReleaseDate": "Fecha de Estreno",
"LabelRemoveCover": "Remover Portada", "LabelRemoveCover": "Remover Portada",
"LabelRSSFeedCustomOwnerEmail": "Custom owner Email", "LabelRSSFeedCustomOwnerEmail": "Email de dueño personalizado",
"LabelRSSFeedCustomOwnerName": "Custom owner Name", "LabelRSSFeedCustomOwnerName": "Nombre de dueño personalizado",
"LabelRSSFeedOpen": "Fuente RSS Abierta", "LabelRSSFeedOpen": "Fuente RSS Abierta",
"LabelRSSFeedPreventIndexing": "Prevenir Indaxación", "LabelRSSFeedPreventIndexing": "Prevenir Indexado",
"LabelRSSFeedSlug": "Fuente RSS Slug", "LabelRSSFeedSlug": "Fuente RSS Slug",
"LabelRSSFeedURL": "URL de Fuente RSS", "LabelRSSFeedURL": "URL de Fuente RSS",
"LabelSearchTerm": "Buscar Termino", "LabelSearchTerm": "Buscar Termino",
"LabelSearchTitle": "Buscar Titulo", "LabelSearchTitle": "Buscar Titulo",
"LabelSearchTitleOrASIN": "Buscar Titulo o ASIN", "LabelSearchTitleOrASIN": "Buscar Título o ASIN",
"LabelSeason": "Temporada", "LabelSeason": "Temporada",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Seleccionar todos los episodios",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Enviar Ebook a...",
"LabelSequence": "Secuencia", "LabelSequence": "Secuencia",
"LabelSeries": "Series", "LabelSeries": "Series",
"LabelSeriesName": "Nombre de la Serie", "LabelSeriesName": "Nombre de la Serie",
"LabelSeriesProgress": "Progreso de la Serie", "LabelSeriesProgress": "Progreso de la Serie",
"LabelSetEbookAsPrimary": "Set as primary", "LabelSetEbookAsPrimary": "Establecer como primario",
"LabelSetEbookAsSupplementary": "Set as supplementary", "LabelSetEbookAsSupplementary": "Establecer como suplementario",
"LabelSettingsAudiobooksOnly": "Audiobooks only", "LabelSettingsAudiobooksOnly": "Sólo Audiolibros",
"LabelSettingsAudiobooksOnlyHelp": "Enabling this setting will ignore ebook files unless they are inside an audiobook folder in which case they will be set as supplementary ebooks", "LabelSettingsAudiobooksOnlyHelp": "Al activar esta opción se ignorarán los archivos de ebook a menos de que estén dentro de la carpeta de un audiolibro, en cuyo caso se marcarán como ebooks suplementarios",
"LabelSettingsBookshelfViewHelp": "Diseño Skeumorphic con Estantes de Madera", "LabelSettingsBookshelfViewHelp": "Diseño Esqueuomorfo con Estantes de Madera",
"LabelSettingsChromecastSupport": "Soporte para Chromecast", "LabelSettingsChromecastSupport": "Soporte para Chromecast",
"LabelSettingsDateFormat": "Formato de Fecha", "LabelSettingsDateFormat": "Formato de Fecha",
"LabelSettingsDisableWatcher": "Deshabilitar Watcher", "LabelSettingsDisableWatcher": "Deshabilitar Watcher",
"LabelSettingsDisableWatcherForLibrary": "Deshabilitar Watcher de Carpetas para esta biblioteca", "LabelSettingsDisableWatcherForLibrary": "Deshabilitar Watcher de Carpetas para esta biblioteca",
"LabelSettingsDisableWatcherHelp": "Deshabilitar la función automática de agregar/actualizar los elementos, cuando se detecta cambio en los archivos. *Require Reiniciar el Servidor", "LabelSettingsDisableWatcherHelp": "Deshabilitar la función de agregar/actualizar elementos automáticamente cuando se detectan cambios en los archivos. *Require Reiniciar el Servidor",
"LabelSettingsEnableWatcher": "Habilitar Watcher",
"LabelSettingsEnableWatcherForLibrary": "Habilitar Watcher para la carpeta de esta biblioteca",
"LabelSettingsEnableWatcherHelp": "Permite agregar/actualizar elementos automáticamente cuando se detectan cambios en los archivos. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Funciones Experimentales", "LabelSettingsExperimentalFeatures": "Funciones Experimentales",
"LabelSettingsExperimentalFeaturesHelp": "Funciones en desarrollo sobre las que esperamos sus comentarios y experiencia. Haga click aquí para abrir una conversación en Github.", "LabelSettingsExperimentalFeaturesHelp": "Funciones en desarrollo que se beneficiarían de sus comentarios y experiencias de prueba. Haga click aquí para abrir una conversación en Github.",
"LabelSettingsFindCovers": "Buscar Portadas", "LabelSettingsFindCovers": "Buscar Portadas",
"LabelSettingsFindCoversHelp": "Si tu audiolibro no tiene una portada incluida o la portada no esta dentro de la carpeta, el escaneador tratara de encontrar una portada.<br>Nota: Esto extenderá el tiempo de escaneo", "LabelSettingsFindCoversHelp": "Si tu audiolibro no tiene una portada incluída, o la portada no esta dentro de la carpeta, el escaneador tratará de encontrar una portada.<br>Nota: Esto extenderá el tiempo de escaneo",
"LabelSettingsHideSingleBookSeries": "Hide single book series", "LabelSettingsHideSingleBookSeries": "Esconder series con un solo libro",
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Las series con un solo libro no aparecerán en la página de series ni la repisa para series de la página principal.",
"LabelSettingsHomePageBookshelfView": "La pagina de inicio usa la vista de librero", "LabelSettingsHomePageBookshelfView": "Usar la vista de librero en la página principal",
"LabelSettingsLibraryBookshelfView": "La biblioteca usa la vista de librero", "LabelSettingsLibraryBookshelfView": "Usar la vista de librero en la biblioteca",
"LabelSettingsOverdriveMediaMarkers": "Usar Markers de multimedia en Overdrive para estos capítulos", "LabelSettingsParseSubtitles": "Extraer Subtítulos",
"LabelSettingsOverdriveMediaMarkersHelp": "Archivos MP3 de Overdrive vienen con capítulos con tiempos incrustados como metadata personalizada. Habilitar esto utilizará estas etiquetas para los tiempos de los capítulos automáticamente.", "LabelSettingsParseSubtitlesHelp": "Extraer subtítulos de los nombres de las carpetas de los audiolibros.<br>Los subtítulos deben estar separados por \" - \"<br>Por ejemplo: \"Ejemplo de Título - Subtítulo Aquí\" tiene el subtítulo \"Subtítulo Aquí\"",
"LabelSettingsParseSubtitles": "Parse subtitles", "LabelSettingsPreferMatchedMetadata": "Preferir metadatos encontrados",
"LabelSettingsParseSubtitlesHelp": "Extraiga subtítulos de los nombres de las carpetas de los audiolibros.<br>Los subtítulos deben estar separados por \" - \"<br>ejemplo. \"Titulo Libro - Este Subtitulo\" tiene el subtitulo \"Este Subtitulo\"", "LabelSettingsPreferMatchedMetadataHelp": "Los datos encontrados sobreescribirán los detalles del elemento cuando se use \"Encontrar Rápido\". Por defecto, \"Encontrar Rápido\" sólo completará los detalles faltantes.",
"LabelSettingsPreferAudioMetadata": "Preferir metadata del audio",
"LabelSettingsPreferAudioMetadataHelp": "Archivos de Audio ID3 meta tags se utilizarán para detalles de libros en vez de los nombres de carpetas",
"LabelSettingsPreferMatchedMetadata": "Prefer matched metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Los datos coincidentes anularán los detalles del elemento cuando se utilice Quick Match. Por defecto, Quick Match solo completará los detalles faltantes.",
"LabelSettingsPreferOPFMetadata": "Preferir OPF metadata",
"LabelSettingsPreferOPFMetadataHelp": "Los archivos de metadata OPF serán usados para los detalles del libro en vez de el nombre de las carpetas",
"LabelSettingsSkipMatchingBooksWithASIN": "Omitir libros coincidentes que ya tengan un ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Omitir libros coincidentes que ya tengan un ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Omitir libros coincidentes que ya tengan un ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Omitir libros coincidentes que ya tengan un ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignorar prefijos al ordenando", "LabelSettingsSortingIgnorePrefixes": "Ignorar prefijos al ordenar",
"LabelSettingsSortingIgnorePrefixesHelp": "ejemplo. el prefijo \"el\" del titulo \"El titulo del libro\" sera ordenado como \"Titulo del Libro, el\"", "LabelSettingsSortingIgnorePrefixesHelp": "Por ejemplo: El prefijo \"el\" del titulo \"El titulo del libro\" se ordena como \"Titulo del Libro, el\".",
"LabelSettingsSquareBookCovers": "Usar portadas cuadradas", "LabelSettingsSquareBookCovers": "Usar portadas cuadradas",
"LabelSettingsSquareBookCoversHelp": "Prefiere usar portadas cuadradas sobre las portadas estándar 1.6:1", "LabelSettingsSquareBookCoversHelp": "Prefierir usar portadas cuadradas sobre las portadas estándar 1.6:1",
"LabelSettingsStoreCoversWithItem": "Guardar portada con elemento", "LabelSettingsStoreCoversWithItem": "Guardar portadas con elementos",
"LabelSettingsStoreCoversWithItemHelp": "Por defecto, las portadas se almacenan en /metadata/items, si habilita esta configuración, las portadas se almacenará en la carpeta de elementos de su biblioteca. Solamente un archivo llamado \"cover\" sera guardado.", "LabelSettingsStoreCoversWithItemHelp": "Por defecto, las portadas se almacenan en /metadata/items. Si habilita esta opción, las portadas se almacenarán en la carpeta de elementos de su biblioteca. Se guardará un solo archivo llamado \"cover\".",
"LabelSettingsStoreMetadataWithItem": "Guardar metadata con elemento", "LabelSettingsStoreMetadataWithItem": "Guardar metadatos con elementos",
"LabelSettingsStoreMetadataWithItemHelp": "Por defecto, los archivos de metadatos se almacenan en /metadata/items, si habilita esta configuración, los archivos de metadata se guardaran en la carpeta de elementos de tu biblioteca. Usa la extension .abs", "LabelSettingsStoreMetadataWithItemHelp": "Por defecto, los archivos de metadatos se almacenan en /metadata/items. Si habilita esta opción, los archivos de metadatos se guardarán en la carpeta de elementos de su biblioteca",
"LabelSettingsTimeFormat": "Format de Tiempo", "LabelSettingsTimeFormat": "Formato de Tiempo",
"LabelShowAll": "Mostrar Todos", "LabelShowAll": "Mostrar Todos",
"LabelSize": "Tamaño", "LabelSize": "Tamaño",
"LabelSleepTimer": "Temporizador para Dormir", "LabelSleepTimer": "Temporizador para Dormir",
"LabelSlug": "Slug",
"LabelStart": "Iniciar", "LabelStart": "Iniciar",
"LabelStarted": "Indiciado", "LabelStarted": "Iniciado",
"LabelStartedAt": "Iniciado En", "LabelStartedAt": "Iniciado En",
"LabelStartTime": "Tiempo de Inicio", "LabelStartTime": "Tiempo de Inicio",
"LabelStatsAudioTracks": "Pistas de Audio", "LabelStatsAudioTracks": "Pistas de Audio",
"LabelStatsAuthors": "Autores", "LabelStatsAuthors": "Autores",
"LabelStatsBestDay": "Mejor Dia", "LabelStatsBestDay": "Mejor Día",
"LabelStatsDailyAverage": "Promedio Diario", "LabelStatsDailyAverage": "Promedio Diario",
"LabelStatsDays": "Dias", "LabelStatsDays": "Días",
"LabelStatsDaysListened": "Dias Escuchando", "LabelStatsDaysListened": "Días Escuchando",
"LabelStatsHours": "Horas", "LabelStatsHours": "Horas",
"LabelStatsInARow": "seguidos", "LabelStatsInARow": "seguidos",
"LabelStatsItemsFinished": "Elementos Terminados", "LabelStatsItemsFinished": "Elementos Terminados",
@@ -445,41 +474,42 @@
"LabelStatsMinutesListening": "Minutos Escuchando", "LabelStatsMinutesListening": "Minutos Escuchando",
"LabelStatsOverallDays": "Total de Dias", "LabelStatsOverallDays": "Total de Dias",
"LabelStatsOverallHours": "Total de Horas", "LabelStatsOverallHours": "Total de Horas",
"LabelStatsWeekListening": "Escuchando en la Semana", "LabelStatsWeekListening": "Tiempo escuchando en la Semana",
"LabelSubtitle": "Subtitulo", "LabelSubtitle": "Subtítulo",
"LabelSupportedFileTypes": "Tipo de Archivos Soportados", "LabelSupportedFileTypes": "Tipos de Archivos Soportados",
"LabelTag": "Etiqueta", "LabelTag": "Etiqueta",
"LabelTags": "Etiquetas", "LabelTags": "Etiquetas",
"LabelTagsAccessibleToUser": "Etiquetas Accessible para el Usuario", "LabelTagsAccessibleToUser": "Etiquetas Accessibles al Usuario",
"LabelTagsNotAccessibleToUser": "Tags not Accessible to User", "LabelTagsNotAccessibleToUser": "Etiquetas no Accesibles al Usuario",
"LabelTasks": "Tareas Corriendo", "LabelTasks": "Tareas Corriendo",
"LabelTheme": "Theme", "LabelTheme": "Tema",
"LabelThemeDark": "Dark", "LabelThemeDark": "Oscuro",
"LabelThemeLight": "Light", "LabelThemeLight": "Claro",
"LabelTimeBase": "Time Base", "LabelTimeBase": "Time Base",
"LabelTimeListened": "Tiempo Escuchando", "LabelTimeListened": "Tiempo Escuchando",
"LabelTimeListenedToday": "Tiempo Escuchando Hoy", "LabelTimeListenedToday": "Tiempo Escuchando Hoy",
"LabelTimeRemaining": "{0} restante", "LabelTimeRemaining": "{0} restante",
"LabelTimeToShift": "Tiempo para Cambiar en Segundos", "LabelTimeToShift": "Tiempo para Cambiar en Segundos",
"LabelTitle": "Titulo", "LabelTitle": "Título",
"LabelToolsEmbedMetadata": "Incorporar Metadata", "LabelToolsEmbedMetadata": "Incrustar Metadatos",
"LabelToolsEmbedMetadataDescription": "Incorpora metadata en archivos de audio incluyendo la portada y capítulos.", "LabelToolsEmbedMetadataDescription": "Incrusta metadatos en los archivos de audio, incluyendo la portada y capítulos.",
"LabelToolsMakeM4b": "Hacer Archivo M4B de Audiolibro", "LabelToolsMakeM4b": "Hacer Archivo de Audiolibro M4B",
"LabelToolsMakeM4bDescription": "Generar archivo .M4B de audiolibro con metadata, imágenes de portada y capítulos incorporados.", "LabelToolsMakeM4bDescription": "Generar archivo de audiolibro .M4B con metadatos, imágenes de portada y capítulos incorporados.",
"LabelToolsSplitM4b": "Dividir M4B en Archivos MP3", "LabelToolsSplitM4b": "Dividir M4B en Archivos MP3",
"LabelToolsSplitM4bDescription": "Dividir M4B en Archivos MP3 y incorporar metadata, images de portada y capítulos.", "LabelToolsSplitM4bDescription": "Dividir M4B en Archivos MP3 e incorporar metadatos, imágenes de portada y capítulos.",
"LabelTotalDuration": "Duración Total", "LabelTotalDuration": "Duración Total",
"LabelTotalTimeListened": "Tiempo Total Escuchado", "LabelTotalTimeListened": "Tiempo Total Escuchado",
"LabelTrackFromFilename": "Pista desde el Nombre del Archivo", "LabelTrackFromFilename": "Pista desde el Nombre del Archivo",
"LabelTrackFromMetadata": "Pista desde Metadata", "LabelTrackFromMetadata": "Pista desde Metadatos",
"LabelTracks": "Pistas", "LabelTracks": "Pistas",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Varias pistas",
"LabelTracksSingleTrack": "Single-track", "LabelTracksNone": "Ninguna pista",
"LabelTracksSingleTrack": "Una pista",
"LabelType": "Tipo", "LabelType": "Tipo",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "No Abreviado",
"LabelUnknown": "Desconocido", "LabelUnknown": "Desconocido",
"LabelUpdateCover": "Actualizar Portada", "LabelUpdateCover": "Actualizar Portada",
"LabelUpdateCoverHelp": "Permitir sobrescribir portadas existentes de los libros seleccionados cuando sean encontrados.", "LabelUpdateCoverHelp": "Permitir sobrescribir las portadas existentes de los libros seleccionados cuando sean encontradas.",
"LabelUpdatedAt": "Actualizado En", "LabelUpdatedAt": "Actualizado En",
"LabelUpdateDetails": "Actualizar Detalles", "LabelUpdateDetails": "Actualizar Detalles",
"LabelUpdateDetailsHelp": "Permitir sobrescribir detalles existentes de los libros seleccionados cuando sean encontrados", "LabelUpdateDetailsHelp": "Permitir sobrescribir detalles existentes de los libros seleccionados cuando sean encontrados",
@@ -488,77 +518,83 @@
"LabelUseChapterTrack": "Usar pista por capitulo", "LabelUseChapterTrack": "Usar pista por capitulo",
"LabelUseFullTrack": "Usar pista completa", "LabelUseFullTrack": "Usar pista completa",
"LabelUser": "Usuario", "LabelUser": "Usuario",
"LabelUsername": "Nombré de Usuario", "LabelUsername": "Nombre de Usuario",
"LabelValue": "Valor", "LabelValue": "Valor",
"LabelVersion": "Versión", "LabelVersion": "Versión",
"LabelViewBookmarks": "Ver Marcadores", "LabelViewBookmarks": "Ver Marcadores",
"LabelViewChapters": "Ver Capítulos", "LabelViewChapters": "Ver Capítulos",
"LabelViewQueue": "Ver player queue", "LabelViewQueue": "Ver Fila del Reproductor",
"LabelVolume": "Volumen", "LabelVolume": "Volumen",
"LabelWeekdaysToRun": "Correr en Dias de la Semana", "LabelWeekdaysToRun": "Correr en Días de la Semana",
"LabelYourAudiobookDuration": "Duración de tu Audiolibro", "LabelYourAudiobookDuration": "Duración de tu Audiolibro",
"LabelYourBookmarks": "Tus Marcadores Bookmarks", "LabelYourBookmarks": "Tus Marcadores",
"LabelYourPlaylists": "Tus Listas", "LabelYourPlaylists": "Tus Listas",
"LabelYourProgress": "Tu Progreso", "LabelYourProgress": "Tu Progreso",
"MessageAddToPlayerQueue": "Agregar a player queue", "MessageAddToPlayerQueue": "Agregar a fila del Reproductor",
"MessageAppriseDescription": "Para usar esta función deberás tener <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> corriendo o un API que maneje los mismos resultados. <br />El Apprise API URL debe tener la misma ruta de archivos que donde se envina las notificaciones, ejemplo, si su API esta en <code>http://192.168.1.1:8337</code> entonces pondría <code>http://192.168.1.1:8337/notify</code>.", "MessageAppriseDescription": "Para usar esta función deberás tener <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">la API de Apprise</a> corriendo o una API que maneje los mismos resultados. <br/>La URL de la API de Apprise debe tener la misma ruta de archivos que donde se envían las notificaciones. Por ejemplo: si su API esta en <code>http://192.168.1.1:8337</code> entonces pondría <code>http://192.168.1.1:8337/notify</code>.",
"MessageBackupsDescription": "Los respaldos incluyen, usuarios, el progreso del los usuarios, detalles de los elementos de la biblioteca, configuración del servidor y las imágenes en <code>/metadata/items</code> & <code>/metadata/authors</code>. Los Respaldo <strong>NO</strong> incluyen ningún archivo guardado en la carpeta de tu biblioteca.", "MessageBackupsDescription": "Los respaldos incluyen: usuarios, el progreso del los usuarios, los detalles de los elementos de la biblioteca, la configuración del servidor y las imágenes en <code>/metadata/items</code> y <code>/metadata/authors</code>. Los Respaldos <strong>NO</strong> incluyen ningún archivo guardado en la carpeta de tu biblioteca.",
"MessageBatchQuickMatchDescription": "Quick Match tratara de agregar porta y metadata faltantes de los elementos seleccionados. Habilite la opción de abajo para que Quick Match pueda sobrescribir portadas y/o metadata existentes.", "MessageBatchQuickMatchDescription": "\"Encontrar Rápido\" tratará de agregar portadas y metadatos faltantes de los elementos seleccionados. Habilite la opción de abajo para que \"Encontrar Rápido\" pueda sobrescribir portadas y/o metadatos existentes.",
"MessageBookshelfNoCollections": "No tienes ninguna colección.", "MessageBookshelfNoCollections": "No tienes ninguna colección.",
"MessageBookshelfNoResultsForFilter": "Ningún Resultado para el filtro \"{0}: {1}\"", "MessageBookshelfNoResultsForFilter": "Ningún Resultado para el filtro \"{0}: {1}\"",
"MessageBookshelfNoRSSFeeds": "Ninguna Fuente RSS esta abierta", "MessageBookshelfNoRSSFeeds": "Ninguna Fuente RSS esta abierta",
"MessageBookshelfNoSeries": "No tienes ninguna series", "MessageBookshelfNoSeries": "No tienes ninguna serie",
"MessageChapterEndIsAfter": "El final del capítulo es después del final de su audiolibro.", "MessageChapterEndIsAfter": "El final del capítulo es después del final de su audiolibro.",
"MessageChapterErrorFirstNotZero": "El primer capitulo debe iniciar en 0", "MessageChapterErrorFirstNotZero": "El primer capitulo debe iniciar en 0",
"MessageChapterErrorStartGteDuration": "El tiempo de inicio no es válida debe ser inferior a la duración del audiolibro.", "MessageChapterErrorStartGteDuration": "El tiempo de inicio no es válido: debe ser inferior a la duración del audiolibro.",
"MessageChapterErrorStartLtPrev": "El tiempo de inicio no es válida debe ser mayor o igual que la hora de inicio del capítulo anterior", "MessageChapterErrorStartLtPrev": "El tiempo de inicio no es válido: debe ser mayor o igual que el tiempo de inicio del capítulo anterior",
"MessageChapterStartIsAfter": "El comienzo del capítulo es después del final de su audiolibro", "MessageChapterStartIsAfter": "El comienzo del capítulo es después del final de su audiolibro",
"MessageCheckingCron": "Checking cron...", "MessageCheckingCron": "Revisando cron...",
"MessageConfirmDeleteBackup": "Esta seguro que desea eliminar el respaldo {0}?", "MessageConfirmCloseFeed": "Está seguro de que desea cerrar esta fuente?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteBackup": "¿Está seguro de que desea eliminar el respaldo {0}?",
"MessageConfirmDeleteLibrary": "Esta seguro que desea eliminar permanentemente la biblioteca \"{0}\"?", "MessageConfirmDeleteFile": "Esto eliminará el archivo de su sistema de archivos. ¿Está seguro?",
"MessageConfirmDeleteSession": "Esta seguro que desea eliminar esta session?", "MessageConfirmDeleteLibrary": "¿Está seguro de que desea eliminar permanentemente la biblioteca \"{0}\"?",
"MessageConfirmForceReScan": "Esta seguro que desea forzar re-escanear?", "MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmDeleteSession": "¿Está seguro de que desea eliminar esta sesión?",
"MessageConfirmMarkSeriesFinished": "Esta seguro que desea marcar todos los libros en esta serie como terminados?", "MessageConfirmForceReScan": "¿Está seguro de que desea forzar un re-escaneo?",
"MessageConfirmMarkSeriesNotFinished": "Esta seguro que desea marcar todos los libros en esta serie como no terminados?", "MessageConfirmMarkAllEpisodesFinished": "¿Está seguro de que desea marcar todos los episodios como terminados?",
"MessageConfirmRemoveAllChapters": "Esta seguro que desea remover todos los capitulos?", "MessageConfirmMarkAllEpisodesNotFinished": "¿Está seguro de que desea marcar todos los episodios como no terminados?",
"MessageConfirmRemoveCollection": "Esta seguro que desea remover la colección \"{0}\"?", "MessageConfirmMarkSeriesFinished": "¿Está seguro de que desea marcar todos los libros en esta serie como terminados?",
"MessageConfirmRemoveEpisode": "Esta seguro que desea remover el episodio \"{0}\"?", "MessageConfirmMarkSeriesNotFinished": "¿Está seguro de que desea marcar todos los libros en esta serie como no terminados?",
"MessageConfirmRemoveEpisodes": "Esta seguro que desea remover {0} episodios?", "MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveNarrator": "Are you sure you want to remove narrator \"{0}\"?", "MessageConfirmRemoveAllChapters": "¿Está seguro de que desea remover todos los capitulos?",
"MessageConfirmRemovePlaylist": "Esta seguro que desea remover su lista de reproducción \"{0}\"?", "MessageConfirmRemoveAuthor": "¿Está seguro de que desea remover el autor \"{0}\"?",
"MessageConfirmRenameGenre": "Esta seguro que desea renombrar el genero \"{0}\" a \"{1}\" de todos los elementos?", "MessageConfirmRemoveCollection": "¿Está seguro de que desea remover la colección \"{0}\"?",
"MessageConfirmRenameGenreMergeNote": "Nota: Este genero ya existe por lo que se fusionarán.", "MessageConfirmRemoveEpisode": "¿Está seguro de que desea remover el episodio \"{0}\"?",
"MessageConfirmRenameGenreWarning": "Advertencia! un genero similar ya existe \"{0}\".", "MessageConfirmRemoveEpisodes": "¿Está seguro de que desea remover {0} episodios?",
"MessageConfirmRenameTag": "Esta seguro que desea renombrar la etiqueta \"{0}\" a \"{1}\" de todos los elementos?", "MessageConfirmRemoveNarrator": "¿Está seguro de que desea remover el narrador \"{0}\"?",
"MessageConfirmRenameTagMergeNote": "Nota: Esta etiqueta ya existe por lo que se fusionarán.", "MessageConfirmRemovePlaylist": "¿Está seguro de que desea remover la lista de reproducción \"{0}\"?",
"MessageConfirmRenameGenre": "¿Está seguro de que desea renombrar el genero \"{0}\" a \"{1}\" de todos los elementos?",
"MessageConfirmRenameGenreMergeNote": "Nota: Este género ya existe, por lo que se fusionarán.",
"MessageConfirmRenameGenreWarning": "Advertencia! Un genero similar ya existe \"{0}\".",
"MessageConfirmRenameTag": "¿Está seguro de que desea renombrar la etiqueta \"{0}\" a \"{1}\" de todos los elementos?",
"MessageConfirmRenameTagMergeNote": "Nota: Esta etiqueta ya existe, por lo que se fusionarán.",
"MessageConfirmRenameTagWarning": "Advertencia! Una etiqueta similar ya existe \"{0}\".", "MessageConfirmRenameTagWarning": "Advertencia! Una etiqueta similar ya existe \"{0}\".",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "¿Está seguro de que enviar {0} ebook(s) \"{1}\" al dispositivo \"{2}\"?",
"MessageDownloadingEpisode": "Descargando Capitulo", "MessageDownloadingEpisode": "Descargando Capitulo",
"MessageDragFilesIntoTrackOrder": "Arrastras los archivos en el orden correcto de la pista.", "MessageDragFilesIntoTrackOrder": "Arrastra los archivos al orden correcto de las pistas.",
"MessageEmbedFinished": "Incorporación Terminada!", "MessageEmbedFinished": "Incrustación Terminada!",
"MessageEpisodesQueuedForDownload": "{0} Episodio(s) en cola para descargar", "MessageEpisodesQueuedForDownload": "{0} Episodio(s) en cola para descargar",
"MessageFeedURLWillBe": "Fuente URL sera {0}", "MessageFeedURLWillBe": "URL de la fuente será {0}",
"MessageFetching": "Buscando...", "MessageFetching": "Buscando...",
"MessageForceReScanDescription": "Escaneara todos los archivos como un nuevo escaneo. Archivos de audio con etiqueta ID3, archivos OPF y archivos de texto serán escaneados como nuevos.", "MessageForceReScanDescription": "Escaneará todos los archivos como un nuevo escaneo. Archivos de audio con etiquetas ID3, archivos OPF y archivos de texto serán escaneados como nuevos.",
"MessageImportantNotice": "Noticia importante!", "MessageImportantNotice": "¡Notificación importante!",
"MessageInsertChapterBelow": "Insertar Capítulo Abajo", "MessageInsertChapterBelow": "Insertar Capítulo Abajo",
"MessageItemsSelected": "{0} Elementos Seleccionados", "MessageItemsSelected": "{0} Elementos Seleccionados",
"MessageItemsUpdated": "{0} Elementos Actualizados", "MessageItemsUpdated": "{0} Elementos Actualizados",
"MessageJoinUsOn": "Únete en", "MessageJoinUsOn": "Únetenos en",
"MessageListeningSessionsInTheLastYear": "{0} sesiones de escuchadas en el último año", "MessageListeningSessionsInTheLastYear": "{0} sesiones de escucha en el último año",
"MessageLoading": "Cargando...", "MessageLoading": "Cargando...",
"MessageLoadingFolders": "Cargando archivos...", "MessageLoadingFolders": "Cargando archivos...",
"MessageM4BFailed": "M4B Fallo!", "MessageM4BFailed": "¡Fallo de M4B!",
"MessageM4BFinished": "M4B Terminado!", "MessageM4BFinished": "¡M4B Terminado!",
"MessageMapChapterTitles": "Map chapter titles to your existing audiobook chapters without adjusting timestamps", "MessageMapChapterTitles": "Asignar los nombres de capítulos a los capítulos existentes en tu audiolibro sin ajustar sus tiempos",
"MessageMarkAllEpisodesFinished": "Mark all episodes finished", "MessageMarkAllEpisodesFinished": "Marcar todos los episodios como terminados",
"MessageMarkAllEpisodesNotFinished": "Mark all episodes not finished", "MessageMarkAllEpisodesNotFinished": "Marcar todos los episodios como no terminados",
"MessageMarkAsFinished": "Marcar como Terminado", "MessageMarkAsFinished": "Marcar como Terminado",
"MessageMarkAsNotFinished": "Marcar como No Terminado", "MessageMarkAsNotFinished": "Marcar como No Terminado",
"MessageMatchBooksDescription": "intentará hacer coincidir los libros de la biblioteca con un libro del proveedor de búsqueda seleccionado y rellenará los detalles vacíos y la portada. No sobrescribe los detalles.", "MessageMatchBooksDescription": "Se intentará hacer coincidir los libros de la biblioteca con un libro del proveedor de búsqueda seleccionado, y se rellenarán los detalles vacíos y la portada. No sobrescribe los detalles.",
"MessageNoAudioTracks": "Sin Pista de Audio", "MessageNoAudioTracks": "Sin Pista de Audio",
"MessageNoAuthors": "Sin Autores", "MessageNoAuthors": "Sin Autores",
"MessageNoBackups": "Sin Respaldos", "MessageNoBackups": "Sin Respaldos",
@@ -571,18 +607,18 @@
"MessageNoDownloadsQueued": "Sin Lista de Descarga", "MessageNoDownloadsQueued": "Sin Lista de Descarga",
"MessageNoEpisodeMatchesFound": "No se encontraron episodios que coinciden", "MessageNoEpisodeMatchesFound": "No se encontraron episodios que coinciden",
"MessageNoEpisodes": "Sin Episodios", "MessageNoEpisodes": "Sin Episodios",
"MessageNoFoldersAvailable": "No Carpetas Disponibles", "MessageNoFoldersAvailable": "No Hay Carpetas Disponibles",
"MessageNoGenres": "Sin Géneros", "MessageNoGenres": "Sin Géneros",
"MessageNoIssues": "Sin Problemas", "MessageNoIssues": "Sin Problemas",
"MessageNoItems": "Sin Elementos", "MessageNoItems": "Sin Elementos",
"MessageNoItemsFound": "Ningún Elemento Encontrado", "MessageNoItemsFound": "Ningún Elemento Encontrado",
"MessageNoListeningSessions": "Ninguna Session Escuchada", "MessageNoListeningSessions": "Ninguna Session Escuchada",
"MessageNoLogs": "No Logs", "MessageNoLogs": "No hay logs",
"MessageNoMediaProgress": "Multimedia sin Progreso ", "MessageNoMediaProgress": "Multimedia sin Progreso",
"MessageNoNotifications": "Ninguna Notificación", "MessageNoNotifications": "Ninguna Notificación",
"MessageNoPodcastsFound": "Ningún podcasts encontrado", "MessageNoPodcastsFound": "Ningún podcast encontrado",
"MessageNoResults": "Sin Resultados", "MessageNoResults": "Sin Resultados",
"MessageNoSearchResultsFor": "No hay resultados de la búsqueda para \"{0}\"", "MessageNoSearchResultsFor": "No hay resultados para la búsqueda \"{0}\"",
"MessageNoSeries": "Sin Series", "MessageNoSeries": "Sin Series",
"MessageNoTags": "Sin Etiquetas", "MessageNoTags": "Sin Etiquetas",
"MessageNoTasksRunning": "Ninguna Tarea Corriendo", "MessageNoTasksRunning": "Ninguna Tarea Corriendo",
@@ -592,45 +628,45 @@
"MessageNoUserPlaylists": "No tienes lista de reproducciones", "MessageNoUserPlaylists": "No tienes lista de reproducciones",
"MessageOr": "o", "MessageOr": "o",
"MessagePauseChapter": "Pausar la reproducción del capítulo", "MessagePauseChapter": "Pausar la reproducción del capítulo",
"MessagePlayChapter": "Escuche para comenzar el capítulo", "MessagePlayChapter": "Escuchar el comienzo del capítulo",
"MessagePlaylistCreateFromCollection": "Crear lista de reproducción a partir de colección", "MessagePlaylistCreateFromCollection": "Crear una lista de reproducción a partir de una colección",
"MessagePodcastHasNoRSSFeedForMatching": "El podcast no tiene una URL de fuente RSS que pueda usar que coincida", "MessagePodcastHasNoRSSFeedForMatching": "El podcast no tiene una URL de fuente RSS que pueda usar",
"MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la configuración 'Prefer matched metadata' del servidor este habilita.", "MessageQuickMatchDescription": "Rellenar detalles de elementos vacíos y portada con los primeros resultados de '{0}'. No sobrescribe los detalles a menos que la opción \"Preferir Metadatos Encontrados\" del servidor esté habilitada.",
"MessageRemoveChapter": "Remover capítulos", "MessageRemoveChapter": "Remover capítulos",
"MessageRemoveEpisodes": "Remover {0} episodio(s)", "MessageRemoveEpisodes": "Remover {0} episodio(s)",
"MessageRemoveFromPlayerQueue": "Romover la cola de reporduccion", "MessageRemoveFromPlayerQueue": "Romover la cola de reproducción",
"MessageRemoveUserWarning": "Esta seguro que desea eliminar el usuario \"{0}\"?", "MessageRemoveUserWarning": "¿Está seguro de que desea eliminar el usuario \"{0}\"?",
"MessageReportBugsAndContribute": "Reporte erres, solicite funciones y contribuye en", "MessageReportBugsAndContribute": "Reporte erres, solicite funciones y contribuya en",
"MessageResetChaptersConfirm": "Esta seguro que desea reiniciar el capitulo y deshacer los cambios que hiciste?", "MessageResetChaptersConfirm": "¿Está seguro de que desea deshacer los cambios y revertir los capítulos a su estado original?",
"MessageRestoreBackupConfirm": "Esta seguro que desea para restaurar del respaldo creado en", "MessageRestoreBackupConfirm": "¿Está seguro de que desea para restaurar del respaldo creado en",
"MessageRestoreBackupWarning": "Restaurar sobrescribirá toda la base de datos localizada en /config y las imágenes de portadas en /metadata/items & /metadata/authors.<br /><br />El respaldo no modifica ningún archivo en las carpetas de tu biblioteca. Si ha habilitado la configuración del servidor para almacenar portadas y metadata en las carpetas de su biblioteca, entonces esos no se respaldan o sobrescribe.<br /><br />Todos los clientes que usen su servidor se actualizarán automáticamente.", "MessageRestoreBackupWarning": "Restaurar sobrescribirá toda la base de datos localizada en /config y las imágenes de portadas en /metadata/items y /metadata/authors.<br /><br />El respaldo no modifica ningún archivo en las carpetas de su biblioteca. Si ha habilitado la opción del servidor para almacenar portadas y metadata en las carpetas de su biblioteca, esos archivos no se respaldan o sobrescriben.<br /><br />Todos los clientes que usen su servidor se actualizarán automáticamente.",
"MessageSearchResultsFor": "Resultados de la búsqueda de", "MessageSearchResultsFor": "Resultados de la búsqueda de",
"MessageServerCouldNotBeReached": "No se pude establecer la conexión con el servidor", "MessageServerCouldNotBeReached": "No se pudo establecer la conexión con el servidor",
"MessageSetChaptersFromTracksDescription": "Establecer capítulos usando cada archivo de audio como un capítulo y el título del capítulo como el nombre del archivo de audio", "MessageSetChaptersFromTracksDescription": "Establecer capítulos usando cada archivo de audio como un capítulo y el título del capítulo como el nombre del archivo de audio",
"MessageStartPlaybackAtTime": "Iniciar reproducción para \"{0}\" en {1}?", "MessageStartPlaybackAtTime": "Iniciar reproducción para \"{0}\" en {1}?",
"MessageThinking": "Pensando...", "MessageThinking": "Pensando...",
"MessageUploaderItemFailed": "Error al Subir", "MessageUploaderItemFailed": "Error al Subir",
"MessageUploaderItemSuccess": "Éxito al Subir!", "MessageUploaderItemSuccess": "¡Éxito al Subir!",
"MessageUploading": "Subiendo...", "MessageUploading": "Subiendo...",
"MessageValidCronExpression": "Valid cron expression", "MessageValidCronExpression": "Expresión de Cron bálida",
"MessageWatcherIsDisabledGlobally": "Watcher es desactivado globalmente en la configuración del servidor", "MessageWatcherIsDisabledGlobally": "El watcher es desactivado globalmente en la configuración del servidor",
"MessageXLibraryIsEmpty": "{0} La biblioteca esta vacía!", "MessageXLibraryIsEmpty": "La biblioteca {0} está vacía!",
"MessageYourAudiobookDurationIsLonger": "La duración de tu audiolibro es más larga que la duración encontrada", "MessageYourAudiobookDurationIsLonger": "La duración de su audiolibro es más larga que la duración encontrada",
"MessageYourAudiobookDurationIsShorter": "La duración de su audiolibro es más corta que la duración encontrada", "MessageYourAudiobookDurationIsShorter": "La duración de su audiolibro es más corta que la duración encontrada",
"NoteChangeRootPassword": "El usuario Root es el único usuario que puede no tener una contraseña", "NoteChangeRootPassword": "El usuario Root es el único usuario que puede no tener una contraseña",
"NoteChapterEditorTimes": "Nota: La hora de inicio del primer capítulo debe permanecer en 0:00 y la hora de inicio del último capítulo no puede exceder la duración de este audiolibro.", "NoteChapterEditorTimes": "Nota: El tiempo de inicio del primer capítulo debe permanecer en 0:00, y el tiempo de inicio del último capítulo no puede exceder la duración del audiolibro.",
"NoteFolderPicker": "Nota: las carpetas ya asignadas no se mostrarán", "NoteFolderPicker": "Nota: Las carpetas ya asignadas no se mostrarán",
"NoteFolderPickerDebian": "Nota: Folder picker for the debian install is not fully implemented. You should enter the path to your library directly.", "NoteFolderPickerDebian": "Nota: El selector de archivos no está completamente implementado para instalaciones en Debian. Deberá ingresar la ruta de la carpeta de su biblioteca directamente.",
"NoteRSSFeedPodcastAppsHttps": "Advertencia: La mayoría de las aplicaciones de podcast requieren que URL de la fuente RSS use HTTPS", "NoteRSSFeedPodcastAppsHttps": "Advertencia: La mayoría de las aplicaciones de podcast requieren que la URL de la fuente RSS use HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Advertencia: 1 o más de tus episodios no tienen fecha de publicación. Algunas aplicaciones de podcast lo requieren.", "NoteRSSFeedPodcastAppsPubDate": "Advertencia: 1 o más de sus episodios no tienen fecha de publicación. Algunas aplicaciones de podcast lo requieren.",
"NoteUploaderFoldersWithMediaFiles": "Las carpetas con archivos multimedia se manejarán como elementos separados en la biblioteca.", "NoteUploaderFoldersWithMediaFiles": "Las carpetas con archivos multimedia se manejarán como elementos separados en la biblioteca.",
"NoteUploaderOnlyAudioFiles": "Si subes solamente un archivos de audio, cada archivo se manejara como un audiolibro.", "NoteUploaderOnlyAudioFiles": "Si sube solamente archivos de audio, cada archivo se manejará como un audiolibro por separado.",
"NoteUploaderUnsupportedFiles": "Los archivos no soportados se ignoran. Al elegir o soltar una carpeta, los archivos que no estén en una carpeta serán ignorados.", "NoteUploaderUnsupportedFiles": "Se ignorarán los archivos no soportados. Al elegir o arrastrar una carpeta, los archivos que no estén dentro de una subcarpeta serán ignorados.",
"PlaceholderNewCollection": "Nuevo nombre de la colección", "PlaceholderNewCollection": "Nuevo nombre de la colección",
"PlaceholderNewFolderPath": "Nueva ruta de carpeta", "PlaceholderNewFolderPath": "Nueva ruta de carpeta",
"PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción", "PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción",
"PlaceholderSearch": "Buscando..", "PlaceholderSearch": "Buscar..",
"PlaceholderSearchEpisode": "Search episode..", "PlaceholderSearchEpisode": "Buscar Episodio..",
"ToastAccountUpdateFailed": "Error al actualizar cuenta", "ToastAccountUpdateFailed": "Error al actualizar cuenta",
"ToastAccountUpdateSuccess": "Cuenta actualizada", "ToastAccountUpdateSuccess": "Cuenta actualizada",
"ToastAuthorImageRemoveFailed": "Error al eliminar la imagen", "ToastAuthorImageRemoveFailed": "Error al eliminar la imagen",
@@ -646,16 +682,16 @@
"ToastBackupRestoreFailed": "Error al restaurar el respaldo", "ToastBackupRestoreFailed": "Error al restaurar el respaldo",
"ToastBackupUploadFailed": "Error al subir el respaldo", "ToastBackupUploadFailed": "Error al subir el respaldo",
"ToastBackupUploadSuccess": "Respaldo cargado", "ToastBackupUploadSuccess": "Respaldo cargado",
"ToastBatchUpdateFailed": "Batch update failed", "ToastBatchUpdateFailed": "Subida masiva fallida",
"ToastBatchUpdateSuccess": "Batch update success", "ToastBatchUpdateSuccess": "Subida masiva exitosa",
"ToastBookmarkCreateFailed": "Error al crear marcador", "ToastBookmarkCreateFailed": "Error al crear marcador",
"ToastBookmarkCreateSuccess": "Marca Agregado", "ToastBookmarkCreateSuccess": "Marcador Agregado",
"ToastBookmarkRemoveFailed": "Error al eliminar marcador", "ToastBookmarkRemoveFailed": "Error al eliminar marcador",
"ToastBookmarkRemoveSuccess": "Marcador eliminado", "ToastBookmarkRemoveSuccess": "Marcador eliminado",
"ToastBookmarkUpdateFailed": "Error al eliminar el marcador", "ToastBookmarkUpdateFailed": "Error al actualizar el marcador",
"ToastBookmarkUpdateSuccess": "Marcador actualizado", "ToastBookmarkUpdateSuccess": "Marcador actualizado",
"ToastChaptersHaveErrors": "Los capítulos tienen errores", "ToastChaptersHaveErrors": "Los capítulos tienen errores",
"ToastChaptersMustHaveTitles": "Los capítulos tienen que tener titulo", "ToastChaptersMustHaveTitles": "Los capítulos tienen que tener un título",
"ToastCollectionItemsRemoveFailed": "Error al remover elemento(s) de la colección", "ToastCollectionItemsRemoveFailed": "Error al remover elemento(s) de la colección",
"ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección", "ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección",
"ToastCollectionRemoveFailed": "Error al remover la colección", "ToastCollectionRemoveFailed": "Error al remover la colección",
@@ -665,7 +701,7 @@
"ToastItemCoverUpdateFailed": "Error al actualizar la portada del elemento", "ToastItemCoverUpdateFailed": "Error al actualizar la portada del elemento",
"ToastItemCoverUpdateSuccess": "Portada del elemento actualizada", "ToastItemCoverUpdateSuccess": "Portada del elemento actualizada",
"ToastItemDetailsUpdateFailed": "Error al actualizar los detalles del elemento", "ToastItemDetailsUpdateFailed": "Error al actualizar los detalles del elemento",
"ToastItemDetailsUpdateSuccess": "Detalles de Elemento Actualizados", "ToastItemDetailsUpdateSuccess": "Detalles del Elemento Actualizados",
"ToastItemDetailsUpdateUnneeded": "No se necesitan actualizaciones para los detalles del Elemento", "ToastItemDetailsUpdateUnneeded": "No se necesitan actualizaciones para los detalles del Elemento",
"ToastItemMarkedAsFinishedFailed": "Error al marcar como Terminado", "ToastItemMarkedAsFinishedFailed": "Error al marcar como Terminado",
"ToastItemMarkedAsFinishedSuccess": "Elemento marcado como terminado", "ToastItemMarkedAsFinishedSuccess": "Elemento marcado como terminado",
@@ -673,11 +709,11 @@
"ToastItemMarkedAsNotFinishedSuccess": "Elemento marcado como No Terminado", "ToastItemMarkedAsNotFinishedSuccess": "Elemento marcado como No Terminado",
"ToastLibraryCreateFailed": "Error al crear biblioteca", "ToastLibraryCreateFailed": "Error al crear biblioteca",
"ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada", "ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada",
"ToastLibraryDeleteFailed": "Error al eliminar la biblioteca", "ToastLibraryDeleteFailed": "Error al eliminar biblioteca",
"ToastLibraryDeleteSuccess": "Biblioteca eliminada", "ToastLibraryDeleteSuccess": "Biblioteca eliminada",
"ToastLibraryScanFailedToStart": "Error al iniciar la exploración", "ToastLibraryScanFailedToStart": "Error al iniciar el escaneo",
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca", "ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
"ToastLibraryUpdateFailed": "Error al actualizar biblioteca", "ToastLibraryUpdateFailed": "Error al actualizar la biblioteca",
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada", "ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
"ToastPlaylistCreateFailed": "Error al crear la lista de reproducción.", "ToastPlaylistCreateFailed": "Error al crear la lista de reproducción.",
"ToastPlaylistCreateSuccess": "Lista de reproducción creada", "ToastPlaylistCreateSuccess": "Lista de reproducción creada",
@@ -686,15 +722,15 @@
"ToastPlaylistUpdateFailed": "Error al actualizar la lista de reproducción.", "ToastPlaylistUpdateFailed": "Error al actualizar la lista de reproducción.",
"ToastPlaylistUpdateSuccess": "Lista de reproducción actualizada", "ToastPlaylistUpdateSuccess": "Lista de reproducción actualizada",
"ToastPodcastCreateFailed": "Error al crear podcast", "ToastPodcastCreateFailed": "Error al crear podcast",
"ToastPodcastCreateSuccess": "Podcast creada", "ToastPodcastCreateSuccess": "Podcast creado",
"ToastRemoveItemFromCollectionFailed": "Error al eliminar el elemento de la colección", "ToastRemoveItemFromCollectionFailed": "Error al eliminar el elemento de la colección",
"ToastRemoveItemFromCollectionSuccess": "Elemento eliminado de la colección.", "ToastRemoveItemFromCollectionSuccess": "Elemento eliminado de la colección.",
"ToastRSSFeedCloseFailed": "Error al cerrar fuente RSS", "ToastRSSFeedCloseFailed": "Error al cerrar fuente RSS",
"ToastRSSFeedCloseSuccess": "Fuente RSS cerrada", "ToastRSSFeedCloseSuccess": "Fuente RSS cerrada",
"ToastSendEbookToDeviceFailed": "Failed to Send Ebook to device", "ToastSendEbookToDeviceFailed": "Error al enviar el ebook al dispositivo",
"ToastSendEbookToDeviceSuccess": "Ebook sent to device \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook enviado al dispositivo \"{0}\"",
"ToastSeriesUpdateFailed": "Error al actualizar la serie", "ToastSeriesUpdateFailed": "Error al actualizar la serie",
"ToastSeriesUpdateSuccess": "Series actualizada", "ToastSeriesUpdateSuccess": "Serie actualizada",
"ToastSessionDeleteFailed": "Error al eliminar sesión", "ToastSessionDeleteFailed": "Error al eliminar sesión",
"ToastSessionDeleteSuccess": "Sesión eliminada", "ToastSessionDeleteSuccess": "Sesión eliminada",
"ToastSocketConnected": "Socket conectado", "ToastSocketConnected": "Socket conectado",
+77 -41
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Ajouter", "ButtonAdd": "Ajouter",
"ButtonAddChapters": "Ajouter le chapitre", "ButtonAddChapters": "Ajouter le chapitre",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Ajouter des podcasts", "ButtonAddPodcasts": "Ajouter des podcasts",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Ajouter votre première bibliothèque", "ButtonAddYourFirstLibrary": "Ajouter votre première bibliothèque",
"ButtonApply": "Appliquer", "ButtonApply": "Appliquer",
"ButtonApplyChapters": "Appliquer les chapitres", "ButtonApplyChapters": "Appliquer les chapitres",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Ne plus continuer à écouter la série", "ButtonRemoveSeriesFromContinueSeries": "Ne plus continuer à écouter la série",
"ButtonReScan": "Nouvelle analyse", "ButtonReScan": "Nouvelle analyse",
"ButtonReset": "Réinitialiser", "ButtonReset": "Réinitialiser",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Rétablir", "ButtonRestore": "Rétablir",
"ButtonSave": "Sauvegarder", "ButtonSave": "Sauvegarder",
"ButtonSaveAndClose": "Sauvegarder et Fermer", "ButtonSaveAndClose": "Sauvegarder et Fermer",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Configuration des Notifications Apprise", "HeaderAppriseNotificationSettings": "Configuration des Notifications Apprise",
"HeaderAudiobookTools": "Outils de Gestion de Fichier Audiobook", "HeaderAudiobookTools": "Outils de Gestion de Fichier Audiobook",
"HeaderAudioTracks": "Pistes audio", "HeaderAudioTracks": "Pistes audio",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Sauvegardes", "HeaderBackups": "Sauvegardes",
"HeaderChangePassword": "Modifier le mot de passe", "HeaderChangePassword": "Modifier le mot de passe",
"HeaderChapters": "Chapitres", "HeaderChapters": "Chapitres",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Gérer les étiquettes", "HeaderManageTags": "Gérer les étiquettes",
"HeaderMapDetails": "Édition en masse", "HeaderMapDetails": "Édition en masse",
"HeaderMatch": "Chercher", "HeaderMatch": "Chercher",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Métadonnée à intégrer", "HeaderMetadataToEmbed": "Métadonnée à intégrer",
"HeaderNewAccount": "Nouveau compte", "HeaderNewAccount": "Nouveau compte",
"HeaderNewLibrary": "Nouvelle bibliothèque", "HeaderNewLibrary": "Nouvelle bibliothèque",
"HeaderNotifications": "Notifications", "HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Ouvrir Flux RSS", "HeaderOpenRSSFeed": "Ouvrir Flux RSS",
"HeaderOtherFiles": "Autres fichiers", "HeaderOtherFiles": "Autres fichiers",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions", "HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Liste d’écoute", "HeaderPlayerQueue": "Liste d’écoute",
"HeaderPlaylist": "Liste de lecture", "HeaderPlaylist": "Liste de lecture",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Suppression de {0} épisodes", "HeaderRemoveEpisodes": "Suppression de {0} épisodes",
"HeaderRSSFeedGeneral": "Détails de flux RSS", "HeaderRSSFeedGeneral": "Détails de flux RSS",
"HeaderRSSFeedIsOpen": "Le Flux RSS est actif", "HeaderRSSFeedIsOpen": "Le Flux RSS est actif",
"HeaderRSSFeeds": "Flux RSS",
"HeaderSavedMediaProgress": "Progression de la sauvegarde des médias", "HeaderSavedMediaProgress": "Progression de la sauvegarde des médias",
"HeaderSchedule": "Programmation", "HeaderSchedule": "Programmation",
"HeaderScheduleLibraryScans": "Analyse automatique de la bibliothèque", "HeaderScheduleLibraryScans": "Analyse automatique de la bibliothèque",
@@ -147,7 +156,7 @@
"HeaderSettingsDisplay": "Affichage", "HeaderSettingsDisplay": "Affichage",
"HeaderSettingsExperimental": "Fonctionnalités expérimentales", "HeaderSettingsExperimental": "Fonctionnalités expérimentales",
"HeaderSettingsGeneral": "Général", "HeaderSettingsGeneral": "Général",
"HeaderSettingsScanner": "Scanneur", "HeaderSettingsScanner": "Analyseur",
"HeaderSleepTimer": "Minuterie", "HeaderSleepTimer": "Minuterie",
"HeaderStatsLargestItems": "Articles les plus lourd", "HeaderStatsLargestItems": "Articles les plus lourd",
"HeaderStatsLongestItems": "Articles les plus long (heures)", "HeaderStatsLongestItems": "Articles les plus long (heures)",
@@ -155,7 +164,7 @@
"HeaderStatsRecentSessions": "Sessions récentes", "HeaderStatsRecentSessions": "Sessions récentes",
"HeaderStatsTop10Authors": "Top 10 Auteurs", "HeaderStatsTop10Authors": "Top 10 Auteurs",
"HeaderStatsTop5Genres": "Top 5 Genres", "HeaderStatsTop5Genres": "Top 5 Genres",
"HeaderTableOfContents": "Table of Contents", "HeaderTableOfContents": "Table des matières",
"HeaderTools": "Outils", "HeaderTools": "Outils",
"HeaderUpdateAccount": "Mettre à jour le compte", "HeaderUpdateAccount": "Mettre à jour le compte",
"HeaderUpdateAuthor": "Mettre à jour lauteur", "HeaderUpdateAuthor": "Mettre à jour lauteur",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Ajout de {0} livres à la lollection", "LabelAddToCollectionBatch": "Ajout de {0} livres à la lollection",
"LabelAddToPlaylist": "Ajouter à la liste de lecture", "LabelAddToPlaylist": "Ajouter à la liste de lecture",
"LabelAddToPlaylistBatch": "{0} éléments ajoutés à la liste de lecture", "LabelAddToPlaylistBatch": "{0} éléments ajoutés à la liste de lecture",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "Tout", "LabelAll": "Tout",
"LabelAllUsers": "Tous les utilisateurs", "LabelAllUsers": "Tous les utilisateurs",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque", "LabelAlreadyInYourLibrary": "Déjà dans la bibliothèque",
"LabelAppend": "Ajouter", "LabelAppend": "Ajouter",
"LabelAuthor": "Auteur", "LabelAuthor": "Auteur",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Auteur (Nom, Prénom)", "LabelAuthorLastFirst": "Auteur (Nom, Prénom)",
"LabelAuthors": "Auteurs", "LabelAuthors": "Auteurs",
"LabelAutoDownloadEpisodes": "Téléchargement automatique d’épisode", "LabelAutoDownloadEpisodes": "Téléchargement automatique d’épisode",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Revenir à lUtilisateur", "LabelBackToUser": "Revenir à lUtilisateur",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques", "LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques",
"LabelBackupsEnableAutomaticBackupsHelp": "Sauvegardes Enregistrées dans /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Sauvegardes Enregistrées dans /metadata/backups",
"LabelBackupsMaxBackupSize": "Taille maximale de la sauvegarde (en Go)", "LabelBackupsMaxBackupSize": "Taille maximale de la sauvegarde (en Go)",
@@ -193,19 +210,22 @@
"LabelBackupsNumberToKeepHelp": "Une seule sauvegarde sera effacée à la fois. Si vous avez plus de sauvegardes à effacer, vous devrez le faire manuellement.", "LabelBackupsNumberToKeepHelp": "Une seule sauvegarde sera effacée à la fois. Si vous avez plus de sauvegardes à effacer, vous devrez le faire manuellement.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Livres", "LabelBooks": "Livres",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Modifier le mot de passe", "LabelChangePassword": "Modifier le mot de passe",
"LabelChannels": "Canaux", "LabelChannels": "Canaux",
"LabelChapters": "Chapitres", "LabelChapters": "Chapitres",
"LabelChaptersFound": "Chapitres trouvés", "LabelChaptersFound": "Chapitres trouvés",
"LabelChapterTitle": "Titres du chapitre", "LabelChapterTitle": "Titres du chapitre",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Fermer le lecteur", "LabelClosePlayer": "Fermer le lecteur",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Réduire les séries", "LabelCollapseSeries": "Réduire les séries",
"LabelCollection": "Collection",
"LabelCollections": "Collections", "LabelCollections": "Collections",
"LabelComplete": "Complet", "LabelComplete": "Complet",
"LabelConfirmPassword": "Confirmer le mot de passe", "LabelConfirmPassword": "Confirmer le mot de passe",
"LabelContinueListening": "Continuer la lecture", "LabelContinueListening": "Continuer la lecture",
"LabelContinueReading": "Continue Reading", "LabelContinueReading": "Continuer la lecture",
"LabelContinueSeries": "Continuer la série", "LabelContinueSeries": "Continuer la série",
"LabelCover": "Couverture", "LabelCover": "Couverture",
"LabelCoverImageURL": "URL vers limage de couverture", "LabelCoverImageURL": "URL vers limage de couverture",
@@ -215,13 +235,16 @@
"LabelCurrently": "En ce moment :", "LabelCurrently": "En ce moment :",
"LabelCustomCronExpression": "Expression cron personnalisée:", "LabelCustomCronExpression": "Expression cron personnalisée:",
"LabelDatetime": "Datetime", "LabelDatetime": "Datetime",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Description", "LabelDescription": "Description",
"LabelDeselectAll": "Tout déselectionner", "LabelDeselectAll": "Tout déselectionner",
"LabelDevice": "Appareil", "LabelDevice": "Appareil",
"LabelDeviceInfo": "Détail de lappareil", "LabelDeviceInfo": "Détail de lappareil",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Répertoire", "LabelDirectory": "Répertoire",
"LabelDiscFromFilename": "Disque depuis le fichier", "LabelDiscFromFilename": "Disque depuis le fichier",
"LabelDiscFromMetadata": "Disque depuis les métadonnées", "LabelDiscFromMetadata": "Disque depuis les métadonnées",
"LabelDiscover": "Découvrir",
"LabelDownload": "Téléchargement", "LabelDownload": "Téléchargement",
"LabelDownloadNEpisodes": "Télécharger {0} épisode(s)", "LabelDownloadNEpisodes": "Télécharger {0} épisode(s)",
"LabelDuration": "Durée", "LabelDuration": "Durée",
@@ -232,8 +255,8 @@
"LabelEmail": "Courriel", "LabelEmail": "Courriel",
"LabelEmailSettingsFromAddress": "Expéditeur", "LabelEmailSettingsFromAddress": "Expéditeur",
"LabelEmailSettingsSecure": "Sécurisé", "LabelEmailSettingsSecure": "Sécurisé",
"LabelEmailSettingsSecureHelp": "Si coché, la connexion utilisera TLS lors de la connexion au serveur. Sinon TLS est utilisé si le serveur prend en charge lextension STARTTLS. Dans la plupart des cas, cochez si vous vous connectez au port 465. Décochez pour le port 587 ou 25. (source: nodemailer.com/smtp/#authentication)", "LabelEmailSettingsSecureHelp": "Utiliser TLS lors de la connexion au serveur, autrement TLS sera utilisé si le serveur prend en charge lextension STARTTLS. Dans la plupart des cas, actviez loption si vous vous connectez au port 465. Désactivez loption pour utiliser port 587 ou 25. (source: nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Test Address", "LabelEmailSettingsTestAddress": "Adresse de test",
"LabelEmbeddedCover": "Couverture du livre intégrée", "LabelEmbeddedCover": "Couverture du livre intégrée",
"LabelEnable": "Activer", "LabelEnable": "Activer",
"LabelEnd": "Fin", "LabelEnd": "Fin",
@@ -252,16 +275,19 @@
"LabelFinished": "Fini(e)", "LabelFinished": "Fini(e)",
"LabelFolder": "Dossier", "LabelFolder": "Dossier",
"LabelFolders": "Dossiers", "LabelFolders": "Dossiers",
"LabelFontScale": "Font scale", "LabelFontFamily": "Famille de polices",
"LabelFontScale": "Taille de la police de caractère",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Genre", "LabelGenre": "Genre",
"LabelGenres": "Genres", "LabelGenres": "Genres",
"LabelHardDeleteFile": "Suppression du fichier", "LabelHardDeleteFile": "Suppression du fichier",
"LabelHasEbook": "Dispose dun livre numérique", "LabelHasEbook": "Dispose dun livre numérique",
"LabelHasSupplementaryEbook": "Dispose dun livre numérique supplémentaire", "LabelHasSupplementaryEbook": "Dispose dun livre numérique supplémentaire",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Hôte", "LabelHost": "Hôte",
"LabelHour": "Heure", "LabelHour": "Heure",
"LabelIcon": "Icone", "LabelIcon": "Icone",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Inclure dans la liste des pistes", "LabelIncludeInTracklist": "Inclure dans la liste des pistes",
"LabelIncomplete": "Incomplet", "LabelIncomplete": "Incomplet",
"LabelInProgress": "En cours", "LabelInProgress": "En cours",
@@ -284,23 +310,27 @@
"LabelLastSeen": "Vu dernièrement", "LabelLastSeen": "Vu dernièrement",
"LabelLastTime": "Progression", "LabelLastTime": "Progression",
"LabelLastUpdate": "Dernière mise à jour", "LabelLastUpdate": "Dernière mise à jour",
"LabelLayout": "Layout", "LabelLayout": "Disposition",
"LabelLayoutSinglePage": "Single page", "LabelLayoutSinglePage": "Vue unique",
"LabelLayoutSplitPage": "Split page", "LabelLayoutSplitPage": "Vue partagée",
"LabelLess": "Moins", "LabelLess": "Moins",
"LabelLibrariesAccessibleToUser": "Bibliothèque accessible à lutilisateur", "LabelLibrariesAccessibleToUser": "Bibliothèque accessible à lutilisateur",
"LabelLibrary": "Bibliothèque", "LabelLibrary": "Bibliothèque",
"LabelLibraryItem": "Article de bibliothèque", "LabelLibraryItem": "Article de bibliothèque",
"LabelLibraryName": "Nom de la bibliothèque", "LabelLibraryName": "Nom de la bibliothèque",
"LabelLimit": "Limite", "LabelLimit": "Limite",
"LabelLineSpacing": "Line spacing", "LabelLineSpacing": "Interligne",
"LabelListenAgain": "Écouter à nouveau", "LabelListenAgain": "Écouter à nouveau",
"LabelLogLevelDebug": "Debug", "LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn", "LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Chercher de nouveaux épisode après cette date", "LabelLookForNewEpisodesAfterDate": "Chercher de nouveaux épisode après cette date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Lecteur multimédia", "LabelMediaPlayer": "Lecteur multimédia",
"LabelMediaType": "Type de média", "LabelMediaType": "Type de média",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Fournisseur de métadonnées", "LabelMetadataProvider": "Fournisseur de métadonnées",
"LabelMetaTag": "Etiquette de métadonnée", "LabelMetaTag": "Etiquette de métadonnée",
"LabelMetaTags": "Etiquettes de métadonnée", "LabelMetaTags": "Etiquettes de métadonnée",
@@ -318,7 +348,7 @@
"LabelNewPassword": "Nouveau mot de passe", "LabelNewPassword": "Nouveau mot de passe",
"LabelNextBackupDate": "Date de la prochaine sauvegarde", "LabelNextBackupDate": "Date de la prochaine sauvegarde",
"LabelNextScheduledRun": "Prochain lancement prévu", "LabelNextScheduledRun": "Prochain lancement prévu",
"LabelNoEpisodesSelected": "No episodes selected", "LabelNoEpisodesSelected": "Aucun épisode sélectionné",
"LabelNotes": "Notes", "LabelNotes": "Notes",
"LabelNotFinished": "Non terminé(e)", "LabelNotFinished": "Non terminé(e)",
"LabelNotificationAppriseURL": "URL(s) dApprise", "LabelNotificationAppriseURL": "URL(s) dApprise",
@@ -378,8 +408,9 @@
"LabelSearchTitle": "Titre de recherche", "LabelSearchTitle": "Titre de recherche",
"LabelSearchTitleOrASIN": "Recherche du titre ou ASIN", "LabelSearchTitleOrASIN": "Recherche du titre ou ASIN",
"LabelSeason": "Saison", "LabelSeason": "Saison",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Sélectionner tous les épisodes",
"LabelSelectEpisodesShowing": "Sélectionner {0} episode(s) en cours", "LabelSelectEpisodesShowing": "Sélectionner {0} episode(s) en cours",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Envoyer le livre numérique à...", "LabelSendEbookToDevice": "Envoyer le livre numérique à...",
"LabelSequence": "Séquence", "LabelSequence": "Séquence",
"LabelSeries": "Séries", "LabelSeries": "Séries",
@@ -388,13 +419,16 @@
"LabelSetEbookAsPrimary": "Définir comme principale", "LabelSetEbookAsPrimary": "Définir comme principale",
"LabelSetEbookAsSupplementary": "Définir comme supplémentaire", "LabelSetEbookAsSupplementary": "Définir comme supplémentaire",
"LabelSettingsAudiobooksOnly": "Livres audios seulement", "LabelSettingsAudiobooksOnly": "Livres audios seulement",
"LabelSettingsAudiobooksOnlyHelp": "Lactivation de ce paramètre ignorera les fichiers “ ebook ”, à moins quils ne se trouvent dans un dossier de livres audio, auquel cas ils seront définis comme des livres numériques supplémentaires.", "LabelSettingsAudiobooksOnlyHelp": "Lactivation de ce paramètre ignorera les fichiers “ ebook ”, à moins quils ne se trouvent dans un dossier de livres audio, auquel cas ils seront définis comme des livres numériques supplémentaires.",
"LabelSettingsBookshelfViewHelp": "Interface skeuomorphique avec une étagère en bois", "LabelSettingsBookshelfViewHelp": "Interface skeuomorphique avec une étagère en bois",
"LabelSettingsChromecastSupport": "Support du Chromecast", "LabelSettingsChromecastSupport": "Support du Chromecast",
"LabelSettingsDateFormat": "Format de date", "LabelSettingsDateFormat": "Format de date",
"LabelSettingsDisableWatcher": "Désactiver la surveillance", "LabelSettingsDisableWatcher": "Désactiver la surveillance",
"LabelSettingsDisableWatcherForLibrary": "Désactiver la surveillance des dossiers pour la bibliothèque", "LabelSettingsDisableWatcherForLibrary": "Désactiver la surveillance des dossiers pour la bibliothèque",
"LabelSettingsDisableWatcherHelp": "Désactive la mise à jour automatique lorsque les fichiers changent. *Nécessite un redémarrage*", "LabelSettingsDisableWatcherHelp": "Désactive la mise à jour automatique lorsque des modifications de fichiers sont détectées. *Nécessite le redémarrage du serveur",
"LabelSettingsEnableWatcher": "Activer la veille",
"LabelSettingsEnableWatcherForLibrary": "Activer la surveillance des dossiers pour la bibliothèque",
"LabelSettingsEnableWatcherHelp": "Active la mise à jour automatique automatique lorsque des modifications de fichiers sont détectées. *Nécessite le redémarrage du serveur",
"LabelSettingsExperimentalFeatures": "Fonctionnalités expérimentales", "LabelSettingsExperimentalFeatures": "Fonctionnalités expérimentales",
"LabelSettingsExperimentalFeaturesHelp": "Fonctionnalités en cours de développement sur lesquelles nous attendons votre retour et expérience. Cliquez pour ouvrir la discussion Github.", "LabelSettingsExperimentalFeaturesHelp": "Fonctionnalités en cours de développement sur lesquelles nous attendons votre retour et expérience. Cliquez pour ouvrir la discussion Github.",
"LabelSettingsFindCovers": "Chercher des couvertures de livre", "LabelSettingsFindCovers": "Chercher des couvertures de livre",
@@ -403,30 +437,25 @@
"LabelSettingsHideSingleBookSeriesHelp": "Les séries qui ne comportent quun seul livre seront masquées sur la page de la série et sur les étagères de la page daccueil.", "LabelSettingsHideSingleBookSeriesHelp": "Les séries qui ne comportent quun seul livre seront masquées sur la page de la série et sur les étagères de la page daccueil.",
"LabelSettingsHomePageBookshelfView": "La page daccueil utilise la vue étagère", "LabelSettingsHomePageBookshelfView": "La page daccueil utilise la vue étagère",
"LabelSettingsLibraryBookshelfView": "La bibliothèque utilise la vue étagère", "LabelSettingsLibraryBookshelfView": "La bibliothèque utilise la vue étagère",
"LabelSettingsOverdriveMediaMarkers": "Utiliser Overdrive Media Marker pour les chapitres", "LabelSettingsParseSubtitles": "Analyser les sous-titres",
"LabelSettingsOverdriveMediaMarkersHelp": "Les fichiers MP3 dOverdrive viennent avec les minutages des chapitres intégrés en métadonnées. Activer ce paramètre utilisera ces minutages pour les chapitres automatiquement.",
"LabelSettingsParseSubtitles": "Analyse des sous-titres",
"LabelSettingsParseSubtitlesHelp": "Extrait les sous-titres depuis le dossier du Livre Audio.<br>Les sous-titres doivent être séparés par « - »<br>i.e. « Titre du Livre - Ceci est un sous-titre » aura le sous-titre « Ceci est un sous-titre »", "LabelSettingsParseSubtitlesHelp": "Extrait les sous-titres depuis le dossier du Livre Audio.<br>Les sous-titres doivent être séparés par « - »<br>i.e. « Titre du Livre - Ceci est un sous-titre » aura le sous-titre « Ceci est un sous-titre »",
"LabelSettingsPreferAudioMetadata": "Préférer les Métadonnées audio", "LabelSettingsPreferMatchedMetadata": "Préférer les métadonnées par correspondance",
"LabelSettingsPreferAudioMetadataHelp": "Les méta étiquettes ID3 des fichiers audios seront utilisés à la place des noms de dossier pour les détails du livre audio",
"LabelSettingsPreferMatchedMetadata": "Préférer les Métadonnées par correspondance",
"LabelSettingsPreferMatchedMetadataHelp": "Les métadonnées par correspondance écrase les détails de larticle lors dune recherche par correspondance rapide. Par défaut, la recherche par correspondance rapide ne comblera que les éléments manquant.", "LabelSettingsPreferMatchedMetadataHelp": "Les métadonnées par correspondance écrase les détails de larticle lors dune recherche par correspondance rapide. Par défaut, la recherche par correspondance rapide ne comblera que les éléments manquant.",
"LabelSettingsPreferOPFMetadata": "Préférer les Métadonnées OPF",
"LabelSettingsPreferOPFMetadataHelp": "Les fichiers de métadonnées OPF seront utilisés à la place des noms de dossier pour les détails du Livre Audio",
"LabelSettingsSkipMatchingBooksWithASIN": "Ignorer la recherche par correspondance sur les livres ayant déjà un ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Ignorer la recherche par correspondance sur les livres ayant déjà un ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Ignorer la recherche par correspondance sur les livres ayant déjà un ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Ignorer la recherche par correspondance sur les livres ayant déjà un ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignorer les préfixes lors du tri", "LabelSettingsSortingIgnorePrefixes": "Ignorer les préfixes lors du tri",
"LabelSettingsSortingIgnorePrefixesHelp": "i.e. pour le préfixe « le », le livre avec pour titre « Le Titre du Livre » sera trié en tant que « Titre du Livre, Le »", "LabelSettingsSortingIgnorePrefixesHelp": "i.e. pour le préfixe « le », le livre avec pour titre « Le Titre du Livre » sera trié en tant que « Titre du Livre, Le »",
"LabelSettingsSquareBookCovers": "Utiliser des couvertures carrées", "LabelSettingsSquareBookCovers": "Utiliser des couvertures carrées",
"LabelSettingsSquareBookCoversHelp": "Préférer les couvertures carrées par rapport aux couvertures standardes de 1.6:1.", "LabelSettingsSquareBookCoversHelp": "Préférer les couvertures carrées par rapport aux couvertures standards de ratio 1.6:1.",
"LabelSettingsStoreCoversWithItem": "Enregistrer la couverture avec les articles", "LabelSettingsStoreCoversWithItem": "Enregistrer la couverture avec les articles",
"LabelSettingsStoreCoversWithItemHelp": "Par défaut, les couvertures sont enregistrées dans /metadata/items. Activer ce paramètre enregistrera les couvertures dans le dossier avec les fichiers de larticle. Seul un fichier nommé « cover » sera conservé.", "LabelSettingsStoreCoversWithItemHelp": "Par défaut, les couvertures sont enregistrées dans /metadata/items. Activer ce paramètre enregistrera les couvertures dans le dossier avec les fichiers de larticle. Seul un fichier nommé « cover » sera conservé.",
"LabelSettingsStoreMetadataWithItem": "Enregistrer les Métadonnées avec les articles", "LabelSettingsStoreMetadataWithItem": "Enregistrer les Métadonnées avec les articles",
"LabelSettingsStoreMetadataWithItemHelp": "Par défaut, les métadonnées sont enregistrées dans /metadata/items. Activer ce paramètre enregistrera les métadonnées dans le dossier de larticle avec une extension « .abs ».", "LabelSettingsStoreMetadataWithItemHelp": "Par défaut, les métadonnées sont enregistrées dans /metadata/items",
"LabelSettingsTimeFormat": "Format dheure", "LabelSettingsTimeFormat": "Format dheure",
"LabelShowAll": "Afficher Tout", "LabelShowAll": "Afficher Tout",
"LabelSize": "Taille", "LabelSize": "Taille",
"LabelSleepTimer": "Minuterie", "LabelSleepTimer": "Minuterie",
"LabelSlug": "Slug",
"LabelStart": "Démarrer", "LabelStart": "Démarrer",
"LabelStarted": "Démarré", "LabelStarted": "Démarré",
"LabelStartedAt": "Démarré à", "LabelStartedAt": "Démarré à",
@@ -451,11 +480,11 @@
"LabelTag": "Étiquette", "LabelTag": "Étiquette",
"LabelTags": "Étiquettes", "LabelTags": "Étiquettes",
"LabelTagsAccessibleToUser": "Étiquettes accessibles à lutilisateur", "LabelTagsAccessibleToUser": "Étiquettes accessibles à lutilisateur",
"LabelTagsNotAccessibleToUser": "Tags not Accessible to User", "LabelTagsNotAccessibleToUser": "Étiquettes non accessibles à lutilisateur",
"LabelTasks": "Tâches en cours", "LabelTasks": "Tâches en cours",
"LabelTheme": "Theme", "LabelTheme": "Thème",
"LabelThemeDark": "Dark", "LabelThemeDark": "Sombre",
"LabelThemeLight": "Light", "LabelThemeLight": "Clair",
"LabelTimeBase": "Base de temps", "LabelTimeBase": "Base de temps",
"LabelTimeListened": "Temps d’écoute", "LabelTimeListened": "Temps d’écoute",
"LabelTimeListenedToday": "Nombres d’écoutes Aujourdhui", "LabelTimeListenedToday": "Nombres d’écoutes Aujourdhui",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Piste depuis les métadonnées", "LabelTrackFromMetadata": "Piste depuis les métadonnées",
"LabelTracks": "Pistes", "LabelTracks": "Pistes",
"LabelTracksMultiTrack": "Piste multiple", "LabelTracksMultiTrack": "Piste multiple",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Piste simple", "LabelTracksSingleTrack": "Piste simple",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Version intégrale", "LabelUnabridged": "Version intégrale",
@@ -514,20 +544,25 @@
"MessageChapterErrorStartLtPrev": "Horodatage invalide car il doit débuter au moins après le précédent chapitre", "MessageChapterErrorStartLtPrev": "Horodatage invalide car il doit débuter au moins après le précédent chapitre",
"MessageChapterStartIsAfter": "Le premier chapitre est situé au début de votre livre audio", "MessageChapterStartIsAfter": "Le premier chapitre est situé au début de votre livre audio",
"MessageCheckingCron": "Vérification du cron…", "MessageCheckingCron": "Vérification du cron…",
"MessageConfirmDeleteBackup": "Êtes-vous sûr de vouloir supprimer la Sauvegarde de {0} ?", "MessageConfirmCloseFeed": "Êtes-vous sûr de vouloir fermer ce flux ?",
"MessageConfirmDeleteFile": "Cela Le fichier sera supprimer de votre système. Êtes-vous sûr ?", "MessageConfirmDeleteBackup": "Êtes-vous sûr de vouloir supprimer la sauvegarde de « {0} » ?",
"MessageConfirmDeleteFile": "Cela supprimera le fichier de votre système de fichiers. Êtes-vous sûr ?",
"MessageConfirmDeleteLibrary": "Êtes-vous sûr de vouloir supprimer définitivement la bibliothèque « {0} » ?", "MessageConfirmDeleteLibrary": "Êtes-vous sûr de vouloir supprimer définitivement la bibliothèque « {0} » ?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Êtes-vous sûr de vouloir supprimer cette session ?", "MessageConfirmDeleteSession": "Êtes-vous sûr de vouloir supprimer cette session ?",
"MessageConfirmForceReScan": "Êtes-vous sûr de vouloir lancer une Analyse Forcée ?", "MessageConfirmForceReScan": "Êtes-vous sûr de vouloir lancer une analyse forcée ?",
"MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr de marquer tous les épisodes comme terminés ?", "MessageConfirmMarkAllEpisodesFinished": "Êtes-vous sûr de marquer tous les épisodes comme terminés ?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Êtes-vous sûr de vouloir marquer tous les épisodes comme non terminés ?",
"MessageConfirmMarkSeriesFinished": "Êtes-vous sûr de vouloir marquer comme terminé tous les livres de cette série ?", "MessageConfirmMarkSeriesFinished": "Êtes-vous sûr de vouloir marquer tous les livres de cette série comme terminées ?",
"MessageConfirmMarkSeriesNotFinished": "Êtes-vous sûr de vouloir marquer comme non terminé tous les livres de cette série ?", "MessageConfirmMarkSeriesNotFinished": "Êtes-vous sûr de vouloir marquer tous les livres de cette série comme comme non terminés ?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Êtes-vous sûr de vouloir supprimer tous les chapitres ?", "MessageConfirmRemoveAllChapters": "Êtes-vous sûr de vouloir supprimer tous les chapitres ?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "Êtes-vous sûr de vouloir supprimer la collection « {0} » ?", "MessageConfirmRemoveCollection": "Êtes-vous sûr de vouloir supprimer la collection « {0} » ?",
"MessageConfirmRemoveEpisode": "Êtes-vous sûr de vouloir supprimer l’épisode « {0} » ?", "MessageConfirmRemoveEpisode": "Êtes-vous sûr de vouloir supprimer l’épisode « {0} » ?",
"MessageConfirmRemoveEpisodes": "Êtes-vous sûr de vouloir supprimer {0} épisodes ?", "MessageConfirmRemoveEpisodes": "Êtes-vous sûr de vouloir supprimer {0} épisodes ?",
"MessageConfirmRemoveNarrator": "Êtes-vous sûr de vouloir supprimer le narrateur \"{0}\"?", "MessageConfirmRemoveNarrator": "Êtes-vous sûr de vouloir supprimer le narrateur « {0} » ?",
"MessageConfirmRemovePlaylist": "Êtes-vous sûr de vouloir supprimer la liste de lecture « {0} » ?", "MessageConfirmRemovePlaylist": "Êtes-vous sûr de vouloir supprimer la liste de lecture « {0} » ?",
"MessageConfirmRenameGenre": "Êtes-vous sûr de vouloir renommer le genre « {0} » en « {1} » pour tous les articles ?", "MessageConfirmRenameGenre": "Êtes-vous sûr de vouloir renommer le genre « {0} » en « {1} » pour tous les articles ?",
"MessageConfirmRenameGenreMergeNote": "Information: Ce genre existe déjà et sera fusionné.", "MessageConfirmRenameGenreMergeNote": "Information: Ce genre existe déjà et sera fusionné.",
@@ -535,12 +570,13 @@
"MessageConfirmRenameTag": "Êtes-vous sûr de vouloir renommer l’étiquette « {0} » en « {1} » pour tous les articles ?", "MessageConfirmRenameTag": "Êtes-vous sûr de vouloir renommer l’étiquette « {0} » en « {1} » pour tous les articles ?",
"MessageConfirmRenameTagMergeNote": "Information: Cette étiquette existe déjà et sera fusionnée.", "MessageConfirmRenameTagMergeNote": "Information: Cette étiquette existe déjà et sera fusionnée.",
"MessageConfirmRenameTagWarning": "Attention ! Une étiquette similaire avec une casse différente existe déjà « {0} ».", "MessageConfirmRenameTagWarning": "Attention ! Une étiquette similaire avec une casse différente existe déjà « {0} ».",
"MessageConfirmSendEbookToDevice": "Êtes-vous sûr de vouloir envoyer le livre numérique {0} \"{1}\" à lappareil \"{2}\"?", "MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Êtes-vous sûr de vouloir envoyer le livre numérique {0} « {1} » à lappareil « {2} »?",
"MessageDownloadingEpisode": "Téléchargement de l’épisode", "MessageDownloadingEpisode": "Téléchargement de l’épisode",
"MessageDragFilesIntoTrackOrder": "Faire glisser les fichiers dans lordre correct", "MessageDragFilesIntoTrackOrder": "Faire glisser les fichiers dans lordre correct",
"MessageEmbedFinished": "Intégration Terminée !", "MessageEmbedFinished": "Intégration terminée !",
"MessageEpisodesQueuedForDownload": "{0} épisode(s) mis en file pour téléchargement", "MessageEpisodesQueuedForDownload": "{0} épisode(s) mis en file pour téléchargement",
"MessageFeedURLWillBe": "lURL du Flux sera {0}", "MessageFeedURLWillBe": "lURL du flux sera {0}",
"MessageFetching": "Récupération…", "MessageFetching": "Récupération…",
"MessageForceReScanDescription": "Analysera tous les fichiers de nouveau. Les étiquettes ID3 des fichiers audios, fichiers OPF, et les fichiers textes seront analysés comme sils étaient nouveaux.", "MessageForceReScanDescription": "Analysera tous les fichiers de nouveau. Les étiquettes ID3 des fichiers audios, fichiers OPF, et les fichiers textes seront analysés comme sils étaient nouveaux.",
"MessageImportantNotice": "Information Importante !", "MessageImportantNotice": "Information Importante !",
@@ -551,8 +587,8 @@
"MessageListeningSessionsInTheLastYear": "{0} sessions d’écoute lan dernier", "MessageListeningSessionsInTheLastYear": "{0} sessions d’écoute lan dernier",
"MessageLoading": "Chargement…", "MessageLoading": "Chargement…",
"MessageLoadingFolders": "Chargement des dossiers…", "MessageLoadingFolders": "Chargement des dossiers…",
"MessageM4BFailed": "M4B en échec !", "MessageM4BFailed": "M4B échec",
"MessageM4BFinished": "M4B terminé !", "MessageM4BFinished": "M4B terminé",
"MessageMapChapterTitles": "Faire correspondre les titres des chapitres aux chapitres existants de votre livre audio sans ajuster lhorodatage.", "MessageMapChapterTitles": "Faire correspondre les titres des chapitres aux chapitres existants de votre livre audio sans ajuster lhorodatage.",
"MessageMarkAllEpisodesFinished": "Marquer tous les épisodes terminés", "MessageMarkAllEpisodesFinished": "Marquer tous les épisodes terminés",
"MessageMarkAllEpisodesNotFinished": "Marquer tous les épisodes non terminés", "MessageMarkAllEpisodesNotFinished": "Marquer tous les épisodes non terminés",
@@ -702,4 +738,4 @@
"ToastSocketFailedToConnect": "Échec de la connexion WebSocket", "ToastSocketFailedToConnect": "Échec de la connexion WebSocket",
"ToastUserDeleteFailed": "Échec de la suppression de lutilisateur", "ToastUserDeleteFailed": "Échec de la suppression de lutilisateur",
"ToastUserDeleteSuccess": "Utilisateur supprimé" "ToastUserDeleteSuccess": "Utilisateur supprimé"
} }
+43 -7
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "ઉમેરો", "ButtonAdd": "ઉમેરો",
"ButtonAddChapters": "પ્રકરણો ઉમેરો", "ButtonAddChapters": "પ્રકરણો ઉમેરો",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "પોડકાસ્ટ ઉમેરો", "ButtonAddPodcasts": "પોડકાસ્ટ ઉમેરો",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "તમારી પ્રથમ પુસ્તકાલય ઉમેરો", "ButtonAddYourFirstLibrary": "તમારી પ્રથમ પુસ્તકાલય ઉમેરો",
"ButtonApply": "લાગુ કરો", "ButtonApply": "લાગુ કરો",
"ButtonApplyChapters": "પ્રકરણો લાગુ કરો", "ButtonApplyChapters": "પ્રકરણો લાગુ કરો",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "સાંભળતી સિરીઝ માંથી કાઢી નાખો", "ButtonRemoveSeriesFromContinueSeries": "સાંભળતી સિરીઝ માંથી કાઢી નાખો",
"ButtonReScan": "ફરીથી સ્કેન કરો", "ButtonReScan": "ફરીથી સ્કેન કરો",
"ButtonReset": "રીસેટ કરો", "ButtonReset": "રીસેટ કરો",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "પુનઃસ્થાપિત કરો", "ButtonRestore": "પુનઃસ્થાપિત કરો",
"ButtonSave": "સાચવો", "ButtonSave": "સાચવો",
"ButtonSaveAndClose": "સાચવો અને બંધ કરો", "ButtonSaveAndClose": "સાચવો અને બંધ કરો",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise સૂચના સેટિંગ્સ", "HeaderAppriseNotificationSettings": "Apprise સૂચના સેટિંગ્સ",
"HeaderAudiobookTools": "Audiobook File Management Tools", "HeaderAudiobookTools": "Audiobook File Management Tools",
"HeaderAudioTracks": "Audio Tracks", "HeaderAudioTracks": "Audio Tracks",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Backups", "HeaderBackups": "Backups",
"HeaderChangePassword": "Change Password", "HeaderChangePassword": "Change Password",
"HeaderChapters": "Chapters", "HeaderChapters": "Chapters",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Manage Tags", "HeaderManageTags": "Manage Tags",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Map details",
"HeaderMatch": "Match", "HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadata to embed", "HeaderMetadataToEmbed": "Metadata to embed",
"HeaderNewAccount": "New Account", "HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library", "HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications", "HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed", "HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files", "HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions", "HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue", "HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Remove {0} Episodes", "HeaderRemoveEpisodes": "Remove {0} Episodes",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed is Open", "HeaderRSSFeedIsOpen": "RSS Feed is Open",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Saved Media Progress", "HeaderSavedMediaProgress": "Saved Media Progress",
"HeaderSchedule": "Schedule", "HeaderSchedule": "Schedule",
"HeaderScheduleLibraryScans": "Schedule Automatic Library Scans", "HeaderScheduleLibraryScans": "Schedule Automatic Library Scans",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Add {0} Books to Collection", "LabelAddToCollectionBatch": "Add {0} Books to Collection",
"LabelAddToPlaylist": "Add to Playlist", "LabelAddToPlaylist": "Add to Playlist",
"LabelAddToPlaylistBatch": "Add {0} Items to Playlist", "LabelAddToPlaylistBatch": "Add {0} Items to Playlist",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "All", "LabelAll": "All",
"LabelAllUsers": "All Users", "LabelAllUsers": "All Users",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Already in your library", "LabelAlreadyInYourLibrary": "Already in your library",
"LabelAppend": "Append", "LabelAppend": "Append",
"LabelAuthor": "Author", "LabelAuthor": "Author",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Author (Last, First)", "LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors", "LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes", "LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User", "LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups", "LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximum backup size (in GB)", "LabelBackupsMaxBackupSize": "Maximum backup size (in GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.", "LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Books", "LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password", "LabelChangePassword": "Change Password",
"LabelChannels": "Channels", "LabelChannels": "Channels",
"LabelChapters": "Chapters", "LabelChapters": "Chapters",
"LabelChaptersFound": "chapters found", "LabelChaptersFound": "chapters found",
"LabelChapterTitle": "Chapter Title", "LabelChapterTitle": "Chapter Title",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Close player", "LabelClosePlayer": "Close player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Collapse Series", "LabelCollapseSeries": "Collapse Series",
"LabelCollection": "Collection",
"LabelCollections": "Collections", "LabelCollections": "Collections",
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
@@ -215,13 +235,16 @@
"LabelCurrently": "Currently:", "LabelCurrently": "Currently:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Custom Cron Expression:",
"LabelDatetime": "Datetime", "LabelDatetime": "Datetime",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Description", "LabelDescription": "Description",
"LabelDeselectAll": "Deselect All", "LabelDeselectAll": "Deselect All",
"LabelDevice": "Device", "LabelDevice": "Device",
"LabelDeviceInfo": "Device Info", "LabelDeviceInfo": "Device Info",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Directory", "LabelDirectory": "Directory",
"LabelDiscFromFilename": "Disc from Filename", "LabelDiscFromFilename": "Disc from Filename",
"LabelDiscFromMetadata": "Disc from Metadata", "LabelDiscFromMetadata": "Disc from Metadata",
"LabelDiscover": "Discover",
"LabelDownload": "Download", "LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Duration", "LabelDuration": "Duration",
@@ -252,6 +275,7 @@
"LabelFinished": "Finished", "LabelFinished": "Finished",
"LabelFolder": "Folder", "LabelFolder": "Folder",
"LabelFolders": "Folders", "LabelFolders": "Folders",
"LabelFontFamily": "ફોન્ટ કુટુંબ",
"LabelFontScale": "Font scale", "LabelFontScale": "Font scale",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Genre", "LabelGenre": "Genre",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Hard delete file", "LabelHardDeleteFile": "Hard delete file",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Has ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Has supplementary ebook",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Hour", "LabelHour": "Hour",
"LabelIcon": "Icon", "LabelIcon": "Icon",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Include in Tracklist", "LabelIncludeInTracklist": "Include in Tracklist",
"LabelIncomplete": "Incomplete", "LabelIncomplete": "Incomplete",
"LabelInProgress": "In Progress", "LabelInProgress": "In Progress",
@@ -299,8 +325,12 @@
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn", "LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date", "LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadata Provider", "LabelMetadataProvider": "Metadata Provider",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Season", "LabelSeason": "Season",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Select all episodes",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Select {0} episodes showing",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSendEbookToDevice": "Send Ebook to...",
"LabelSequence": "Sequence", "LabelSequence": "Sequence",
"LabelSeries": "Series", "LabelSeries": "Series",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Disable Watcher", "LabelSettingsDisableWatcher": "Disable Watcher",
"LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library", "LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library",
"LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart", "LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsEnableWatcher": "Enable Watcher",
"LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
"LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Experimental features", "LabelSettingsExperimentalFeatures": "Experimental features",
"LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.", "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
"LabelSettingsFindCovers": "Find covers", "LabelSettingsFindCovers": "Find covers",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view", "LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view", "LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
"LabelSettingsOverdriveMediaMarkers": "Use Overdrive Media Markers for chapters",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically",
"LabelSettingsParseSubtitles": "Parse subtitles", "LabelSettingsParseSubtitles": "Parse subtitles",
"LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"", "LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"",
"LabelSettingsPreferAudioMetadata": "Prefer audio metadata",
"LabelSettingsPreferAudioMetadataHelp": "Audio file ID3 meta tags will be used for book details over folder names",
"LabelSettingsPreferMatchedMetadata": "Prefer matched metadata", "LabelSettingsPreferMatchedMetadata": "Prefer matched metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.", "LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.",
"LabelSettingsPreferOPFMetadata": "Prefer OPF metadata",
"LabelSettingsPreferOPFMetadataHelp": "OPF file metadata will be used for book details over folder names",
"LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting", "LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Store covers with item", "LabelSettingsStoreCoversWithItem": "Store covers with item",
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept", "LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
"LabelSettingsStoreMetadataWithItem": "Store metadata with item", "LabelSettingsStoreMetadataWithItem": "Store metadata with item",
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension", "LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders",
"LabelSettingsTimeFormat": "Time Format", "LabelSettingsTimeFormat": "Time Format",
"LabelShowAll": "Show All", "LabelShowAll": "Show All",
"LabelSize": "Size", "LabelSize": "Size",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSlug": "Slug",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStarted": "Started", "LabelStarted": "Started",
"LabelStartedAt": "Started At", "LabelStartedAt": "Started At",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Track from Metadata", "LabelTrackFromMetadata": "Track from Metadata",
"LabelTracks": "Tracks", "LabelTracks": "Tracks",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Single-track", "LabelTracksSingleTrack": "Single-track",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "Unabridged",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time", "MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time",
"MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook", "MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook",
"MessageCheckingCron": "Checking cron...", "MessageCheckingCron": "Checking cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?", "MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?",
"MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?", "MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Are you sure you want to delete this session?", "MessageConfirmDeleteSession": "Are you sure you want to delete this session?",
"MessageConfirmForceReScan": "Are you sure you want to force re-scan?", "MessageConfirmForceReScan": "Are you sure you want to force re-scan?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?",
"MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?", "MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?",
"MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?", "MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?", "MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?", "MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?",
"MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?", "MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?", "MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?",
@@ -535,6 +570,7 @@
"MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?", "MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?",
"MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.", "MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.",
"MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".", "MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?",
"MessageDownloadingEpisode": "Downloading episode", "MessageDownloadingEpisode": "Downloading episode",
"MessageDragFilesIntoTrackOrder": "Drag files into correct track order", "MessageDragFilesIntoTrackOrder": "Drag files into correct track order",
+43 -7
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "जोड़ें", "ButtonAdd": "जोड़ें",
"ButtonAddChapters": "अध्याय जोड़ें", "ButtonAddChapters": "अध्याय जोड़ें",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "पॉडकास्ट जोड़ें", "ButtonAddPodcasts": "पॉडकास्ट जोड़ें",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "अपनी पहली पुस्तकालय जोड़ें", "ButtonAddYourFirstLibrary": "अपनी पहली पुस्तकालय जोड़ें",
"ButtonApply": "लागू करें", "ButtonApply": "लागू करें",
"ButtonApplyChapters": "अध्यायों में परिवर्तन लागू करें", "ButtonApplyChapters": "अध्यायों में परिवर्तन लागू करें",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "इस सीरीज को कंटिन्यू सीरीज से हटा दें", "ButtonRemoveSeriesFromContinueSeries": "इस सीरीज को कंटिन्यू सीरीज से हटा दें",
"ButtonReScan": "पुन: स्कैन करें", "ButtonReScan": "पुन: स्कैन करें",
"ButtonReset": "रीसेट करें", "ButtonReset": "रीसेट करें",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "पुनर्स्थापित करें", "ButtonRestore": "पुनर्स्थापित करें",
"ButtonSave": "सहेजें", "ButtonSave": "सहेजें",
"ButtonSaveAndClose": "सहेजें और बंद करें", "ButtonSaveAndClose": "सहेजें और बंद करें",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise अधिसूचना सेटिंग्स", "HeaderAppriseNotificationSettings": "Apprise अधिसूचना सेटिंग्स",
"HeaderAudiobookTools": "Audiobook File Management Tools", "HeaderAudiobookTools": "Audiobook File Management Tools",
"HeaderAudioTracks": "Audio Tracks", "HeaderAudioTracks": "Audio Tracks",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Backups", "HeaderBackups": "Backups",
"HeaderChangePassword": "Change Password", "HeaderChangePassword": "Change Password",
"HeaderChapters": "Chapters", "HeaderChapters": "Chapters",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Manage Tags", "HeaderManageTags": "Manage Tags",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Map details",
"HeaderMatch": "Match", "HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadata to embed", "HeaderMetadataToEmbed": "Metadata to embed",
"HeaderNewAccount": "New Account", "HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library", "HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications", "HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed", "HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files", "HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions", "HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue", "HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Remove {0} Episodes", "HeaderRemoveEpisodes": "Remove {0} Episodes",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed is Open", "HeaderRSSFeedIsOpen": "RSS Feed is Open",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Saved Media Progress", "HeaderSavedMediaProgress": "Saved Media Progress",
"HeaderSchedule": "Schedule", "HeaderSchedule": "Schedule",
"HeaderScheduleLibraryScans": "Schedule Automatic Library Scans", "HeaderScheduleLibraryScans": "Schedule Automatic Library Scans",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Add {0} Books to Collection", "LabelAddToCollectionBatch": "Add {0} Books to Collection",
"LabelAddToPlaylist": "Add to Playlist", "LabelAddToPlaylist": "Add to Playlist",
"LabelAddToPlaylistBatch": "Add {0} Items to Playlist", "LabelAddToPlaylistBatch": "Add {0} Items to Playlist",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "All", "LabelAll": "All",
"LabelAllUsers": "All Users", "LabelAllUsers": "All Users",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Already in your library", "LabelAlreadyInYourLibrary": "Already in your library",
"LabelAppend": "Append", "LabelAppend": "Append",
"LabelAuthor": "Author", "LabelAuthor": "Author",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Author (Last, First)", "LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors", "LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes", "LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User", "LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups", "LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Backups saved in /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximum backup size (in GB)", "LabelBackupsMaxBackupSize": "Maximum backup size (in GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.", "LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Books", "LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password", "LabelChangePassword": "Change Password",
"LabelChannels": "Channels", "LabelChannels": "Channels",
"LabelChapters": "Chapters", "LabelChapters": "Chapters",
"LabelChaptersFound": "chapters found", "LabelChaptersFound": "chapters found",
"LabelChapterTitle": "Chapter Title", "LabelChapterTitle": "Chapter Title",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Close player", "LabelClosePlayer": "Close player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Collapse Series", "LabelCollapseSeries": "Collapse Series",
"LabelCollection": "Collection",
"LabelCollections": "Collections", "LabelCollections": "Collections",
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Confirm Password", "LabelConfirmPassword": "Confirm Password",
@@ -215,13 +235,16 @@
"LabelCurrently": "Currently:", "LabelCurrently": "Currently:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Custom Cron Expression:",
"LabelDatetime": "Datetime", "LabelDatetime": "Datetime",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Description", "LabelDescription": "Description",
"LabelDeselectAll": "Deselect All", "LabelDeselectAll": "Deselect All",
"LabelDevice": "Device", "LabelDevice": "Device",
"LabelDeviceInfo": "Device Info", "LabelDeviceInfo": "Device Info",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Directory", "LabelDirectory": "Directory",
"LabelDiscFromFilename": "Disc from Filename", "LabelDiscFromFilename": "Disc from Filename",
"LabelDiscFromMetadata": "Disc from Metadata", "LabelDiscFromMetadata": "Disc from Metadata",
"LabelDiscover": "Discover",
"LabelDownload": "Download", "LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Duration", "LabelDuration": "Duration",
@@ -252,6 +275,7 @@
"LabelFinished": "Finished", "LabelFinished": "Finished",
"LabelFolder": "Folder", "LabelFolder": "Folder",
"LabelFolders": "Folders", "LabelFolders": "Folders",
"LabelFontFamily": "फुहारा परिवार",
"LabelFontScale": "Font scale", "LabelFontScale": "Font scale",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Genre", "LabelGenre": "Genre",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Hard delete file", "LabelHardDeleteFile": "Hard delete file",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Has ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Has supplementary ebook",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Hour", "LabelHour": "Hour",
"LabelIcon": "Icon", "LabelIcon": "Icon",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Include in Tracklist", "LabelIncludeInTracklist": "Include in Tracklist",
"LabelIncomplete": "Incomplete", "LabelIncomplete": "Incomplete",
"LabelInProgress": "In Progress", "LabelInProgress": "In Progress",
@@ -299,8 +325,12 @@
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn", "LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date", "LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadata Provider", "LabelMetadataProvider": "Metadata Provider",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Season", "LabelSeason": "Season",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Select all episodes",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Select {0} episodes showing",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSendEbookToDevice": "Send Ebook to...",
"LabelSequence": "Sequence", "LabelSequence": "Sequence",
"LabelSeries": "Series", "LabelSeries": "Series",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Disable Watcher", "LabelSettingsDisableWatcher": "Disable Watcher",
"LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library", "LabelSettingsDisableWatcherForLibrary": "Disable folder watcher for library",
"LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart", "LabelSettingsDisableWatcherHelp": "Disables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsEnableWatcher": "Enable Watcher",
"LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
"LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Experimental features", "LabelSettingsExperimentalFeatures": "Experimental features",
"LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.", "LabelSettingsExperimentalFeaturesHelp": "Features in development that could use your feedback and help testing. Click to open github discussion.",
"LabelSettingsFindCovers": "Find covers", "LabelSettingsFindCovers": "Find covers",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
"LabelSettingsHomePageBookshelfView": "Home page use bookshelf view", "LabelSettingsHomePageBookshelfView": "Home page use bookshelf view",
"LabelSettingsLibraryBookshelfView": "Library use bookshelf view", "LabelSettingsLibraryBookshelfView": "Library use bookshelf view",
"LabelSettingsOverdriveMediaMarkers": "Use Overdrive Media Markers for chapters",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3 files from Overdrive come with chapter timings embedded as custom metadata. Enabling this will use these tags for chapter timings automatically",
"LabelSettingsParseSubtitles": "Parse subtitles", "LabelSettingsParseSubtitles": "Parse subtitles",
"LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"", "LabelSettingsParseSubtitlesHelp": "Extract subtitles from audiobook folder names.<br>Subtitle must be seperated by \" - \"<br>i.e. \"Book Title - A Subtitle Here\" has the subtitle \"A Subtitle Here\"",
"LabelSettingsPreferAudioMetadata": "Prefer audio metadata",
"LabelSettingsPreferAudioMetadataHelp": "Audio file ID3 meta tags will be used for book details over folder names",
"LabelSettingsPreferMatchedMetadata": "Prefer matched metadata", "LabelSettingsPreferMatchedMetadata": "Prefer matched metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.", "LabelSettingsPreferMatchedMetadataHelp": "Matched data will overide item details when using Quick Match. By default Quick Match will only fill in missing details.",
"LabelSettingsPreferOPFMetadata": "Prefer OPF metadata",
"LabelSettingsPreferOPFMetadataHelp": "OPF file metadata will be used for book details over folder names",
"LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Skip matching books that already have an ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Skip matching books that already have an ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting", "LabelSettingsSortingIgnorePrefixes": "Ignore prefixes when sorting",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Store covers with item", "LabelSettingsStoreCoversWithItem": "Store covers with item",
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept", "LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
"LabelSettingsStoreMetadataWithItem": "Store metadata with item", "LabelSettingsStoreMetadataWithItem": "Store metadata with item",
"LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders. Uses .abs file extension", "LabelSettingsStoreMetadataWithItemHelp": "By default metadata files are stored in /metadata/items, enabling this setting will store metadata files in your library item folders",
"LabelSettingsTimeFormat": "Time Format", "LabelSettingsTimeFormat": "Time Format",
"LabelShowAll": "Show All", "LabelShowAll": "Show All",
"LabelSize": "Size", "LabelSize": "Size",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSlug": "Slug",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStarted": "Started", "LabelStarted": "Started",
"LabelStartedAt": "Started At", "LabelStartedAt": "Started At",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Track from Metadata", "LabelTrackFromMetadata": "Track from Metadata",
"LabelTracks": "Tracks", "LabelTracks": "Tracks",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Single-track", "LabelTracksSingleTrack": "Single-track",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "Unabridged",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time", "MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time",
"MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook", "MessageChapterStartIsAfter": "Chapter start is after the end of your audiobook",
"MessageCheckingCron": "Checking cron...", "MessageCheckingCron": "Checking cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?", "MessageConfirmDeleteBackup": "Are you sure you want to delete backup for {0}?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?",
"MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?", "MessageConfirmDeleteLibrary": "Are you sure you want to permanently delete library \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Are you sure you want to delete this session?", "MessageConfirmDeleteSession": "Are you sure you want to delete this session?",
"MessageConfirmForceReScan": "Are you sure you want to force re-scan?", "MessageConfirmForceReScan": "Are you sure you want to force re-scan?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?",
"MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?", "MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?",
"MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?", "MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?", "MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?", "MessageConfirmRemoveCollection": "Are you sure you want to remove collection \"{0}\"?",
"MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?", "MessageConfirmRemoveEpisode": "Are you sure you want to remove episode \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?", "MessageConfirmRemoveEpisodes": "Are you sure you want to remove {0} episodes?",
@@ -535,6 +570,7 @@
"MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?", "MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?",
"MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.", "MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.",
"MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".", "MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?",
"MessageDownloadingEpisode": "Downloading episode", "MessageDownloadingEpisode": "Downloading episode",
"MessageDragFilesIntoTrackOrder": "Drag files into correct track order", "MessageDragFilesIntoTrackOrder": "Drag files into correct track order",
+43 -7
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Dodaj", "ButtonAdd": "Dodaj",
"ButtonAddChapters": "Dodaj poglavlja", "ButtonAddChapters": "Dodaj poglavlja",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Dodaj podcaste", "ButtonAddPodcasts": "Dodaj podcaste",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Dodaj svoju prvu biblioteku", "ButtonAddYourFirstLibrary": "Dodaj svoju prvu biblioteku",
"ButtonApply": "Primijeni", "ButtonApply": "Primijeni",
"ButtonApplyChapters": "Primijeni poglavlja", "ButtonApplyChapters": "Primijeni poglavlja",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Ukloni seriju iz Nastavi seriju", "ButtonRemoveSeriesFromContinueSeries": "Ukloni seriju iz Nastavi seriju",
"ButtonReScan": "Skeniraj ponovno", "ButtonReScan": "Skeniraj ponovno",
"ButtonReset": "Poništi", "ButtonReset": "Poništi",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Povrati", "ButtonRestore": "Povrati",
"ButtonSave": "Spremi", "ButtonSave": "Spremi",
"ButtonSaveAndClose": "Spremi i zatvori", "ButtonSaveAndClose": "Spremi i zatvori",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise Notification Settings", "HeaderAppriseNotificationSettings": "Apprise Notification Settings",
"HeaderAudiobookTools": "Audiobook File Management alati", "HeaderAudiobookTools": "Audiobook File Management alati",
"HeaderAudioTracks": "Audio Tracks", "HeaderAudioTracks": "Audio Tracks",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Backups", "HeaderBackups": "Backups",
"HeaderChangePassword": "Promijeni lozinku", "HeaderChangePassword": "Promijeni lozinku",
"HeaderChapters": "Poglavlja", "HeaderChapters": "Poglavlja",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Manage Tags", "HeaderManageTags": "Manage Tags",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Map details",
"HeaderMatch": "Match", "HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metapodatci za ugradnju", "HeaderMetadataToEmbed": "Metapodatci za ugradnju",
"HeaderNewAccount": "Novi korisnički račun", "HeaderNewAccount": "Novi korisnički račun",
"HeaderNewLibrary": "Nova biblioteka", "HeaderNewLibrary": "Nova biblioteka",
"HeaderNotifications": "Obavijesti", "HeaderNotifications": "Obavijesti",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Otvori RSS Feed", "HeaderOpenRSSFeed": "Otvori RSS Feed",
"HeaderOtherFiles": "Druge datoteke", "HeaderOtherFiles": "Druge datoteke",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Dozvole", "HeaderPermissions": "Dozvole",
"HeaderPlayerQueue": "Player Queue", "HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Ukloni {0} epizoda/-e", "HeaderRemoveEpisodes": "Ukloni {0} epizoda/-e",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed je otvoren", "HeaderRSSFeedIsOpen": "RSS Feed je otvoren",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Spremljen Media Progress", "HeaderSavedMediaProgress": "Spremljen Media Progress",
"HeaderSchedule": "Schedule", "HeaderSchedule": "Schedule",
"HeaderScheduleLibraryScans": "Zakaži automatsko skeniranje biblioteke", "HeaderScheduleLibraryScans": "Zakaži automatsko skeniranje biblioteke",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Add {0} Books to Collection", "LabelAddToCollectionBatch": "Add {0} Books to Collection",
"LabelAddToPlaylist": "Add to Playlist", "LabelAddToPlaylist": "Add to Playlist",
"LabelAddToPlaylistBatch": "Add {0} Items to Playlist", "LabelAddToPlaylistBatch": "Add {0} Items to Playlist",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "All", "LabelAll": "All",
"LabelAllUsers": "Svi korisnici", "LabelAllUsers": "Svi korisnici",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Already in your library", "LabelAlreadyInYourLibrary": "Already in your library",
"LabelAppend": "Append", "LabelAppend": "Append",
"LabelAuthor": "Autor", "LabelAuthor": "Autor",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Author (Last, First)", "LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Autori", "LabelAuthors": "Autori",
"LabelAutoDownloadEpisodes": "Automatski preuzmi epizode", "LabelAutoDownloadEpisodes": "Automatski preuzmi epizode",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Nazad k korisniku", "LabelBackToUser": "Nazad k korisniku",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Uključi automatski backup", "LabelBackupsEnableAutomaticBackups": "Uključi automatski backup",
"LabelBackupsEnableAutomaticBackupsHelp": "Backups spremljeni u /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Backups spremljeni u /metadata/backups",
"LabelBackupsMaxBackupSize": "Maksimalna količina backupa (u GB)", "LabelBackupsMaxBackupSize": "Maksimalna količina backupa (u GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Samo 1 backup će biti odjednom obrisan. Ako koristite više njih, morati ćete ih ručno ukloniti.", "LabelBackupsNumberToKeepHelp": "Samo 1 backup će biti odjednom obrisan. Ako koristite više njih, morati ćete ih ručno ukloniti.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Knjige", "LabelBooks": "Knjige",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Promijeni lozinku", "LabelChangePassword": "Promijeni lozinku",
"LabelChannels": "Channels", "LabelChannels": "Channels",
"LabelChapters": "Chapters", "LabelChapters": "Chapters",
"LabelChaptersFound": "poglavlja pronađena", "LabelChaptersFound": "poglavlja pronađena",
"LabelChapterTitle": "Ime poglavlja", "LabelChapterTitle": "Ime poglavlja",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Close player", "LabelClosePlayer": "Close player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Collapse Series", "LabelCollapseSeries": "Collapse Series",
"LabelCollection": "Collection",
"LabelCollections": "Kolekcije", "LabelCollections": "Kolekcije",
"LabelComplete": "Complete", "LabelComplete": "Complete",
"LabelConfirmPassword": "Potvrdi lozinku", "LabelConfirmPassword": "Potvrdi lozinku",
@@ -215,13 +235,16 @@
"LabelCurrently": "Trenutno:", "LabelCurrently": "Trenutno:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Custom Cron Expression:",
"LabelDatetime": "Datetime", "LabelDatetime": "Datetime",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Opis", "LabelDescription": "Opis",
"LabelDeselectAll": "Odznači sve", "LabelDeselectAll": "Odznači sve",
"LabelDevice": "Uređaj", "LabelDevice": "Uređaj",
"LabelDeviceInfo": "O uređaju", "LabelDeviceInfo": "O uređaju",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Direktorij", "LabelDirectory": "Direktorij",
"LabelDiscFromFilename": "CD iz imena datoteke", "LabelDiscFromFilename": "CD iz imena datoteke",
"LabelDiscFromMetadata": "CD iz metapodataka", "LabelDiscFromMetadata": "CD iz metapodataka",
"LabelDiscover": "Discover",
"LabelDownload": "Preuzmi", "LabelDownload": "Preuzmi",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Trajanje", "LabelDuration": "Trajanje",
@@ -252,6 +275,7 @@
"LabelFinished": "Finished", "LabelFinished": "Finished",
"LabelFolder": "Folder", "LabelFolder": "Folder",
"LabelFolders": "Folderi", "LabelFolders": "Folderi",
"LabelFontFamily": "Font family",
"LabelFontScale": "Font scale", "LabelFontScale": "Font scale",
"LabelFormat": "Format", "LabelFormat": "Format",
"LabelGenre": "Genre", "LabelGenre": "Genre",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Obriši datoteku zauvijek", "LabelHardDeleteFile": "Obriši datoteku zauvijek",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Has ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Has supplementary ebook",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Sat", "LabelHour": "Sat",
"LabelIcon": "Ikona", "LabelIcon": "Ikona",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Dodaj u Tracklist", "LabelIncludeInTracklist": "Dodaj u Tracklist",
"LabelIncomplete": "Nepotpuno", "LabelIncomplete": "Nepotpuno",
"LabelInProgress": "U tijeku", "LabelInProgress": "U tijeku",
@@ -299,8 +325,12 @@
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn", "LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Traži nove epizode nakon ovog datuma", "LabelLookForNewEpisodesAfterDate": "Traži nove epizode nakon ovog datuma",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type", "LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Poslužitelj metapodataka ", "LabelMetadataProvider": "Poslužitelj metapodataka ",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Sezona", "LabelSeason": "Sezona",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Select all episodes",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Select {0} episodes showing",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSendEbookToDevice": "Send Ebook to...",
"LabelSequence": "Sekvenca", "LabelSequence": "Sekvenca",
"LabelSeries": "Serije", "LabelSeries": "Serije",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Isključi Watchera", "LabelSettingsDisableWatcher": "Isključi Watchera",
"LabelSettingsDisableWatcherForLibrary": "Isključi folder watchera za biblioteku", "LabelSettingsDisableWatcherForLibrary": "Isključi folder watchera za biblioteku",
"LabelSettingsDisableWatcherHelp": "Isključi automatsko dodavanje/aktualiziranje stavci ako su promjene prepoznate. *Potreban restart servera", "LabelSettingsDisableWatcherHelp": "Isključi automatsko dodavanje/aktualiziranje stavci ako su promjene prepoznate. *Potreban restart servera",
"LabelSettingsEnableWatcher": "Enable Watcher",
"LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
"LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Eksperimentalni features", "LabelSettingsExperimentalFeatures": "Eksperimentalni features",
"LabelSettingsExperimentalFeaturesHelp": "Features u razvoju trebaju vaš feedback i pomoć pri testiranju. Klikni da odeš to Github discussionsa.", "LabelSettingsExperimentalFeaturesHelp": "Features u razvoju trebaju vaš feedback i pomoć pri testiranju. Klikni da odeš to Github discussionsa.",
"LabelSettingsFindCovers": "Pronađi covers", "LabelSettingsFindCovers": "Pronađi covers",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.",
"LabelSettingsHomePageBookshelfView": "Koristi bookshelf pogled za početnu stranicu", "LabelSettingsHomePageBookshelfView": "Koristi bookshelf pogled za početnu stranicu",
"LabelSettingsLibraryBookshelfView": "Koristi bookshelf pogled za biblioteku", "LabelSettingsLibraryBookshelfView": "Koristi bookshelf pogled za biblioteku",
"LabelSettingsOverdriveMediaMarkers": "Koristi Overdrive Media Markers za poglavlja",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3 datoteke iz Overdriva dolaze sa vremenima od poglavlja embedani kao posebni metapodatci. Ova postavka će koristiti tagove za vremena od poglavlja automatski.",
"LabelSettingsParseSubtitles": "Parsaj podnapise", "LabelSettingsParseSubtitles": "Parsaj podnapise",
"LabelSettingsParseSubtitlesHelp": "Izvadi podnapise iz imena od audiobook foldera.<br>Podnapis mora biti odvojen sa \" - \"<br>npr. \"Ime knjige - Podnapis ovdje\" ima podnapis \"Podnapis ovdje\"", "LabelSettingsParseSubtitlesHelp": "Izvadi podnapise iz imena od audiobook foldera.<br>Podnapis mora biti odvojen sa \" - \"<br>npr. \"Ime knjige - Podnapis ovdje\" ima podnapis \"Podnapis ovdje\"",
"LabelSettingsPreferAudioMetadata": "Preferiraj audio metapodatke",
"LabelSettingsPreferAudioMetadataHelp": "Audio file ID3 meta tagovi u audio datoteci će biti korišteni za detalje knjige.",
"LabelSettingsPreferMatchedMetadata": "Preferiraj matchane metapodatke", "LabelSettingsPreferMatchedMetadata": "Preferiraj matchane metapodatke",
"LabelSettingsPreferMatchedMetadataHelp": "Matchani podatci će biti korišteni kada se koristi Quick Match. Po defaultu Quick Match će ispuniti samo prazne detalje.", "LabelSettingsPreferMatchedMetadataHelp": "Matchani podatci će biti korišteni kada se koristi Quick Match. Po defaultu Quick Match će ispuniti samo prazne detalje.",
"LabelSettingsPreferOPFMetadata": "Preferiraj OPF metapodatke",
"LabelSettingsPreferOPFMetadataHelp": "OPF metapodatci datoteke će biti korišteni za detalje knjige.",
"LabelSettingsSkipMatchingBooksWithASIN": "Preskoči matchanje knjiga koje već imaju ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Preskoči matchanje knjiga koje već imaju ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "SPreskoči matchanje knjiga koje već imaju ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "SPreskoči matchanje knjiga koje već imaju ISBN",
"LabelSettingsSortingIgnorePrefixes": "Zanemari prefikse tokom sortiranja", "LabelSettingsSortingIgnorePrefixes": "Zanemari prefikse tokom sortiranja",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Spremi cover uz stakvu", "LabelSettingsStoreCoversWithItem": "Spremi cover uz stakvu",
"LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept", "LabelSettingsStoreCoversWithItemHelp": "By default covers are stored in /metadata/items, enabling this setting will store covers in your library item folder. Only one file named \"cover\" will be kept",
"LabelSettingsStoreMetadataWithItem": "Spremi metapodatke uz stavku", "LabelSettingsStoreMetadataWithItem": "Spremi metapodatke uz stavku",
"LabelSettingsStoreMetadataWithItemHelp": "Po defaultu metapodatci su spremljeni u /metadata/items, uključujućite li ovu postavku, metapodatci će biti spremljeni u folderima od biblioteke. Koristi .abs ekstenziju.", "LabelSettingsStoreMetadataWithItemHelp": "Po defaultu metapodatci su spremljeni u /metadata/items, uključujućite li ovu postavku, metapodatci će biti spremljeni u folderima od biblioteke",
"LabelSettingsTimeFormat": "Time Format", "LabelSettingsTimeFormat": "Time Format",
"LabelShowAll": "Prikaži sve", "LabelShowAll": "Prikaži sve",
"LabelSize": "Veličina", "LabelSize": "Veličina",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSlug": "Slug",
"LabelStart": "Pokreni", "LabelStart": "Pokreni",
"LabelStarted": "Pokrenuto", "LabelStarted": "Pokrenuto",
"LabelStartedAt": "Pokrenuto", "LabelStartedAt": "Pokrenuto",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Track iz metapodataka", "LabelTrackFromMetadata": "Track iz metapodataka",
"LabelTracks": "Tracks", "LabelTracks": "Tracks",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Single-track", "LabelTracksSingleTrack": "Single-track",
"LabelType": "Tip", "LabelType": "Tip",
"LabelUnabridged": "Unabridged", "LabelUnabridged": "Unabridged",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time", "MessageChapterErrorStartLtPrev": "Invalid start time must be greater than or equal to previous chapter start time",
"MessageChapterStartIsAfter": "Početak poglavlja je nakon kraja audioknjige.", "MessageChapterStartIsAfter": "Početak poglavlja je nakon kraja audioknjige.",
"MessageCheckingCron": "Provjeravam cron...", "MessageCheckingCron": "Provjeravam cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Jeste li sigurni da želite obrisati backup za {0}?", "MessageConfirmDeleteBackup": "Jeste li sigurni da želite obrisati backup za {0}?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?",
"MessageConfirmDeleteLibrary": "Jeste li sigurni da želite trajno obrisati biblioteku \"{0}\"?", "MessageConfirmDeleteLibrary": "Jeste li sigurni da želite trajno obrisati biblioteku \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Jeste li sigurni da želite obrisati ovu sesiju?", "MessageConfirmDeleteSession": "Jeste li sigurni da želite obrisati ovu sesiju?",
"MessageConfirmForceReScan": "Jeste li sigurni da želite ponovno skenirati?", "MessageConfirmForceReScan": "Jeste li sigurni da želite ponovno skenirati?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?",
"MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?", "MessageConfirmMarkSeriesFinished": "Are you sure you want to mark all books in this series as finished?",
"MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?", "MessageConfirmMarkSeriesNotFinished": "Are you sure you want to mark all books in this series as not finished?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?", "MessageConfirmRemoveAllChapters": "Are you sure you want to remove all chapters?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "AJeste li sigurni da želite obrisati kolekciju \"{0}\"?", "MessageConfirmRemoveCollection": "AJeste li sigurni da želite obrisati kolekciju \"{0}\"?",
"MessageConfirmRemoveEpisode": "Jeste li sigurni da želite obrisati epizodu \"{0}\"?", "MessageConfirmRemoveEpisode": "Jeste li sigurni da želite obrisati epizodu \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Jeste li sigurni da želite obrisati {0} epizoda/-u?", "MessageConfirmRemoveEpisodes": "Jeste li sigurni da želite obrisati {0} epizoda/-u?",
@@ -535,6 +570,7 @@
"MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?", "MessageConfirmRenameTag": "Are you sure you want to rename tag \"{0}\" to \"{1}\" for all items?",
"MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.", "MessageConfirmRenameTagMergeNote": "Note: This tag already exists so they will be merged.",
"MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".", "MessageConfirmRenameTagWarning": "Warning! A similar tag with a different casing already exists \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?",
"MessageDownloadingEpisode": "Preuzimam epizodu", "MessageDownloadingEpisode": "Preuzimam epizodu",
"MessageDragFilesIntoTrackOrder": "Povuci datoteke u pravilan redoslijed tracka.", "MessageDragFilesIntoTrackOrder": "Povuci datoteke u pravilan redoslijed tracka.",
+58 -22
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Aggiungi", "ButtonAdd": "Aggiungi",
"ButtonAddChapters": "Aggiungi Capitoli", "ButtonAddChapters": "Aggiungi Capitoli",
"ButtonAddDevice": "Aggiungi Dispositivo",
"ButtonAddLibrary": "Aggiungi Libreria",
"ButtonAddPodcasts": "Aggiungi Podcast", "ButtonAddPodcasts": "Aggiungi Podcast",
"ButtonAddUser": "Aggiungi User",
"ButtonAddYourFirstLibrary": "Aggiungi la tua prima libreria", "ButtonAddYourFirstLibrary": "Aggiungi la tua prima libreria",
"ButtonApply": "Applica", "ButtonApply": "Applica",
"ButtonApplyChapters": "Applica", "ButtonApplyChapters": "Applica",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Rimuovi la Serie per Continuarla", "ButtonRemoveSeriesFromContinueSeries": "Rimuovi la Serie per Continuarla",
"ButtonReScan": "Ri-scansiona", "ButtonReScan": "Ri-scansiona",
"ButtonReset": "Reset", "ButtonReset": "Reset",
"ButtonResetToDefault": "Ripristino di default",
"ButtonRestore": "Ripristina", "ButtonRestore": "Ripristina",
"ButtonSave": "Salva", "ButtonSave": "Salva",
"ButtonSaveAndClose": "Salva & Chiudi", "ButtonSaveAndClose": "Salva & Chiudi",
@@ -71,7 +75,7 @@
"ButtonSetChaptersFromTracks": "Impostare i capitoli dalle tracce", "ButtonSetChaptersFromTracks": "Impostare i capitoli dalle tracce",
"ButtonShiftTimes": "Ricerca veloce", "ButtonShiftTimes": "Ricerca veloce",
"ButtonShow": "Mostra", "ButtonShow": "Mostra",
"ButtonStartM4BEncode": "Inizia L'Encoda del M4B", "ButtonStartM4BEncode": "Inizia L'Encode del M4B",
"ButtonStartMetadataEmbed": "Inizia Incorporo Metadata", "ButtonStartMetadataEmbed": "Inizia Incorporo Metadata",
"ButtonSubmit": "Invia", "ButtonSubmit": "Invia",
"ButtonTest": "Test", "ButtonTest": "Test",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprendi le impostazioni di Notifica", "HeaderAppriseNotificationSettings": "Apprendi le impostazioni di Notifica",
"HeaderAudiobookTools": "Utilità Audiobook File Management", "HeaderAudiobookTools": "Utilità Audiobook File Management",
"HeaderAudioTracks": "Tracce Audio", "HeaderAudioTracks": "Tracce Audio",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Backup", "HeaderBackups": "Backup",
"HeaderChangePassword": "Cambia Password", "HeaderChangePassword": "Cambia Password",
"HeaderChapters": "Capitoli", "HeaderChapters": "Capitoli",
@@ -98,7 +103,7 @@
"HeaderCurrentDownloads": "Download Correnti", "HeaderCurrentDownloads": "Download Correnti",
"HeaderDetails": "Dettagli", "HeaderDetails": "Dettagli",
"HeaderDownloadQueue": "Download Queue", "HeaderDownloadQueue": "Download Queue",
"HeaderEbookFiles": "Ebook Files", "HeaderEbookFiles": "Ebook File",
"HeaderEmail": "Email", "HeaderEmail": "Email",
"HeaderEmailSettings": "Email Settings", "HeaderEmailSettings": "Email Settings",
"HeaderEpisodes": "Episodi", "HeaderEpisodes": "Episodi",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Gestisci Tags", "HeaderManageTags": "Gestisci Tags",
"HeaderMapDetails": "Mappa Dettagli", "HeaderMapDetails": "Mappa Dettagli",
"HeaderMatch": "Trova Corrispondenza", "HeaderMatch": "Trova Corrispondenza",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metadata da incorporare", "HeaderMetadataToEmbed": "Metadata da incorporare",
"HeaderNewAccount": "Nuovo Account", "HeaderNewAccount": "Nuovo Account",
"HeaderNewLibrary": "Nuova Libreria", "HeaderNewLibrary": "Nuova Libreria",
"HeaderNotifications": "Notifiche", "HeaderNotifications": "Notifiche",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Apri RSS Feed", "HeaderOpenRSSFeed": "Apri RSS Feed",
"HeaderOtherFiles": "Altri File", "HeaderOtherFiles": "Altri File",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permessi", "HeaderPermissions": "Permessi",
"HeaderPlayerQueue": "Coda Riproduzione", "HeaderPlayerQueue": "Coda Riproduzione",
"HeaderPlaylist": "Playlist", "HeaderPlaylist": "Playlist",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Rimuovi {0} Episodi", "HeaderRemoveEpisodes": "Rimuovi {0} Episodi",
"HeaderRSSFeedGeneral": "RSS Details", "HeaderRSSFeedGeneral": "RSS Details",
"HeaderRSSFeedIsOpen": "RSS Feed è aperto", "HeaderRSSFeedIsOpen": "RSS Feed è aperto",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Progressi salvati", "HeaderSavedMediaProgress": "Progressi salvati",
"HeaderSchedule": "Schedula", "HeaderSchedule": "Schedula",
"HeaderScheduleLibraryScans": "Schedula la scansione della libreria", "HeaderScheduleLibraryScans": "Schedula la scansione della libreria",
@@ -155,7 +164,7 @@
"HeaderStatsRecentSessions": "Sessioni Recenti", "HeaderStatsRecentSessions": "Sessioni Recenti",
"HeaderStatsTop10Authors": "Top 10 Autori", "HeaderStatsTop10Authors": "Top 10 Autori",
"HeaderStatsTop5Genres": "Top 5 Generi", "HeaderStatsTop5Genres": "Top 5 Generi",
"HeaderTableOfContents": "Tabellla dei Contenuti", "HeaderTableOfContents": "Tabella dei Contenuti",
"HeaderTools": "Strumenti", "HeaderTools": "Strumenti",
"HeaderUpdateAccount": "Aggiorna Account", "HeaderUpdateAccount": "Aggiorna Account",
"HeaderUpdateAuthor": "Aggiorna Autore", "HeaderUpdateAuthor": "Aggiorna Autore",
@@ -175,8 +184,11 @@
"LabelAddToCollectionBatch": "Aggiungi {0} Libri alla Raccolta", "LabelAddToCollectionBatch": "Aggiungi {0} Libri alla Raccolta",
"LabelAddToPlaylist": "aggiungi alla Playlist", "LabelAddToPlaylist": "aggiungi alla Playlist",
"LabelAddToPlaylistBatch": "Aggiungi {0} file alla Playlist", "LabelAddToPlaylistBatch": "Aggiungi {0} file alla Playlist",
"LabelAdminUsersOnly": "Solo utenti Amministratori",
"LabelAll": "Tutti", "LabelAll": "Tutti",
"LabelAllUsers": "Tutti gli Utenti", "LabelAllUsers": "Tutti gli Utenti",
"LabelAllUsersExcludingGuests": "Tutti gli Utenti Esclusi gli ospiti",
"LabelAllUsersIncludingGuests": "Tutti gli Utenti Inclusi gli ospiti",
"LabelAlreadyInYourLibrary": "Già esistente nella libreria", "LabelAlreadyInYourLibrary": "Già esistente nella libreria",
"LabelAppend": "Appese", "LabelAppend": "Appese",
"LabelAuthor": "Autore", "LabelAuthor": "Autore",
@@ -184,7 +196,12 @@
"LabelAuthorLastFirst": "Autori (Per Cognome)", "LabelAuthorLastFirst": "Autori (Per Cognome)",
"LabelAuthors": "Autori", "LabelAuthors": "Autori",
"LabelAutoDownloadEpisodes": "Auto Download Episodi", "LabelAutoDownloadEpisodes": "Auto Download Episodi",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Torna a Utenti", "LabelBackToUser": "Torna a Utenti",
"LabelBackupLocation": "Percorso del Backup",
"LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico", "LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico",
"LabelBackupsEnableAutomaticBackupsHelp": "I Backup saranno salvati in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "I Backup saranno salvati in /metadata/backups",
"LabelBackupsMaxBackupSize": "Dimensione massima backup (in GB)", "LabelBackupsMaxBackupSize": "Dimensione massima backup (in GB)",
@@ -193,14 +210,17 @@
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.", "LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Libri", "LabelBooks": "Libri",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Cambia Password", "LabelChangePassword": "Cambia Password",
"LabelChannels": "Canali", "LabelChannels": "Canali",
"LabelChapters": "Capitoli", "LabelChapters": "Capitoli",
"LabelChaptersFound": "Capitoli Trovati", "LabelChaptersFound": "Capitoli Trovati",
"LabelChapterTitle": "Titoli dei Capitoli", "LabelChapterTitle": "Titoli dei Capitoli",
"LabelClickForMoreInfo": "Click per altre Info",
"LabelClosePlayer": "Chiudi player", "LabelClosePlayer": "Chiudi player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Comprimi Serie", "LabelCollapseSeries": "Comprimi Serie",
"LabelCollection": "Raccolta",
"LabelCollections": "Raccolte", "LabelCollections": "Raccolte",
"LabelComplete": "Completo", "LabelComplete": "Completo",
"LabelConfirmPassword": "Conferma Password", "LabelConfirmPassword": "Conferma Password",
@@ -208,20 +228,23 @@
"LabelContinueReading": "Continua la Lettura", "LabelContinueReading": "Continua la Lettura",
"LabelContinueSeries": "Continua Serie", "LabelContinueSeries": "Continua Serie",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Cover Image URL", "LabelCoverImageURL": "Indirizzo della cover URL",
"LabelCreatedAt": "Creato A", "LabelCreatedAt": "Creato A",
"LabelCronExpression": "Espressione Cron", "LabelCronExpression": "Espressione Cron",
"LabelCurrent": "Attuale", "LabelCurrent": "Attuale",
"LabelCurrently": "Attualmente:", "LabelCurrently": "Attualmente:",
"LabelCustomCronExpression": "Custom Cron Expression:", "LabelCustomCronExpression": "Espressione Cron personalizzata:",
"LabelDatetime": "Data & Ora", "LabelDatetime": "Data & Ora",
"LabelDeleteFromFileSystemCheckbox": "Elimina dal file system (togli la spunta per eliminarla solo dal DB)",
"LabelDescription": "Descrizione", "LabelDescription": "Descrizione",
"LabelDeselectAll": "Deseleziona Tutto", "LabelDeselectAll": "Deseleziona Tutto",
"LabelDevice": "Dispositivo", "LabelDevice": "Dispositivo",
"LabelDeviceInfo": "Info Dispositivo", "LabelDeviceInfo": "Info Dispositivo",
"LabelDeviceIsAvailableTo": "Il dispositivo e disponibile su...",
"LabelDirectory": "Elenco", "LabelDirectory": "Elenco",
"LabelDiscFromFilename": "Disco dal nome file", "LabelDiscFromFilename": "Disco dal nome file",
"LabelDiscFromMetadata": "Disco dal Metadata", "LabelDiscFromMetadata": "Disco dal Metadata",
"LabelDiscover": "Scopri",
"LabelDownload": "Download", "LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Durata", "LabelDuration": "Durata",
@@ -252,6 +275,7 @@
"LabelFinished": "Finita", "LabelFinished": "Finita",
"LabelFolder": "Cartella", "LabelFolder": "Cartella",
"LabelFolders": "Cartelle", "LabelFolders": "Cartelle",
"LabelFontFamily": "Font family",
"LabelFontScale": "Dimensione Font", "LabelFontScale": "Dimensione Font",
"LabelFormat": "Formato", "LabelFormat": "Formato",
"LabelGenre": "Genere", "LabelGenre": "Genere",
@@ -259,9 +283,11 @@
"LabelHardDeleteFile": "Elimina Definitivamente", "LabelHardDeleteFile": "Elimina Definitivamente",
"LabelHasEbook": "Un ebook", "LabelHasEbook": "Un ebook",
"LabelHasSupplementaryEbook": "Un ebook Supplementare", "LabelHasSupplementaryEbook": "Un ebook Supplementare",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Ora", "LabelHour": "Ora",
"LabelIcon": "Icona", "LabelIcon": "Icona",
"LabelImageURLFromTheWeb": "Immagine URL da internet",
"LabelIncludeInTracklist": "Includi nella Tracklist", "LabelIncludeInTracklist": "Includi nella Tracklist",
"LabelIncomplete": "Incompleta", "LabelIncomplete": "Incompleta",
"LabelInProgress": "In Corso", "LabelInProgress": "In Corso",
@@ -286,21 +312,25 @@
"LabelLastUpdate": "Ultimo Aggiornamento", "LabelLastUpdate": "Ultimo Aggiornamento",
"LabelLayout": "Layout", "LabelLayout": "Layout",
"LabelLayoutSinglePage": "Pagina Singola", "LabelLayoutSinglePage": "Pagina Singola",
"LabelLayoutSplitPage": "DIvidi Pagina", "LabelLayoutSplitPage": "Dividi Pagina",
"LabelLess": "Poco", "LabelLess": "Poco",
"LabelLibrariesAccessibleToUser": "Librerie Accessibili agli Utenti", "LabelLibrariesAccessibleToUser": "Librerie Accessibili agli Utenti",
"LabelLibrary": "Libreria", "LabelLibrary": "Libreria",
"LabelLibraryItem": "Elementi della Library", "LabelLibraryItem": "Elementi della Library",
"LabelLibraryName": "Nome Libreria", "LabelLibraryName": "Nome Libreria",
"LabelLimit": "Limiti", "LabelLimit": "Limiti",
"LabelLineSpacing": "Line spacing", "LabelLineSpacing": "Interlinea",
"LabelListenAgain": "Ri-ascolta", "LabelListenAgain": "Ri-ascolta",
"LabelLogLevelDebug": "Debug", "LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Allarme", "LabelLogLevelWarn": "Allarme",
"LabelLookForNewEpisodesAfterDate": "Cerca nuovi episodi dopo questa data", "LabelLookForNewEpisodesAfterDate": "Cerca nuovi episodi dopo questa data",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player", "LabelMediaPlayer": "Media Player",
"LabelMediaType": "Tipo Media", "LabelMediaType": "Tipo Media",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadata Provider", "LabelMetadataProvider": "Metadata Provider",
"LabelMetaTag": "Meta Tag", "LabelMetaTag": "Meta Tag",
"LabelMetaTags": "Meta Tags", "LabelMetaTags": "Meta Tags",
@@ -380,6 +410,7 @@
"LabelSeason": "Stagione", "LabelSeason": "Stagione",
"LabelSelectAllEpisodes": "Seleziona tutti gli Episodi", "LabelSelectAllEpisodes": "Seleziona tutti gli Episodi",
"LabelSelectEpisodesShowing": "Episodi {0} selezionati ", "LabelSelectEpisodesShowing": "Episodi {0} selezionati ",
"LabelSelectUsers": "Selezione Utenti",
"LabelSendEbookToDevice": "Invia ebook a...", "LabelSendEbookToDevice": "Invia ebook a...",
"LabelSequence": "Sequenza", "LabelSequence": "Sequenza",
"LabelSeries": "Serie", "LabelSeries": "Serie",
@@ -395,6 +426,9 @@
"LabelSettingsDisableWatcher": "Disattiva Watcher", "LabelSettingsDisableWatcher": "Disattiva Watcher",
"LabelSettingsDisableWatcherForLibrary": "Disattiva Watcher per le librerie", "LabelSettingsDisableWatcherForLibrary": "Disattiva Watcher per le librerie",
"LabelSettingsDisableWatcherHelp": "Disattiva il controllo automatico libri nelle cartelle delle librerie. *Richiede il Riavvio del Server", "LabelSettingsDisableWatcherHelp": "Disattiva il controllo automatico libri nelle cartelle delle librerie. *Richiede il Riavvio del Server",
"LabelSettingsEnableWatcher": "Abilita Watcher",
"LabelSettingsEnableWatcherForLibrary": "Abilita il controllo cartelle per la libreria",
"LabelSettingsEnableWatcherHelp": "Abilita l'aggiunta/aggiornamento automatico degli elementi quando vengono rilevate modifiche ai file. *Richiede il riavvio del Server",
"LabelSettingsExperimentalFeatures": "Opzioni Sperimentali", "LabelSettingsExperimentalFeatures": "Opzioni Sperimentali",
"LabelSettingsExperimentalFeaturesHelp": "Funzionalità in fase di sviluppo che potrebbero utilizzare i tuoi feedback e aiutare i test. Fare clic per aprire la discussione github.", "LabelSettingsExperimentalFeaturesHelp": "Funzionalità in fase di sviluppo che potrebbero utilizzare i tuoi feedback e aiutare i test. Fare clic per aprire la discussione github.",
"LabelSettingsFindCovers": "Trova covers", "LabelSettingsFindCovers": "Trova covers",
@@ -403,16 +437,10 @@
"LabelSettingsHideSingleBookSeriesHelp": "Le serie che hanno un solo libro saranno nascoste dalla pagina della serie e dagli scaffali della home page.", "LabelSettingsHideSingleBookSeriesHelp": "Le serie che hanno un solo libro saranno nascoste dalla pagina della serie e dagli scaffali della home page.",
"LabelSettingsHomePageBookshelfView": "Home page con sfondo legno", "LabelSettingsHomePageBookshelfView": "Home page con sfondo legno",
"LabelSettingsLibraryBookshelfView": "Libreria con sfondo legno", "LabelSettingsLibraryBookshelfView": "Libreria con sfondo legno",
"LabelSettingsOverdriveMediaMarkers": "Usa Overdrive Media Markers per i capitoli",
"LabelSettingsOverdriveMediaMarkersHelp": "I file MP3 di Overdrive vengono forniti con i tempi dei capitoli incorporati come metadati personalizzati. Abilitando questa funzione verranno utilizzati automaticamente questi tag per i tempi dei capitoli",
"LabelSettingsParseSubtitles": "Analizza sottotitoli", "LabelSettingsParseSubtitles": "Analizza sottotitoli",
"LabelSettingsParseSubtitlesHelp": "Estrai i sottotitoli dai nomi delle cartelle degli audiolibri. <br> I sottotitoli devono essere separati da \" - \"<br> Per esempio \"Il signore degli anelli - Le due Torri \" avrà il sottotitolo \"Le due Torri\"", "LabelSettingsParseSubtitlesHelp": "Estrai i sottotitoli dai nomi delle cartelle degli audiolibri. <br> I sottotitoli devono essere separati da \" - \"<br> Per esempio \"Il signore degli anelli - Le due Torri \" avrà il sottotitolo \"Le due Torri\"",
"LabelSettingsPreferAudioMetadata": "Preferisci i metadati audio",
"LabelSettingsPreferAudioMetadataHelp": "I meta tag ID3 del file audio verrano preferiti rispetto al nome della cartella",
"LabelSettingsPreferMatchedMetadata": "Preferisci i metadata trovati", "LabelSettingsPreferMatchedMetadata": "Preferisci i metadata trovati",
"LabelSettingsPreferMatchedMetadataHelp": "I dati trovati in internet sovrascriveranno i dettagli del libro quando si utilizza quick Match. Per impostazione predefinita, Quick Match riempirà solo i dettagli mancanti.", "LabelSettingsPreferMatchedMetadataHelp": "I dati trovati in internet sovrascriveranno i dettagli del libro quando si utilizza quick Match. Per impostazione predefinita, Quick Match riempirà solo i dettagli mancanti.",
"LabelSettingsPreferOPFMetadata": "Preferisci OPF metadata",
"LabelSettingsPreferOPFMetadataHelp": "I metadati del file OPF verranno utilizzati per i dettagli del libro e non il nome della cartella",
"LabelSettingsSkipMatchingBooksWithASIN": "Salta la ricerca dati in internet se è già presente un codice ASIN", "LabelSettingsSkipMatchingBooksWithASIN": "Salta la ricerca dati in internet se è già presente un codice ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Salta la ricerca dati in internet se è già presente un codice ISBN", "LabelSettingsSkipMatchingBooksWithISBN": "Salta la ricerca dati in internet se è già presente un codice ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignora i prefissi nei titoli durante l'aggiunta", "LabelSettingsSortingIgnorePrefixes": "Ignora i prefissi nei titoli durante l'aggiunta",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Archivia le copertine con il file", "LabelSettingsStoreCoversWithItem": "Archivia le copertine con il file",
"LabelSettingsStoreCoversWithItemHelp": "Di default, le immagini di copertina sono salvate dentro /metadata/items, abilitando questa opzione le copertine saranno archiviate nella cartella della libreria corrispondente. Verrà conservato solo un file denominato \"cover\"", "LabelSettingsStoreCoversWithItemHelp": "Di default, le immagini di copertina sono salvate dentro /metadata/items, abilitando questa opzione le copertine saranno archiviate nella cartella della libreria corrispondente. Verrà conservato solo un file denominato \"cover\"",
"LabelSettingsStoreMetadataWithItem": "Archivia i metadata con il file", "LabelSettingsStoreMetadataWithItem": "Archivia i metadata con il file",
"LabelSettingsStoreMetadataWithItemHelp": "Di default, i metadati sono salvati dentro /metadata/items, abilitando questa opzione si memorizzeranno i metadata nella cartella della libreria. I file avranno estensione .abs", "LabelSettingsStoreMetadataWithItemHelp": "Di default, i metadati sono salvati dentro /metadata/items, abilitando questa opzione si memorizzeranno i metadata nella cartella della libreria",
"LabelSettingsTimeFormat": "Formato Ora", "LabelSettingsTimeFormat": "Formato Ora",
"LabelShowAll": "Mostra Tutto", "LabelShowAll": "Mostra Tutto",
"LabelSize": "Dimensione", "LabelSize": "Dimensione",
"LabelSleepTimer": "Sleep timer", "LabelSleepTimer": "Sleep timer",
"LabelSlug": "Slug",
"LabelStart": "Inizo", "LabelStart": "Inizo",
"LabelStarted": "Iniziato", "LabelStarted": "Iniziato",
"LabelStartedAt": "Iniziato al", "LabelStartedAt": "Iniziato al",
@@ -454,8 +483,8 @@
"LabelTagsNotAccessibleToUser": "Tags non accessibile agli Utenti", "LabelTagsNotAccessibleToUser": "Tags non accessibile agli Utenti",
"LabelTasks": "Processi in esecuzione", "LabelTasks": "Processi in esecuzione",
"LabelTheme": "Tema", "LabelTheme": "Tema",
"LabelThemeDark": "Dark", "LabelThemeDark": "Scuro",
"LabelThemeLight": "Light", "LabelThemeLight": "Chiaro",
"LabelTimeBase": "Time Base", "LabelTimeBase": "Time Base",
"LabelTimeListened": "Tempo di Ascolto", "LabelTimeListened": "Tempo di Ascolto",
"LabelTimeListenedToday": "Tempo di Ascolto Oggi", "LabelTimeListenedToday": "Tempo di Ascolto Oggi",
@@ -474,6 +503,7 @@
"LabelTrackFromMetadata": "Traccia da Metadata", "LabelTrackFromMetadata": "Traccia da Metadata",
"LabelTracks": "Traccia", "LabelTracks": "Traccia",
"LabelTracksMultiTrack": "Multi-traccia", "LabelTracksMultiTrack": "Multi-traccia",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Traccia-singola", "LabelTracksSingleTrack": "Traccia-singola",
"LabelType": "Tipo", "LabelType": "Tipo",
"LabelUnabridged": "Integrale", "LabelUnabridged": "Integrale",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "L'ora di inizio non valida deve essere maggiore o uguale all'ora di inizio del capitolo precedente", "MessageChapterErrorStartLtPrev": "L'ora di inizio non valida deve essere maggiore o uguale all'ora di inizio del capitolo precedente",
"MessageChapterStartIsAfter": "L'inizio del capitolo è dopo la fine del tuo audiolibro", "MessageChapterStartIsAfter": "L'inizio del capitolo è dopo la fine del tuo audiolibro",
"MessageCheckingCron": "Controllo cron...", "MessageCheckingCron": "Controllo cron...",
"MessageConfirmCloseFeed": "Sei sicuro di voler chiudere questo feed?",
"MessageConfirmDeleteBackup": "Sei sicuro di voler eliminare il backup {0}?", "MessageConfirmDeleteBackup": "Sei sicuro di voler eliminare il backup {0}?",
"MessageConfirmDeleteFile": "Questo eliminerà il file dal tuo file system. Sei sicuro?", "MessageConfirmDeleteFile": "Questo eliminerà il file dal tuo file system. Sei sicuro?",
"MessageConfirmDeleteLibrary": "Sei sicuro di voler eliminare definitivamente la libreria \"{0}\"?", "MessageConfirmDeleteLibrary": "Sei sicuro di voler eliminare definitivamente la libreria \"{0}\"?",
"MessageConfirmDeleteLibraryItem": " l'elemento della libreria dal database e dal file system. Sei sicuro?",
"MessageConfirmDeleteLibraryItems": "Ciò eliminerà {0} elementi della libreria dal database e dal file system. Sei sicuro?",
"MessageConfirmDeleteSession": "Sei sicuro di voler eliminare questa sessione?", "MessageConfirmDeleteSession": "Sei sicuro di voler eliminare questa sessione?",
"MessageConfirmForceReScan": "Sei sicuro di voler forzare una nuova scansione?", "MessageConfirmForceReScan": "Sei sicuro di voler forzare una nuova scansione?",
"MessageConfirmMarkAllEpisodesFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come finiti?", "MessageConfirmMarkAllEpisodesFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come finiti?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Sei sicuro di voler contrassegnare tutti gli episodi come non completati?",
"MessageConfirmMarkSeriesFinished": "Sei sicuro di voler contrassegnare tutti i libri di questa serie come completati?", "MessageConfirmMarkSeriesFinished": "Sei sicuro di voler contrassegnare tutti i libri di questa serie come completati?",
"MessageConfirmMarkSeriesNotFinished": "Sei sicuro di voler contrassegnare tutti i libri di questa serie come non completati?", "MessageConfirmMarkSeriesNotFinished": "Sei sicuro di voler contrassegnare tutti i libri di questa serie come non completati?",
"MessageConfirmQuickEmbed": "Attenzione! L'incorporamento rapido non eseguirà il backup dei file audio. Assicurati di avere un backup dei tuoi file audio. <br><br>Vuoi Continuare?",
"MessageConfirmRemoveAllChapters": "Sei sicuro di voler rimuovere tutti i capitoli?", "MessageConfirmRemoveAllChapters": "Sei sicuro di voler rimuovere tutti i capitoli?",
"MessageConfirmRemoveAuthor": "Sei sicuro di voler rimuovere l'autore? \"{0}\"?",
"MessageConfirmRemoveCollection": "Sei sicuro di voler rimuovere la Raccolta \"{0}\"?", "MessageConfirmRemoveCollection": "Sei sicuro di voler rimuovere la Raccolta \"{0}\"?",
"MessageConfirmRemoveEpisode": "Sei sicuro di voler rimuovere l'episodio \"{0}\"?", "MessageConfirmRemoveEpisode": "Sei sicuro di voler rimuovere l'episodio \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Sei sicuro di voler rimuovere {0} episodi?", "MessageConfirmRemoveEpisodes": "Sei sicuro di voler rimuovere {0} episodi?",
@@ -535,6 +570,7 @@
"MessageConfirmRenameTag": "Sei sicuro di voler rinominare il tag \"{0}\" in \"{1}\" per tutti gli oggetti?", "MessageConfirmRenameTag": "Sei sicuro di voler rinominare il tag \"{0}\" in \"{1}\" per tutti gli oggetti?",
"MessageConfirmRenameTagMergeNote": "Nota: Questo tag esiste già e verrà unito nel vecchio.", "MessageConfirmRenameTagMergeNote": "Nota: Questo tag esiste già e verrà unito nel vecchio.",
"MessageConfirmRenameTagWarning": "Avvertimento! Esiste già un tag simile con un nome simile \"{0}\".", "MessageConfirmRenameTagWarning": "Avvertimento! Esiste già un tag simile con un nome simile \"{0}\".",
"MessageConfirmReScanLibraryItems": "Sei sicuro di voler ripetere la scansione? {0} oggetti?",
"MessageConfirmSendEbookToDevice": "Sei sicuro di voler inviare {0} ebook \"{1}\" al Device \"{2}\"?", "MessageConfirmSendEbookToDevice": "Sei sicuro di voler inviare {0} ebook \"{1}\" al Device \"{2}\"?",
"MessageDownloadingEpisode": "Download episodio in corso", "MessageDownloadingEpisode": "Download episodio in corso",
"MessageDragFilesIntoTrackOrder": "Trascina i file nell'ordine di traccia corretto", "MessageDragFilesIntoTrackOrder": "Trascina i file nell'ordine di traccia corretto",
@@ -584,7 +620,7 @@
"MessageNoResults": "Nessun Risultato", "MessageNoResults": "Nessun Risultato",
"MessageNoSearchResultsFor": "Nessun risultato per \"{0}\"", "MessageNoSearchResultsFor": "Nessun risultato per \"{0}\"",
"MessageNoSeries": "Nessuna Serie", "MessageNoSeries": "Nessuna Serie",
"MessageNoTags": "No Tags", "MessageNoTags": "Nessun Tags",
"MessageNoTasksRunning": "Nessun processo in esecuzione", "MessageNoTasksRunning": "Nessun processo in esecuzione",
"MessageNotYetImplemented": "Non Ancora Implementato", "MessageNotYetImplemented": "Non Ancora Implementato",
"MessageNoUpdateNecessary": "Nessun aggiornamento necessario", "MessageNoUpdateNecessary": "Nessun aggiornamento necessario",
@@ -613,7 +649,7 @@
"MessageUploaderItemSuccess": "Caricato con successo!", "MessageUploaderItemSuccess": "Caricato con successo!",
"MessageUploading": "Caricamento...", "MessageUploading": "Caricamento...",
"MessageValidCronExpression": "Espressione Cron Valida", "MessageValidCronExpression": "Espressione Cron Valida",
"MessageWatcherIsDisabledGlobally": "Watcher è disabilitato a livello globale nelle impostazioni del server", "MessageWatcherIsDisabledGlobally": "Controllo file automatico è disabilitato a livello globale nelle impostazioni del server",
"MessageXLibraryIsEmpty": "{0} libreria vuota!", "MessageXLibraryIsEmpty": "{0} libreria vuota!",
"MessageYourAudiobookDurationIsLonger": "La durata dell'audiolibro è più lunga della durata trovata", "MessageYourAudiobookDurationIsLonger": "La durata dell'audiolibro è più lunga della durata trovata",
"MessageYourAudiobookDurationIsShorter": "La durata dell'audiolibro è inferiore alla durata trovata", "MessageYourAudiobookDurationIsShorter": "La durata dell'audiolibro è inferiore alla durata trovata",
@@ -627,7 +663,7 @@
"NoteUploaderOnlyAudioFiles": "Se carichi solo file audio, ogni file audio verrà gestito come un audiolibro separato.", "NoteUploaderOnlyAudioFiles": "Se carichi solo file audio, ogni file audio verrà gestito come un audiolibro separato.",
"NoteUploaderUnsupportedFiles": "I file non supportati vengono ignorati. Quando si sceglie o si elimina una cartella, gli altri file che non si trovano in una cartella di elementi vengono ignorati.", "NoteUploaderUnsupportedFiles": "I file non supportati vengono ignorati. Quando si sceglie o si elimina una cartella, gli altri file che non si trovano in una cartella di elementi vengono ignorati.",
"PlaceholderNewCollection": "Nome Nuova Raccolta", "PlaceholderNewCollection": "Nome Nuova Raccolta",
"PlaceholderNewFolderPath": "Nuovo percorso Cartella", "PlaceholderNewFolderPath": "Nuovo Percorso Cartella",
"PlaceholderNewPlaylist": "Nome nuova playlist", "PlaceholderNewPlaylist": "Nome nuova playlist",
"PlaceholderSearch": "Cerca..", "PlaceholderSearch": "Cerca..",
"PlaceholderSearchEpisode": "Cerca Episodio..", "PlaceholderSearchEpisode": "Cerca Episodio..",
@@ -693,7 +729,7 @@
"ToastRSSFeedCloseSuccess": "RSS feed chiuso", "ToastRSSFeedCloseSuccess": "RSS feed chiuso",
"ToastSendEbookToDeviceFailed": "Impossibile inviare l'ebook al dispositivo", "ToastSendEbookToDeviceFailed": "Impossibile inviare l'ebook al dispositivo",
"ToastSendEbookToDeviceSuccess": "Ebook inviato al dispositivo \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook inviato al dispositivo \"{0}\"",
"ToastSeriesUpdateFailed": "Aggiornaento Serie Fallito", "ToastSeriesUpdateFailed": "Aggiornamento Serie Fallito",
"ToastSeriesUpdateSuccess": "Serie Aggornate", "ToastSeriesUpdateSuccess": "Serie Aggornate",
"ToastSessionDeleteFailed": "Errore eliminazione sessione", "ToastSessionDeleteFailed": "Errore eliminazione sessione",
"ToastSessionDeleteSuccess": "Sessione cancellata", "ToastSessionDeleteSuccess": "Sessione cancellata",
@@ -702,4 +738,4 @@
"ToastSocketFailedToConnect": "Socket non riesce a connettersi", "ToastSocketFailedToConnect": "Socket non riesce a connettersi",
"ToastUserDeleteFailed": "Errore eliminazione utente", "ToastUserDeleteFailed": "Errore eliminazione utente",
"ToastUserDeleteSuccess": "Utente eliminato" "ToastUserDeleteSuccess": "Utente eliminato"
} }
+741
View File
@@ -0,0 +1,741 @@
{
"ButtonAdd": "Pridėti",
"ButtonAddChapters": "Pridėti skyrius",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Pridėti tinklalaides",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Pridėkite savo pirmąją biblioteką",
"ButtonApply": "Taikyti",
"ButtonApplyChapters": "Taikyti skyrius",
"ButtonAuthors": "Autoriai",
"ButtonBrowseForFolder": "Naršyti aplanko",
"ButtonCancel": "Atšaukti",
"ButtonCancelEncode": "Atšaukti kodavimą",
"ButtonChangeRootPassword": "Keisti root slaptažodį",
"ButtonCheckAndDownloadNewEpisodes": "Patikrinti ir parsiųsti naujus epizodus",
"ButtonChooseAFolder": "Pasirinkite aplanką",
"ButtonChooseFiles": "Pasirinkite failus",
"ButtonClearFilter": "Valyti filtrą",
"ButtonCloseFeed": "Uždaryti srautą",
"ButtonCollections": "Kolekcijos",
"ButtonConfigureScanner": "Konfigūruoti skenerį",
"ButtonCreate": "Kurti",
"ButtonCreateBackup": "Kurti atsarginę kopiją",
"ButtonDelete": "Ištrinti",
"ButtonDownloadQueue": "Parsisiuntimų eilė",
"ButtonEdit": "Redaguoti",
"ButtonEditChapters": "Redaguoti skyrius",
"ButtonEditPodcast": "Redaguoti tinklalaidę",
"ButtonForceReScan": "Priverstinai nuskaityti iš naujo",
"ButtonFullPath": "Visas kelias",
"ButtonHide": "Slėpti",
"ButtonHome": "Pradžia",
"ButtonIssues": "Problemos",
"ButtonLatest": "Naujausias",
"ButtonLibrary": "Biblioteka",
"ButtonLogout": "Atsijungti",
"ButtonLookup": "Ieškoti",
"ButtonManageTracks": "Tvarkyti takelius",
"ButtonMapChapterTitles": "Suderinti skyrių pavadinimus",
"ButtonMatchAllAuthors": "Pritaikyti visus autorius",
"ButtonMatchBooks": "Pritaikyti knygas",
"ButtonNevermind": "Nesvarbu",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Atidaryti srautą",
"ButtonOpenManager": "Atidaryti tvarkyklę",
"ButtonPlay": "Groti",
"ButtonPlaying": "Grojama",
"ButtonPlaylists": "Grojaraščiai",
"ButtonPurgeAllCache": "Valyti visą saugyklą",
"ButtonPurgeItemsCache": "Valyti elementų saugyklą",
"ButtonPurgeMediaProgress": "Valyti medijos progresą",
"ButtonQueueAddItem": "Pridėti į eilę",
"ButtonQueueRemoveItem": "Pašalinti iš eilės",
"ButtonQuickMatch": "Greitas pritaikymas",
"ButtonRead": "Skaityti",
"ButtonRemove": "Pašalinti",
"ButtonRemoveAll": "Pašalinti viską",
"ButtonRemoveAllLibraryItems": "Pašalinti visus bibliotekos elementus",
"ButtonRemoveFromContinueListening": "Pašalinti iš Tęsti Klausimą",
"ButtonRemoveFromContinueReading": "Pašalinti iš Tęsti Skaitymą",
"ButtonRemoveSeriesFromContinueSeries": "Pašalinti seriją iš Tęsti Seriją",
"ButtonReScan": "Iš naujo nuskaityti",
"ButtonReset": "Atstatyti",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Atkurti",
"ButtonSave": "Išsaugoti",
"ButtonSaveAndClose": "Išsaugoti ir uždaryti",
"ButtonSaveTracklist": "Išsaugoti takelių sąrašą",
"ButtonScan": "Nuskaityti",
"ButtonScanLibrary": "Nuskaityti biblioteką",
"ButtonSearch": "Ieškoti",
"ButtonSelectFolderPath": "Pasirinkti aplanko kelią",
"ButtonSeries": "Serijos",
"ButtonSetChaptersFromTracks": "Nustatyti skyrius iš takelių",
"ButtonShiftTimes": "Perstumti laikus",
"ButtonShow": "Rodyti",
"ButtonStartM4BEncode": "Pradėti M4B kodavimą",
"ButtonStartMetadataEmbed": "Pradėti metaduomenų įterpimą",
"ButtonSubmit": "Pateikti",
"ButtonTest": "Testuoti",
"ButtonUpload": "Įkelti",
"ButtonUploadBackup": "Įkelti atsarginę kopiją",
"ButtonUploadCover": "Įkelti viršelį",
"ButtonUploadOPMLFile": "Įkelti OPML failą",
"ButtonUserDelete": "Ištrinti naudotoją {0}",
"ButtonUserEdit": "Redaguoti naudotoją {0}",
"ButtonViewAll": "Peržiūrėti visus",
"ButtonYes": "Taip",
"HeaderAccount": "Paskyra",
"HeaderAdvanced": "Papildomi",
"HeaderAppriseNotificationSettings": "Apprise pranešimo nustatymai",
"HeaderAudiobookTools": "Audioknygų failų valdymo įrankiai",
"HeaderAudioTracks": "Garso takeliai",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Atsarginės kopijos",
"HeaderChangePassword": "Pakeisti slaptažodį",
"HeaderChapters": "Skyriai",
"HeaderChooseAFolder": "Pasirinkti aplanką",
"HeaderCollection": "Kolekcija",
"HeaderCollectionItems": "Kolekcijos elementai",
"HeaderCover": "Viršelis",
"HeaderCurrentDownloads": "Dabartiniai parsisiuntimai",
"HeaderDetails": "Detalės",
"HeaderDownloadQueue": "Parsisiuntimo eilė",
"HeaderEbookFiles": "Eknygos failai",
"HeaderEmail": "El. paštas",
"HeaderEmailSettings": "El. pašto nustatymai",
"HeaderEpisodes": "Epizodai",
"HeaderEreaderDevices": "Elektroniniai skaitytuvai",
"HeaderEreaderSettings": "Elektroninių skaitytuvų nustatymai",
"HeaderFiles": "Failai",
"HeaderFindChapters": "Rasti skyrius",
"HeaderIgnoredFiles": "Ignoruojami failai",
"HeaderItemFiles": "Elemento failai",
"HeaderItemMetadataUtils": "Elemento metaduomenų įrankiai",
"HeaderLastListeningSession": "Paskutinė klausymosi sesija",
"HeaderLatestEpisodes": "Naujausi epizodai",
"HeaderLibraries": "Bibliotekos",
"HeaderLibraryFiles": "Bibliotekos failai",
"HeaderLibraryStats": "Bibliotekos statistika",
"HeaderListeningSessions": "Klausymosi sesijos",
"HeaderListeningStats": "Klausymosi statistika",
"HeaderLogin": "Prisijungti",
"HeaderLogs": "Žurnalai",
"HeaderManageGenres": "Tvarkyti žanrus",
"HeaderManageTags": "Tvarkyti žymas",
"HeaderMapDetails": "Susieti detales",
"HeaderMatch": "Atitaikyti",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "Metaduomenys įterpimui",
"HeaderNewAccount": "Nauja paskyra",
"HeaderNewLibrary": "Nauja biblioteka",
"HeaderNotifications": "Pranešimai",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Atidaryti RSS srautą",
"HeaderOtherFiles": "Kiti failai",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Leidimai",
"HeaderPlayerQueue": "Grotuvo eilė",
"HeaderPlaylist": "Grojaraštis",
"HeaderPlaylistItems": "Grojaraščio elementai",
"HeaderPodcastsToAdd": "Pridėti tinklalaides",
"HeaderPreviewCover": "Peržiūrėti viršelį",
"HeaderRemoveEpisode": "Pašalinti epizodą",
"HeaderRemoveEpisodes": "Pašalinti {0} epizodus",
"HeaderRSSFeedGeneral": "RSS informacija",
"HeaderRSSFeedIsOpen": "RSS srautas yra atidarytas",
"HeaderRSSFeeds": "RSS Feeds",
"HeaderSavedMediaProgress": "Išsaugota medijos pažanga",
"HeaderSchedule": "Tvarkaraštis",
"HeaderScheduleLibraryScans": "Nustatyti bibliotekų nuskaitymo tvarkaraštį",
"HeaderSession": "Sesija",
"HeaderSetBackupSchedule": "Nustatyti atsarginių kopijų tvarkaraštį",
"HeaderSettings": "Nustatymai",
"HeaderSettingsDisplay": "Rodymas",
"HeaderSettingsExperimental": "Eksperimentinės funkcijos",
"HeaderSettingsGeneral": "Bendra",
"HeaderSettingsScanner": "Skaitytuvas",
"HeaderSleepTimer": "Miego laikmatis",
"HeaderStatsLargestItems": "Didžiausi elementai",
"HeaderStatsLongestItems": "Ilgiausi elementai (val.)",
"HeaderStatsMinutesListeningChart": "Klausymo minutės (paskutinės 7 dienos)",
"HeaderStatsRecentSessions": "Naujausios sesijos",
"HeaderStatsTop10Authors": "Top 10 autorių",
"HeaderStatsTop5Genres": "Top 5 žanrai",
"HeaderTableOfContents": "Turinys",
"HeaderTools": "Įrankiai",
"HeaderUpdateAccount": "Atnaujinti paskyrą",
"HeaderUpdateAuthor": "Atnaujinti autorių",
"HeaderUpdateDetails": "Atnaujinti informaciją",
"HeaderUpdateLibrary": "Atnaujinti biblioteką",
"HeaderUsers": "Naudotojai",
"HeaderYourStats": "Jūsų statistika",
"LabelAbridged": "Santrauka",
"LabelAccountType": "Paskyros tipas",
"LabelAccountTypeAdmin": "Administratorius",
"LabelAccountTypeGuest": "Svečias",
"LabelAccountTypeUser": "Naudotojas",
"LabelActivity": "Veikla",
"LabelAdded": "Pridėta",
"LabelAddedAt": "Pridėta {0}",
"LabelAddToCollection": "Pridėti į kolekciją",
"LabelAddToCollectionBatch": "Pridėti {0} knygas į kolekciją",
"LabelAddToPlaylist": "Pridėti į grojaraštį",
"LabelAddToPlaylistBatch": "Pridėti {0} elementus į grojaraštį",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "Visi",
"LabelAllUsers": "Visi naudotojai",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Jau yra jūsų bibliotekoje",
"LabelAppend": "Pridėti",
"LabelAuthor": "Autorius",
"LabelAuthorFirstLast": "Autorius (Vardas Pavardė)",
"LabelAuthorLastFirst": "Autorius (Pavardė, Vardas)",
"LabelAuthors": "Autoriai",
"LabelAutoDownloadEpisodes": "Automatiškai atsisiųsti epizodus",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Grįžti į naudotoją",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Įjungti automatinį atsarginių kopijų kūrimą",
"LabelBackupsEnableAutomaticBackupsHelp": "Atsarginės kopijos bus išsaugotos /metadata/backups aplanke",
"LabelBackupsMaxBackupSize": "Maksimalus atsarginių kopijų dydis (GB)",
"LabelBackupsMaxBackupSizeHelp": "Jei konfigūruotas dydis viršijamas, atsarginės kopijos nebus sukurtos, kad būtų išvengta klaidingų konfigūracijų.",
"LabelBackupsNumberToKeep": "Laikytinų atsarginių kopijų skaičius",
"LabelBackupsNumberToKeepHelp": "Tik viena atsarginė kopija bus pašalinta vienu metu, todėl jei jau turite daugiau atsarginių kopijų nei nurodyta, turite jas pašalinti rankiniu būdu.",
"LabelBitrate": "Bitų sparta",
"LabelBooks": "Knygos",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Pakeisti slaptažodį",
"LabelChannels": "Kanalai",
"LabelChapters": "Skyriai",
"LabelChaptersFound": "rasti skyriai",
"LabelChapterTitle": "Skyriaus pavadinimas",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Uždaryti grotuvą",
"LabelCodec": "Kodekas",
"LabelCollapseSeries": "Suskleisti seriją",
"LabelCollection": "Collection",
"LabelCollections": "Kolekcijos",
"LabelComplete": "Baigta",
"LabelConfirmPassword": "Patvirtinkite slaptažodį",
"LabelContinueListening": "Tęsti klausymąsi",
"LabelContinueReading": "Tęsti skaitymą",
"LabelContinueSeries": "Tęsti seriją",
"LabelCover": "Viršelis",
"LabelCoverImageURL": "Viršelio paveikslėlio URL",
"LabelCreatedAt": "Sukurta",
"LabelCronExpression": "Cron išraiška",
"LabelCurrent": "Dabartinė",
"LabelCurrently": "Šiuo metu:",
"LabelCustomCronExpression": "Nestandartinė Cron išraiška:",
"LabelDatetime": "Data ir laikas",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Aprašymas",
"LabelDeselectAll": "Išvalyti pasirinktus",
"LabelDevice": "Įrenginys",
"LabelDeviceInfo": "Įrenginio informacija",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Katalogas",
"LabelDiscFromFilename": "Diskas pagal failo pavadinimą",
"LabelDiscFromMetadata": "Diskas pagal metaduomenis",
"LabelDiscover": "Discover",
"LabelDownload": "Atsisiųsti",
"LabelDownloadNEpisodes": "Atsisiųsti {0} epizodų",
"LabelDuration": "Trukmė",
"LabelDurationFound": "Rasta trukmė:",
"LabelEbook": "Elektroninė knyga",
"LabelEbooks": "Elektroninės knygos",
"LabelEdit": "Redaguoti",
"LabelEmail": "El. paštas",
"LabelEmailSettingsFromAddress": "Siuntėjo adresas",
"LabelEmailSettingsSecure": "Apsaugota",
"LabelEmailSettingsSecureHelp": "Jei ši reikšmė yra \"true\", ryšys naudos TLS protokolą. Jei \"false\", TLS bus naudojamas tik tada, jei serveris palaiko STARTTLS plėtinį. Daugumos atveju, jei jungiamasi prie 465 prievado, šią reikšmę turėtumėte nustatyti kaip \"true\". Jei jungiamasi prie 587 arba 25 prievado, turi būti nustatyta \"false\". (iš nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Testinis adresas",
"LabelEmbeddedCover": "Įterptas viršelis",
"LabelEnable": "Įjungti",
"LabelEnd": "Pabaiga",
"LabelEpisode": "Epizodas",
"LabelEpisodeTitle": "Epizodo pavadinimas",
"LabelEpisodeType": "Epizodo tipas",
"LabelExample": "Pavyzdys",
"LabelExplicit": "Suaugusiems",
"LabelFeedURL": "Srauto URL",
"LabelFile": "Failas",
"LabelFileBirthtime": "Failo kūrimo laikas",
"LabelFileModified": "Failo keitimo laikas",
"LabelFilename": "Failo pavadinimas",
"LabelFilterByUser": "Filtruoti pagal naudotoją",
"LabelFindEpisodes": "Rasti epizodus",
"LabelFinished": "Baigta",
"LabelFolder": "Aplankas",
"LabelFolders": "Aplankai",
"LabelFontFamily": "Famiglia di font",
"LabelFontScale": "Šrifto mastelis",
"LabelFormat": "Formatas",
"LabelGenre": "Žanras",
"LabelGenres": "Žanrai",
"LabelHardDeleteFile": "Galutinai ištrinti failą",
"LabelHasEbook": "Turi e-knygą",
"LabelHasSupplementaryEbook": "Turi papildomą e-knygą",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Serveris",
"LabelHour": "Valanda",
"LabelIcon": "Piktograma",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Įtraukti į takelių sąrašą",
"LabelIncomplete": "Nebaigta",
"LabelInProgress": "Vyksta",
"LabelInterval": "Intervalas",
"LabelIntervalCustomDailyWeekly": "Pasirinktinis kasdieninės/savaitinės periodiškumas",
"LabelIntervalEvery12Hours": "Kas 12 valandų",
"LabelIntervalEvery15Minutes": "Kas 15 minučių",
"LabelIntervalEvery2Hours": "Kas 2 valandas",
"LabelIntervalEvery30Minutes": "Kas 30 minučių",
"LabelIntervalEvery6Hours": "Kas 6 valandas",
"LabelIntervalEveryDay": "Kasdien",
"LabelIntervalEveryHour": "Kiekvieną valandą",
"LabelInvalidParts": "Netinkamos dalys",
"LabelInvert": "Apversti",
"LabelItem": "Elementas",
"LabelLanguage": "Kalba",
"LabelLanguageDefaultServer": "Numatytoji serverio kalba",
"LabelLastBookAdded": "Paskutinė pridėta knyga",
"LabelLastBookUpdated": "Paskutinė atnaujinta knyga",
"LabelLastSeen": "Paskutinį kartą matyta",
"LabelLastTime": "Paskutinį kartą",
"LabelLastUpdate": "Paskutinė atnaujinimo data",
"LabelLayout": "Išdėstymas",
"LabelLayoutSinglePage": "Vieno puslapio",
"LabelLayoutSplitPage": "Padalinto puslapio",
"LabelLess": "Mažiau",
"LabelLibrariesAccessibleToUser": "Naudotojui pasiekiamos bibliotekos",
"LabelLibrary": "Biblioteka",
"LabelLibraryItem": "Bibliotekos elementas",
"LabelLibraryName": "Bibliotekos pavadinimas",
"LabelLimit": "Limitas",
"LabelLineSpacing": "Tarpas tarp eilučių",
"LabelListenAgain": "Klausytis iš naujo",
"LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Ieškoti naujų epizodų po šios datos",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Grotuvas",
"LabelMediaType": "Medijos tipas",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metaduomenų tiekėjas",
"LabelMetaTag": "Meta žymė",
"LabelMetaTags": "Meta žymos",
"LabelMinute": "Minutė",
"LabelMissing": "Trūksta",
"LabelMissingParts": "Trūkstamos dalys",
"LabelMore": "Daugiau",
"LabelMoreInfo": "Daugiau informacijos",
"LabelName": "Pavadinimas",
"LabelNarrator": "Skaitytojas",
"LabelNarrators": "Skaitytojai",
"LabelNew": "Nauja",
"LabelNewestAuthors": "Naujausi autoriai",
"LabelNewestEpisodes": "Naujausi epizodai",
"LabelNewPassword": "Naujas slaptažodis",
"LabelNextBackupDate": "Kitos atsarginės kopijos data",
"LabelNextScheduledRun": "Kito planuoto vykdymo data",
"LabelNoEpisodesSelected": "Nepasirinkti jokie epizodai",
"LabelNotes": "Užrašai",
"LabelNotFinished": "Nebaigta",
"LabelNotificationAppriseURL": "Pranešimo (Apprise) URL",
"LabelNotificationAvailableVariables": "Galimi kintamieji",
"LabelNotificationBodyTemplate": "Turinio šablonas",
"LabelNotificationEvent": "Pranešimo įvykis",
"LabelNotificationsMaxFailedAttempts": "Maksimalus nesėkmingų bandymų skaičius",
"LabelNotificationsMaxFailedAttemptsHelp": "Pranešimai bus išjungti, jei nepavyks jų išsiųsti nurodytą kartų",
"LabelNotificationsMaxQueueSize": "Maksimalus pranešimų eilių dydis",
"LabelNotificationsMaxQueueSizeHelp": "Įvykiai yra apriboti vienu įvykiu per sekundę. Įvykiai bus ignoruojami, jei eilė yra maksimalaus dydžio. Tai apsaugo nuo pranešimų šlamšto.",
"LabelNotificationTitleTemplate": "Pavadinimo šablonas",
"LabelNotStarted": "Nepasileista",
"LabelNumberOfBooks": "Knygų skaičius",
"LabelNumberOfEpisodes": "Epizodų skaičius",
"LabelOpenRSSFeed": "Atidaryti RSS srautą",
"LabelOverwrite": "Perrašyti",
"LabelPassword": "Slaptažodis",
"LabelPath": "Kelias",
"LabelPermissionsAccessAllLibraries": "Gali pasiekti visas bibliotekas",
"LabelPermissionsAccessAllTags": "Gali pasiekti visas žymes",
"LabelPermissionsAccessExplicitContent": "Gali pasiekti turinį suaugusiems",
"LabelPermissionsDelete": "Gali trinti",
"LabelPermissionsDownload": "Gali atsisiųsti",
"LabelPermissionsUpdate": "Gali atnaujinti",
"LabelPermissionsUpload": "Gali įkelti",
"LabelPhotoPathURL": "Nuotraukos kelias/URL",
"LabelPlaylists": "Grojaraščiai",
"LabelPlayMethod": "Grojimo metodas",
"LabelPodcast": "Tinklalaidė",
"LabelPodcasts": "Tinklalaidės",
"LabelPodcastType": "Tinklalaidės tipas",
"LabelPort": "Prievadas",
"LabelPrefixesToIgnore": "Ignoruojami priešdėliai (didžiosios/mažosios nesvarbu)",
"LabelPreventIndexing": "Neleisti indeksuoti jūsų srauto „iTunes“ ir Google podcast kataloguose",
"LabelPrimaryEbook": "Pagrindinė e-knyga",
"LabelProgress": "Progresas",
"LabelProvider": "Tiekėjas",
"LabelPubDate": "Publikavimo data",
"LabelPublisher": "Leidėjas",
"LabelPublishYear": "Leidimo metai",
"LabelRead": "Skaityta",
"LabelReadAgain": "Skaityti dar kartą",
"LabelReadEbookWithoutProgress": "Skaityti e-knygą be pažangos saugojimo",
"LabelRecentlyAdded": "Neseniai pridėta",
"LabelRecentSeries": "Naujausios serijos",
"LabelRecommended": "Rekomenduojama",
"LabelRegion": "Regionas",
"LabelReleaseDate": "Išleidimo data",
"LabelRemoveCover": "Pašalinti viršelį",
"LabelRSSFeedCustomOwnerEmail": "Pasirinktinis savininko el. paštas",
"LabelRSSFeedCustomOwnerName": "Pasirinktinis savininko vardas",
"LabelRSSFeedOpen": "Atidarytas RSS srautas",
"LabelRSSFeedPreventIndexing": "Neleisti indeksuoti",
"LabelRSSFeedSlug": "RSS srauto identifikatorius",
"LabelRSSFeedURL": "RSS srauto URL",
"LabelSearchTerm": "Paieškos žodis",
"LabelSearchTitle": "Ieškoti pavadinimo",
"LabelSearchTitleOrASIN": "Ieškoti pavadinimo arba ASIN",
"LabelSeason": "Sezonas",
"LabelSelectAllEpisodes": "Pažymėti visus epizodus",
"LabelSelectEpisodesShowing": "Pažymėti {0} rodomus epizodus",
"LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Siųsti e-knygą į...",
"LabelSequence": "Seka",
"LabelSeries": "Serija",
"LabelSeriesName": "Serijos pavadinimas",
"LabelSeriesProgress": "Serijos progresas",
"LabelSetEbookAsPrimary": "Nustatyti kaip pagrindinę",
"LabelSetEbookAsSupplementary": "Nustatyti kaip papildomą",
"LabelSettingsAudiobooksOnly": "Tik garso knygos",
"LabelSettingsAudiobooksOnlyHelp": "Įjungus šią parinktį, e-knygų failai bus ignoruojami, nebent jie būtų audioknygų aplankuose, kurie tada būtų rodomi kaip papildomos e-knygos",
"LabelSettingsBookshelfViewHelp": "Knygų lentynos dizainas su medinėmis lentynomis",
"LabelSettingsChromecastSupport": "„Chromecast“ palaikymas",
"LabelSettingsDateFormat": "Datos formatas",
"LabelSettingsDisableWatcher": "Išjungti stebėtoją",
"LabelSettingsDisableWatcherForLibrary": "Išjungti aplankų stebėtoją bibliotekai",
"LabelSettingsDisableWatcherHelp": "Išjungia automatinį elementų pridėjimą/atnaujinimą, jei pastebėti failų pokyčiai. *Reikalingas serverio paleidimas iš naujo",
"LabelSettingsEnableWatcher": "Enable Watcher",
"LabelSettingsEnableWatcherForLibrary": "Enable folder watcher for library",
"LabelSettingsEnableWatcherHelp": "Enables the automatic adding/updating of items when file changes are detected. *Requires server restart",
"LabelSettingsExperimentalFeatures": "Eksperimentiniai funkcionalumai",
"LabelSettingsExperimentalFeaturesHelp": "Funkcijos, kurios yra kuriamos ir laukiami jūsų komentarai. Spustelėkite, kad atidarytumėte „GitHub“ diskusiją.",
"LabelSettingsFindCovers": "Rasti viršelius",
"LabelSettingsFindCoversHelp": "Jei jūsų audioknyga neturi įterpto viršelio arba viršelio paveikslėlio aplanko, skeneris bandys rasti viršelį.<br>Pastaba: Tai padidins skenavimo trukmę.",
"LabelSettingsHideSingleBookSeries": "Slėpti serijas, turinčias tik vieną knygą",
"LabelSettingsHideSingleBookSeriesHelp": "Serijos, turinčios tik vieną knygą, bus paslėptos nuo serijų puslapio ir pagrindinio puslapio lentynų.",
"LabelSettingsHomePageBookshelfView": "Naudoti pagrindinio puslapio knygų lentynų vaizdą",
"LabelSettingsLibraryBookshelfView": "Naudoti bibliotekos knygų lentynų vaizdą",
"LabelSettingsParseSubtitles": "Analizuoti subtitrus",
"LabelSettingsParseSubtitlesHelp": "Išskleisti subtitrus iš audioknygos aplanko pavadinimų.<br>Subtitrai turi būti atskirti brūkšniu \"-\"<br>pavyzdžiui, \"Knygos pavadinimas - Čia yra subtitrai\" turi subtitrą \"Čia yra subtitrai\"",
"LabelSettingsPreferMatchedMetadata": "Pirmenybė atitaikytiems metaduomenis",
"LabelSettingsPreferMatchedMetadataHelp": "Atitaikyti duomenys pakeis elementų informaciją naudojant Greitą atitikimą. Pagal nutylėjimą Greitas atitaikymas užpildys tik trūkstamas detales.",
"LabelSettingsSkipMatchingBooksWithASIN": "Praleisti knygas, kurios jau turi ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Praleisti knygas, kurios jau turi ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignoruoti priešdėlius rūšiuojant",
"LabelSettingsSortingIgnorePrefixesHelp": "pvz., su priešdėliu \"the\" knygos pavadinimas \"The Book Title\" bus rūšiuojamas kaip \"Book Title, The\"",
"LabelSettingsSquareBookCovers": "Naudoti kvadratinius knygos viršelius",
"LabelSettingsSquareBookCoversHelp": "Naudoti kvadratinius viršelius vietoj standartinių 1.6:1 knygų viršelių",
"LabelSettingsStoreCoversWithItem": "Saugoti viršelius su elementu",
"LabelSettingsStoreCoversWithItemHelp": "Pagal nutylėjimą viršeliai saugomi /metadata/items aplanke, įjungus šią parinktį viršeliai bus saugomi jūsų bibliotekos elemento aplanke. Bus išsaugotas tik vienas „cover“ pavadinimo failas.",
"LabelSettingsStoreMetadataWithItem": "Saugoti metaduomenis su elementu",
"LabelSettingsStoreMetadataWithItemHelp": "Pagal nutylėjimą metaduomenų failai saugomi /metadata/items aplanke, įjungus šią parinktį metaduomenų failai bus saugomi jūsų bibliotekos elemento aplanke",
"LabelSettingsTimeFormat": "Laiko formatas",
"LabelShowAll": "Rodyti viską",
"LabelSize": "Dydis",
"LabelSleepTimer": "Miego laikmatis",
"LabelSlug": "Slug",
"LabelStart": "Pradėti",
"LabelStarted": "Pradėta",
"LabelStartedAt": "Pradėta",
"LabelStartTime": "Pradžios laikas",
"LabelStatsAudioTracks": "Garsiniai takeliai",
"LabelStatsAuthors": "Autoriai",
"LabelStatsBestDay": "Geriausia diena",
"LabelStatsDailyAverage": "Vidutiniškai per dieną",
"LabelStatsDays": "Dienos",
"LabelStatsDaysListened": "Klausyta dienų",
"LabelStatsHours": "Valandos",
"LabelStatsInARow": "iš eilės",
"LabelStatsItemsFinished": "Baigti elementai",
"LabelStatsItemsInLibrary": "Elementai bibliotekoje",
"LabelStatsMinutes": "minutės",
"LabelStatsMinutesListening": "Klausyta minučių",
"LabelStatsOverallDays": "Iš viso dienų",
"LabelStatsOverallHours": "Iš viso valandų",
"LabelStatsWeekListening": "Savaitės klausymas",
"LabelSubtitle": "Subtitrai",
"LabelSupportedFileTypes": "Palaikomi failų tipai",
"LabelTag": "Žyma",
"LabelTags": "Žymos",
"LabelTagsAccessibleToUser": "Žymos, pasiekiamos vartotojui",
"LabelTagsNotAccessibleToUser": "Žymos, nepasiekiamos vartotojui",
"LabelTasks": "Vykdomos užduotys",
"LabelTheme": "Tema",
"LabelThemeDark": "Tamsi",
"LabelThemeLight": "Šviesi",
"LabelTimeBase": "Laiko pagrindas",
"LabelTimeListened": "Klausytas laikas",
"LabelTimeListenedToday": "Klausytas laikas šiandien",
"LabelTimeRemaining": "{0} likę",
"LabelTimeToShift": "Laiko perkėlimas sekundėmis",
"LabelTitle": "Pavadinimas",
"LabelToolsEmbedMetadata": "Įterpti metaduomenis",
"LabelToolsEmbedMetadataDescription": "Įterpti metaduomenis į garso failus, įskaitant viršelio paveikslu ir skyrius.",
"LabelToolsMakeM4b": "Sukurti M4B garso knygų failą",
"LabelToolsMakeM4bDescription": "Sukurti .M4B garso knygų failą su įterptais metaduomenimis, viršelio paveikslu ir skyriais.",
"LabelToolsSplitM4b": "Skaidyti M4B į MP3 failus",
"LabelToolsSplitM4bDescription": "Sukurti MP3 failus iš M4B su skyrių skaldymu ir įterptais metaduomenimis, viršelio paveikslu ir skyriais.",
"LabelTotalDuration": "Viso trukmė",
"LabelTotalTimeListened": "Iš viso klausyta laiko",
"LabelTrackFromFilename": "Takelis iš failo pavadinimo",
"LabelTrackFromMetadata": "Takelis iš metaduomenų",
"LabelTracks": "Takeliai",
"LabelTracksMultiTrack": "Keli takeliai",
"LabelTracksNone": "No tracks",
"LabelTracksSingleTrack": "Vienas takelis",
"LabelType": "Tipas",
"LabelUnabridged": "Neprikurptas",
"LabelUnknown": "Nežinoma",
"LabelUpdateCover": "Atnaujinti viršelį",
"LabelUpdateCoverHelp": "Leisti perrašyti esamus viršelius pasirinktoms knygoms, kai yra rasta atitikmenų",
"LabelUpdatedAt": "Atnaujinta",
"LabelUpdateDetails": "Atnaujinti duomenis",
"LabelUpdateDetailsHelp": "Leisti perrašyti esamus duomenis pasirinktoms knygoms, kai yra rasta atitikmenų",
"LabelUploaderDragAndDrop": "Tempkite ir paleiskite failus ar aplankus",
"LabelUploaderDropFiles": "Nutempti failus",
"LabelUseChapterTrack": "Naudoti skyrių takelį",
"LabelUseFullTrack": "Naudoti visą takelį",
"LabelUser": "Vartotojas",
"LabelUsername": "Vartotojo vardas",
"LabelValue": "Reikšmė",
"LabelVersion": "Versija",
"LabelViewBookmarks": "Peržiūrėti skirtukus",
"LabelViewChapters": "Peržiūrėti skyrius",
"LabelViewQueue": "Peržiūrėti grotuvo eilę",
"LabelVolume": "Garsumas",
"LabelWeekdaysToRun": "Dienos, kuriomis vykdyti",
"LabelYourAudiobookDuration": "Jūsų garso knygos trukmė",
"LabelYourBookmarks": "Jūsų skirtukai",
"LabelYourPlaylists": "Jūsų grojaraščiai",
"LabelYourProgress": "Jūsų pažanga",
"MessageAddToPlayerQueue": "Pridėti į grotuvo eilę",
"MessageAppriseDescription": "Norint naudoti šią funkciją, reikės turėti <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> veikiantį arba API, kuris tvarkys tas pačias užklausas.<br />Apprise API URL turėtų būti visi kelio takai iki pranešimo siuntimo, pvz., jei jūsų API pasiekiamas adresu <code>http://192.168.1.1:8337</code>, tada įveskite <code>http://192.168.1.1:8337/notify</code>.",
"MessageBackupsDescription": "Atsarginės kopijos apima vartotojus, vartotojų pažangą, bibliotekos elemento informaciją, serverio nustatymus ir vaizdus, saugomus <code>/metadata/items</code> ir <code>/metadata/authors</code>. Atsarginės kopijos <strong>neįtraukia</strong> jokių failų, saugomų jūsų bibliotekos aplankuose.",
"MessageBatchQuickMatchDescription": "Greitas atitikmens rasti bandys pridėti trūkstamus viršelius ir metaduomenis pasirinktiems elementams. Įjunkite žemiau esančias parinktis, kad leistumėte Greitajam atitikmeniui perrašyti esamus viršelius ir/ar metaduomenis.",
"MessageBookshelfNoCollections": "Dar nepridėjote jokių kolekcijų",
"MessageBookshelfNoResultsForFilter": "Rezultatų pagal filtrą \"{0}: {1}\" nėra",
"MessageBookshelfNoRSSFeeds": "Nėra atvertų RSS srautų",
"MessageBookshelfNoSeries": "Neturite jokių serijų",
"MessageChapterEndIsAfter": "Skyriaus pabaiga yra po jūsų garso knygos pabaigos",
"MessageChapterErrorFirstNotZero": "Pirmasis skyrius turi prasidėti nuo 0",
"MessageChapterErrorStartGteDuration": "Netinkamas pradžios laikas. Turi būti mažesnis nei garso knygos trukmė",
"MessageChapterErrorStartLtPrev": "Netinkamas pradžios laikas. Turi būti didesnis arba lygus ankstesnio skyriaus pradžios laikui",
"MessageChapterStartIsAfter": "Skyriaus pradžia yra po jūsų garso knygos pabaigos",
"MessageCheckingCron": "Tikrinamas cron...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Ar tikrai norite ištrinti atsarginę kopiją, skirtą {0}?",
"MessageConfirmDeleteFile": "Tai ištrins failą iš jūsų failų sistemos. Ar tikrai?",
"MessageConfirmDeleteLibrary": "Ar tikrai norite visam laikui ištrinti biblioteką \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Ar tikrai norite ištrinti šią sesiją?",
"MessageConfirmForceReScan": "Ar tikrai norite priversti perskenavimą?",
"MessageConfirmMarkAllEpisodesFinished": "Ar tikrai norite pažymėti visus epizodus kaip užbaigtus?",
"MessageConfirmMarkAllEpisodesNotFinished": "Ar tikrai norite pažymėti visus epizodus kaip nebaigtus?",
"MessageConfirmMarkSeriesFinished": "Ar tikrai norite pažymėti visas knygas šioje serijoje kaip užbaigtas?",
"MessageConfirmMarkSeriesNotFinished": "Ar tikrai norite pažymėti visas knygas šioje serijoje kaip nebaigtas?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Ar tikrai norite pašalinti visus skyrius?",
"MessageConfirmRemoveAuthor": "Are you sure you want to remove author \"{0}\"?",
"MessageConfirmRemoveCollection": "Ar tikrai norite pašalinti kolekciją \"{0}\"?",
"MessageConfirmRemoveEpisode": "Ar tikrai norite pašalinti epizodą \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Ar tikrai norite pašalinti {0} epizodus?",
"MessageConfirmRemoveNarrator": "Ar tikrai norite pašalinti skaitytoją \"{0}\"?",
"MessageConfirmRemovePlaylist": "Ar tikrai norite pašalinti savo grojaraštį \"{0}\"?",
"MessageConfirmRenameGenre": "Ar tikrai norite pervadinti žanrą \"{0}\" į \"{1}\" visiems elementams?",
"MessageConfirmRenameGenreMergeNote": "Pastaba: šis žanras jau yra, todėl jie bus sujungti.",
"MessageConfirmRenameGenreWarning": "Įspėjimas! Panašus žanras jau yra \"{0}\".",
"MessageConfirmRenameTag": "Ar tikrai norite pervadinti žymą \"{0}\" į \"{1}\" visiems elementams?",
"MessageConfirmRenameTagMergeNote": "Pastaba: ši žyma jau egzistuoja, todėl jos bus sujungtos.",
"MessageConfirmRenameTagWarning": "Įspėjimas! Panaši žyma jau egzistuoja \"{0}\".",
"MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Ar tikrai norite nusiųsti {0} el. knygą \"{1}\" į įrenginį \"{2}\"?",
"MessageDownloadingEpisode": "Epizodas atsisiunčiamas",
"MessageDragFilesIntoTrackOrder": "Surikiuokite takelius vilkdami failus",
"MessageEmbedFinished": "Įterpimas baigtas!",
"MessageEpisodesQueuedForDownload": "{0} epizodai laukia atsisiuntimo",
"MessageFeedURLWillBe": "Srauto URL bus {0}",
"MessageFetching": "Surenkama...",
"MessageForceReScanDescription": "skenuos visus failus lyg iš naujo. Garsinių failų ID3 žymos, OPF failai ir tekstiniai failai bus nuskenuoti kaip nauji.",
"MessageImportantNotice": "Svarbus pranešimas!",
"MessageInsertChapterBelow": "Įterpti skyrių žemiau",
"MessageItemsSelected": "Pasirinkti {0} elementai (-ų)",
"MessageItemsUpdated": "Atnaujinti {0} elementai (-ų)",
"MessageJoinUsOn": "Prisijunkite prie mūsų",
"MessageListeningSessionsInTheLastYear": "{0} klausymo sesijų per paskutinius metus",
"MessageLoading": "Kraunama...",
"MessageLoadingFolders": "Kraunami aplankai...",
"MessageM4BFailed": "M4B Nepavyko!",
"MessageM4BFinished": "M4B Baigta!",
"MessageMapChapterTitles": "Susieti skyriaus pavadinimus su jūsų esamais garso knygos skyriais, neredaguojant laiko žymų",
"MessageMarkAllEpisodesFinished": "Pažymėti visus epizodus kaip užbaigtus",
"MessageMarkAllEpisodesNotFinished": "Pažymėti visus epizodus kaip nebaigtus",
"MessageMarkAsFinished": "Pažymėti kaip užbaigtą",
"MessageMarkAsNotFinished": "Pažymėti kaip nebaigtą",
"MessageMatchBooksDescription": "bandys suderinti bibliotekos knygas su knyga iš pasirinkto paieškos tiekėjo ir užpildys tuščius duomenis ir viršelius. Neperrašo detalių.",
"MessageNoAudioTracks": "Nėra garso takelių",
"MessageNoAuthors": "Nėra autorių",
"MessageNoBackups": "Nėra atsarginių kopijų",
"MessageNoBookmarks": "Nėra žymų",
"MessageNoChapters": "Nėra skyrių",
"MessageNoCollections": "Nėra kolekcijų",
"MessageNoCoversFound": "Nerasta viršelių",
"MessageNoDescription": "Nėra aprašymo",
"MessageNoDownloadsInProgress": "Nėra vykstančių atsisiuntimų",
"MessageNoDownloadsQueued": "Nėra eilėje esančių atsisiuntimų",
"MessageNoEpisodeMatchesFound": "Nerasta epizodo atitikmenų",
"MessageNoEpisodes": "Nėra epizodų",
"MessageNoFoldersAvailable": "Nėra prieinamų aplankų",
"MessageNoGenres": "Nėra žanrų",
"MessageNoIssues": "Nėra problemų",
"MessageNoItems": "Nėra elementų",
"MessageNoItemsFound": "Elementų nerasta",
"MessageNoListeningSessions": "Klausymo sesijų nėra",
"MessageNoLogs": "Žurnalo įrašų nėra",
"MessageNoMediaProgress": "Nėra medijos pažangos",
"MessageNoNotifications": "Nėra pranešimų",
"MessageNoPodcastsFound": "Tinklalaidžių nerasta",
"MessageNoResults": "Rezultatų nėra",
"MessageNoSearchResultsFor": "Paieškos rezultatų nėra „{0}“",
"MessageNoSeries": "Serijų nėra",
"MessageNoTags": "Žymų nėra",
"MessageNoTasksRunning": "Nėra vykstančių užduočių",
"MessageNotYetImplemented": "Dar neįgyvendinta",
"MessageNoUpdateNecessary": "Atnaujinimai nereikalingi",
"MessageNoUpdatesWereNecessary": "Nereikalingi jokie atnaujinimai",
"MessageNoUserPlaylists": "Neturite grojaraščių",
"MessageOr": "arba",
"MessagePauseChapter": "Pristabdyti skyriaus grojimą",
"MessagePlayChapter": "Paklausyti skyriaus pradžios",
"MessagePlaylistCreateFromCollection": "Sukurti grojaraštį iš kolekcijos",
"MessagePodcastHasNoRSSFeedForMatching": "Tinklalidė neturi RSS srauto URL kuriuo būtų galima sulyginti",
"MessageQuickMatchDescription": "Užpildykite tuščius elementų duomenis ir viršelius su pirmuoju atitikimo rezultatu iš „{0}“. Neneperrašo detalių, nebent įgalintas serverio nustatymas „Pirmenybė atitaikytiems metaduomenis“.",
"MessageRemoveChapter": "Pašalinti skyrių",
"MessageRemoveEpisodes": "Pašalinti {0} epizodų (-ą)",
"MessageRemoveFromPlayerQueue": "Pašalinti iš grojaraščio",
"MessageRemoveUserWarning": "Ar tikrai norite visam laikui ištrinti naudotoją „{0}“?",
"MessageReportBugsAndContribute": "Praneškite apie klaidas, prašykite naujovių ir prisidėkite",
"MessageResetChaptersConfirm": "Ar tikrai norite atkurti skyrius ir atšaukti pakeitimus, kuriuos atlikote?",
"MessageRestoreBackupConfirm": "Ar tikrai norite atkurti atsarginę kopiją, sukurtą",
"MessageRestoreBackupWarning": "Atkurdami atsarginę kopiją perrašysite visą duomenų bazę, esančią /config ir viršelių vaizdus /metadata/items ir /metadata/authors.<br /><br />Atsarginės kopijos nekeičia jokių failų jūsų bibliotekos aplankuose. Jei esate įgalinę serverio nustatymus, kad viršelio meną ir metaduomenis saugotumėte savo bibliotekos aplankuose, šie neperrašomi ar atkuriami.<br /><br />Visi klientai, naudojantys jūsų serverį, bus automatiškai atnaujinti.",
"MessageSearchResultsFor": "Paieškos rezultatai „{0}“",
"MessageServerCouldNotBeReached": "Nepavyko pasiekti serverio",
"MessageSetChaptersFromTracksDescription": "Nustatyti skyrius, naudojant kiekvieną garso failą kaip skyrių ir skyriaus pavadinimą kaip garso failo pavadinimą",
"MessageStartPlaybackAtTime": "Paleisti klausymą „{0}“ nuo {1}?",
"MessageThinking": "Mąstau...",
"MessageUploaderItemFailed": "Įkelti nepavyko",
"MessageUploaderItemSuccess": "Sėkmingai įkelta!",
"MessageUploading": "Įkeliama...",
"MessageValidCronExpression": "Galiojanti cron išraiška",
"MessageWatcherIsDisabledGlobally": "Serverio nustatymuose stebėtojas išjungtas visuotinai",
"MessageXLibraryIsEmpty": "{0} biblioteka tuščia!",
"MessageYourAudiobookDurationIsLonger": "Jūsų garso knygos trukmė yra ilgesnė nei rasta trukmė",
"MessageYourAudiobookDurationIsShorter": "Jūsų garso knygos trukmė yra trumpesnė nei rasta trukmė",
"NoteChangeRootPassword": "Tik root vartotojas gali turėti tuščią slaptažodį",
"NoteChapterEditorTimes": "Pastaba: Pirmasis skyriaus pradžios laikas turi likti 0:00, o paskutinio skyriaus pradžios laikas negali viršyti šios garso knygos trukmės.",
"NoteFolderPicker": "Pastaba: jau susieti aplankai nebus rodomi",
"NoteFolderPickerDebian": "Pastaba: Aplanko pasirinkimo įrankis „Debian“ sistemoje nėra visiškai įgyvendintas. Turėtumėte tiesiogiai įvesti kelią į savo biblioteką.",
"NoteRSSFeedPodcastAppsHttps": "Įspėjimas: Dauguma tinklalaidžių programų reikalauja, kad RSS kanalo URL būtų naudojamas su HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Įspėjimas: Vienas ar daugiau jūsų epizodų neturi publikavimo datos. Kai kurios tinklalaidžių programos to reikalauja.",
"NoteUploaderFoldersWithMediaFiles": "Aplankai su medijos failais bus tvarkomi kaip atskiri bibliotekos elementai.",
"NoteUploaderOnlyAudioFiles": "Jei įkeliami tik garso failai, kiekvienas garso failas bus tvarkomas kaip atskira garso knyga.",
"NoteUploaderUnsupportedFiles": "Nepalaikomi failai yra ignoruojami. Pasirinkus ar atidarant aplanką, kiti failai, nesantys elementų aplankuose, yra ignoruojami.",
"PlaceholderNewCollection": "Naujas kolekcijos pavadinimas",
"PlaceholderNewFolderPath": "Naujas aplanko kelias",
"PlaceholderNewPlaylist": "Naujas grojaraščio pavadinimas",
"PlaceholderSearch": "Ieškoti..",
"PlaceholderSearchEpisode": "Ieškoti epizodo..",
"ToastAccountUpdateFailed": "Paskyros atnaujinimas nepavyko",
"ToastAccountUpdateSuccess": "Paskyra atnaujinta",
"ToastAuthorImageRemoveFailed": "Nepavyko pašalinti autoriaus paveiksliuko",
"ToastAuthorImageRemoveSuccess": "Autoriaus paveiksliukas pašalintas",
"ToastAuthorUpdateFailed": "Nepavyko atnaujinti autoriaus",
"ToastAuthorUpdateMerged": "Autorius sujungtas",
"ToastAuthorUpdateSuccess": "Autorius atnaujintas",
"ToastAuthorUpdateSuccessNoImageFound": "Autorius atnaujintas (paveiksliukas nerastas)",
"ToastBackupCreateFailed": "Atsarginės kopijos sukurti nepavyko",
"ToastBackupCreateSuccess": "Atsarginė kopija sukurta",
"ToastBackupDeleteFailed": "Atsarginės kopijos ištrinti nepavyko",
"ToastBackupDeleteSuccess": "Atsarginė kopija ištrinta",
"ToastBackupRestoreFailed": "Atsarginės kopijos atkurti nepavyko",
"ToastBackupUploadFailed": "Atsarginės kopijos įkelti nepavyko",
"ToastBackupUploadSuccess": "Atsarginė kopija įkelta",
"ToastBatchUpdateFailed": "Masinis atnaujinimas nepavyko",
"ToastBatchUpdateSuccess": "Masinis atnaujinimas sėkmingas",
"ToastBookmarkCreateFailed": "Žymos sukurti nepavyko",
"ToastBookmarkCreateSuccess": "Žyma pridėta",
"ToastBookmarkRemoveFailed": "Žymos pašalinti nepavyko",
"ToastBookmarkRemoveSuccess": "Žyma pašalinta",
"ToastBookmarkUpdateFailed": "Žymos atnaujinti nepavyko",
"ToastBookmarkUpdateSuccess": "Žyma atnaujinta",
"ToastChaptersHaveErrors": "Skyriai turi klaidų",
"ToastChaptersMustHaveTitles": "Skyriai turi turėti pavadinimus",
"ToastCollectionItemsRemoveFailed": "Elementų pašalinti iš kolekcijos nepavyko",
"ToastCollectionItemsRemoveSuccess": "Elementai pašalinti iš kolekcijos",
"ToastCollectionRemoveFailed": "Kolekcijos pašalinti nepavyko",
"ToastCollectionRemoveSuccess": "Kolekcija pašalinta",
"ToastCollectionUpdateFailed": "Kolekcijos atnaujinti nepavyko",
"ToastCollectionUpdateSuccess": "Kolekcija atnaujinta",
"ToastItemCoverUpdateFailed": "Elemento viršelio atnaujinti nepavyko",
"ToastItemCoverUpdateSuccess": "Elemento viršelis atnaujintas",
"ToastItemDetailsUpdateFailed": "Elemento detalių atnaujinti nepavyko",
"ToastItemDetailsUpdateSuccess": "Elemento detalės atnaujintos",
"ToastItemDetailsUpdateUnneeded": "Elemento detalės atnaujinimas nereikalingas",
"ToastItemMarkedAsFinishedFailed": "Pažymėti kaip Baigta nepavyko",
"ToastItemMarkedAsFinishedSuccess": "Elementas pažymėtas kaip Baigta",
"ToastItemMarkedAsNotFinishedFailed": "Pažymėti kaip Nebaigta nepavyko",
"ToastItemMarkedAsNotFinishedSuccess": "Elementas pažymėtas kaip Nebaigta",
"ToastLibraryCreateFailed": "Bibliotekos sukurti nepavyko",
"ToastLibraryCreateSuccess": "Biblioteka \"{0}\" sukurta",
"ToastLibraryDeleteFailed": "Bibliotekos ištrinti nepavyko",
"ToastLibraryDeleteSuccess": "Biblioteka ištrinta",
"ToastLibraryScanFailedToStart": "Nepavyko pradėti bibliotekos skenavimo",
"ToastLibraryScanStarted": "Bibliotekos skenavimas pradėtas",
"ToastLibraryUpdateFailed": "Bibliotekos atnaujinti nepavyko",
"ToastLibraryUpdateSuccess": "Biblioteka \"{0}\" atnaujinta",
"ToastPlaylistCreateFailed": "Grojaraščio sukurti nepavyko",
"ToastPlaylistCreateSuccess": "Grojaraštis sukurtas",
"ToastPlaylistRemoveFailed": "Grojaraščio pašalinti nepavyko",
"ToastPlaylistRemoveSuccess": "Grojaraštis pašalintas",
"ToastPlaylistUpdateFailed": "Grojaraščio atnaujinti nepavyko",
"ToastPlaylistUpdateSuccess": "Grojaraštis atnaujintas",
"ToastPodcastCreateFailed": "Tinklalaidės sukurti nepavyko",
"ToastPodcastCreateSuccess": "Tinklalaidė sėkmingai sukurta",
"ToastRemoveItemFromCollectionFailed": "Elemento pašalinti iš kolekcijos nepavyko",
"ToastRemoveItemFromCollectionSuccess": "Elementas pašalintas iš kolekcijos",
"ToastRSSFeedCloseFailed": "RSS srauto uždaryti nepavyko",
"ToastRSSFeedCloseSuccess": "RSS srautas uždarytas",
"ToastSendEbookToDeviceFailed": "Nepavyko nusiųsti e-knygos į įrenginį",
"ToastSendEbookToDeviceSuccess": "E-knyga išsiųsta į įrenginį \"{0}\"",
"ToastSeriesUpdateFailed": "Serijos atnaujinti nepavyko",
"ToastSeriesUpdateSuccess": "Serijos atnaujintos",
"ToastSessionDeleteFailed": "Sesijos ištrinti nepavyko",
"ToastSessionDeleteSuccess": "Sesija ištrinta",
"ToastSocketConnected": "Serveris prijungtas",
"ToastSocketDisconnected": "Severis atjungtas",
"ToastSocketFailedToConnect": "Nepavyko prisijungti prie serverio",
"ToastUserDeleteFailed": "Nepavyko ištrinti naudotojo",
"ToastUserDeleteSuccess": "Naudotojas ištrintas"
}
+90 -54
View File
@@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Toevoegen", "ButtonAdd": "Toevoegen",
"ButtonAddChapters": "Hoofdstukken toevoegen", "ButtonAddChapters": "Hoofdstukken toevoegen",
"ButtonAddDevice": "Add Device",
"ButtonAddLibrary": "Add Library",
"ButtonAddPodcasts": "Podcasts toevoegen", "ButtonAddPodcasts": "Podcasts toevoegen",
"ButtonAddUser": "Add User",
"ButtonAddYourFirstLibrary": "Voeg je eerste bibliotheek toe", "ButtonAddYourFirstLibrary": "Voeg je eerste bibliotheek toe",
"ButtonApply": "Pas toe", "ButtonApply": "Pas toe",
"ButtonApplyChapters": "Hoofdstukken toepassen", "ButtonApplyChapters": "Hoofdstukken toepassen",
@@ -59,6 +62,7 @@
"ButtonRemoveSeriesFromContinueSeries": "Verwijder serie uit Serie vervolgen", "ButtonRemoveSeriesFromContinueSeries": "Verwijder serie uit Serie vervolgen",
"ButtonReScan": "Nieuwe scan", "ButtonReScan": "Nieuwe scan",
"ButtonReset": "Reset", "ButtonReset": "Reset",
"ButtonResetToDefault": "Reset to default",
"ButtonRestore": "Herstel", "ButtonRestore": "Herstel",
"ButtonSave": "Opslaan", "ButtonSave": "Opslaan",
"ButtonSaveAndClose": "Opslaan & sluiten", "ButtonSaveAndClose": "Opslaan & sluiten",
@@ -88,6 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen", "HeaderAppriseNotificationSettings": "Apprise-notificatie instellingen",
"HeaderAudiobookTools": "Audioboekbestandbeheer tools", "HeaderAudiobookTools": "Audioboekbestandbeheer tools",
"HeaderAudioTracks": "Audiotracks", "HeaderAudioTracks": "Audiotracks",
"HeaderAuthentication": "Authentication",
"HeaderBackups": "Back-ups", "HeaderBackups": "Back-ups",
"HeaderChangePassword": "Wachtwoord wijzigen", "HeaderChangePassword": "Wachtwoord wijzigen",
"HeaderChapters": "Hoofdstukken", "HeaderChapters": "Hoofdstukken",
@@ -99,11 +104,11 @@
"HeaderDetails": "Details", "HeaderDetails": "Details",
"HeaderDownloadQueue": "Download-wachtrij", "HeaderDownloadQueue": "Download-wachtrij",
"HeaderEbookFiles": "Ebook Files", "HeaderEbookFiles": "Ebook Files",
"HeaderEmail": "Email", "HeaderEmail": "E-mail",
"HeaderEmailSettings": "Email Settings", "HeaderEmailSettings": "E-mail instellingen",
"HeaderEpisodes": "Afleveringen", "HeaderEpisodes": "Afleveringen",
"HeaderEreaderDevices": "Ereader Devices", "HeaderEreaderDevices": "Ereader-apparaten",
"HeaderEreaderSettings": "Ereader Settings", "HeaderEreaderSettings": "Ereader-instellingen",
"HeaderFiles": "Bestanden", "HeaderFiles": "Bestanden",
"HeaderFindChapters": "Zoek hoofdstukken", "HeaderFindChapters": "Zoek hoofdstukken",
"HeaderIgnoredFiles": "Genegeerde bestanden", "HeaderIgnoredFiles": "Genegeerde bestanden",
@@ -122,12 +127,15 @@
"HeaderManageTags": "Tags beheren", "HeaderManageTags": "Tags beheren",
"HeaderMapDetails": "Map details", "HeaderMapDetails": "Map details",
"HeaderMatch": "Match", "HeaderMatch": "Match",
"HeaderMetadataOrderOfPrecedence": "Metadata order of precedence",
"HeaderMetadataToEmbed": "In te sluiten metadata", "HeaderMetadataToEmbed": "In te sluiten metadata",
"HeaderNewAccount": "Nieuwe account", "HeaderNewAccount": "Nieuwe account",
"HeaderNewLibrary": "Nieuwe bibliotheek", "HeaderNewLibrary": "Nieuwe bibliotheek",
"HeaderNotifications": "Notificaties", "HeaderNotifications": "Notificaties",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS-feed", "HeaderOpenRSSFeed": "Open RSS-feed",
"HeaderOtherFiles": "Andere bestanden", "HeaderOtherFiles": "Andere bestanden",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Toestemmingen", "HeaderPermissions": "Toestemmingen",
"HeaderPlayerQueue": "Afspeelwachtrij", "HeaderPlayerQueue": "Afspeelwachtrij",
"HeaderPlaylist": "Afspeellijst", "HeaderPlaylist": "Afspeellijst",
@@ -138,6 +146,7 @@
"HeaderRemoveEpisodes": "Verwijder {0} afleveringen", "HeaderRemoveEpisodes": "Verwijder {0} afleveringen",
"HeaderRSSFeedGeneral": "RSS-details", "HeaderRSSFeedGeneral": "RSS-details",
"HeaderRSSFeedIsOpen": "RSS-feed is open", "HeaderRSSFeedIsOpen": "RSS-feed is open",
"HeaderRSSFeeds": "RSS-feeds",
"HeaderSavedMediaProgress": "Opgeslagen mediavoortgang", "HeaderSavedMediaProgress": "Opgeslagen mediavoortgang",
"HeaderSchedule": "Schema", "HeaderSchedule": "Schema",
"HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans", "HeaderScheduleLibraryScans": "Schema automatische bibliotheekscans",
@@ -155,7 +164,7 @@
"HeaderStatsRecentSessions": "Recente sessies", "HeaderStatsRecentSessions": "Recente sessies",
"HeaderStatsTop10Authors": "Top 10 auteurs", "HeaderStatsTop10Authors": "Top 10 auteurs",
"HeaderStatsTop5Genres": "Top 5 genres", "HeaderStatsTop5Genres": "Top 5 genres",
"HeaderTableOfContents": "Table of Contents", "HeaderTableOfContents": "Inhoudsopgave",
"HeaderTools": "Tools", "HeaderTools": "Tools",
"HeaderUpdateAccount": "Account bijwerken", "HeaderUpdateAccount": "Account bijwerken",
"HeaderUpdateAuthor": "Auteur bijwerken", "HeaderUpdateAuthor": "Auteur bijwerken",
@@ -175,16 +184,24 @@
"LabelAddToCollectionBatch": "{0} boeken toevoegen aan collectie", "LabelAddToCollectionBatch": "{0} boeken toevoegen aan collectie",
"LabelAddToPlaylist": "Toevoegen aan afspeellijst", "LabelAddToPlaylist": "Toevoegen aan afspeellijst",
"LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst", "LabelAddToPlaylistBatch": "{0} onderdelen toevoegen aan afspeellijst",
"LabelAdminUsersOnly": "Admin users only",
"LabelAll": "Alle", "LabelAll": "Alle",
"LabelAllUsers": "Alle gebruikers", "LabelAllUsers": "Alle gebruikers",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAlreadyInYourLibrary": "Reeds in je bibliotheek", "LabelAlreadyInYourLibrary": "Reeds in je bibliotheek",
"LabelAppend": "Append", "LabelAppend": "Achteraan toevoegen",
"LabelAuthor": "Auteur", "LabelAuthor": "Auteur",
"LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)", "LabelAuthorFirstLast": "Auteur (Voornaam Achternaam)",
"LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)", "LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)",
"LabelAuthors": "Auteurs", "LabelAuthors": "Auteurs",
"LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden", "LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Terug naar gebruiker", "LabelBackToUser": "Terug naar gebruiker",
"LabelBackupLocation": "Back-up locatie",
"LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen", "LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen",
"LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Back-ups opgeslagen in /metadata/backups",
"LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB)", "LabelBackupsMaxBackupSize": "Maximale back-up-grootte (in GB)",
@@ -193,19 +210,22 @@
"LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.", "LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.",
"LabelBitrate": "Bitrate", "LabelBitrate": "Bitrate",
"LabelBooks": "Boeken", "LabelBooks": "Boeken",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Wachtwoord wijzigen", "LabelChangePassword": "Wachtwoord wijzigen",
"LabelChannels": "Kanalen", "LabelChannels": "Kanalen",
"LabelChapters": "Hoofdstukken", "LabelChapters": "Hoofdstukken",
"LabelChaptersFound": "Hoofdstukken gevonden", "LabelChaptersFound": "Hoofdstukken gevonden",
"LabelChapterTitle": "Hoofdstuktitel", "LabelChapterTitle": "Hoofdstuktitel",
"LabelClickForMoreInfo": "Click for more info",
"LabelClosePlayer": "Sluit speler", "LabelClosePlayer": "Sluit speler",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Series inklappen", "LabelCollapseSeries": "Series inklappen",
"LabelCollection": "Collection",
"LabelCollections": "Collecties", "LabelCollections": "Collecties",
"LabelComplete": "Compleet", "LabelComplete": "Compleet",
"LabelConfirmPassword": "Bevestig wachtwoord", "LabelConfirmPassword": "Bevestig wachtwoord",
"LabelContinueListening": "Verder luisteren", "LabelContinueListening": "Verder luisteren",
"LabelContinueReading": "Continue Reading", "LabelContinueReading": "Verder luisteren",
"LabelContinueSeries": "Ga verder met serie", "LabelContinueSeries": "Ga verder met serie",
"LabelCover": "Cover", "LabelCover": "Cover",
"LabelCoverImageURL": "Coverafbeelding URL", "LabelCoverImageURL": "Coverafbeelding URL",
@@ -215,13 +235,16 @@
"LabelCurrently": "Op dit moment:", "LabelCurrently": "Op dit moment:",
"LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:", "LabelCustomCronExpression": "Aangepaste Cron-uitdrukking:",
"LabelDatetime": "Datum-tijd", "LabelDatetime": "Datum-tijd",
"LabelDeleteFromFileSystemCheckbox": "Delete from file system (uncheck to only remove from database)",
"LabelDescription": "Beschrijving", "LabelDescription": "Beschrijving",
"LabelDeselectAll": "Deselecteer alle", "LabelDeselectAll": "Deselecteer alle",
"LabelDevice": "Apparaat", "LabelDevice": "Apparaat",
"LabelDeviceInfo": "Apparaat info", "LabelDeviceInfo": "Apparaat info",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDirectory": "Map", "LabelDirectory": "Map",
"LabelDiscFromFilename": "Schijf uit bestandsnaam", "LabelDiscFromFilename": "Schijf uit bestandsnaam",
"LabelDiscFromMetadata": "Schijf uit metadata", "LabelDiscFromMetadata": "Schijf uit metadata",
"LabelDiscover": "Ontdek",
"LabelDownload": "Download", "LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episodes", "LabelDownloadNEpisodes": "Download {0} episodes",
"LabelDuration": "Duur", "LabelDuration": "Duur",
@@ -230,10 +253,10 @@
"LabelEbooks": "Ebooks", "LabelEbooks": "Ebooks",
"LabelEdit": "Wijzig", "LabelEdit": "Wijzig",
"LabelEmail": "Email", "LabelEmail": "Email",
"LabelEmailSettingsFromAddress": "From Address", "LabelEmailSettingsFromAddress": "Van-adres",
"LabelEmailSettingsSecure": "Secure", "LabelEmailSettingsSecure": "Veilig",
"LabelEmailSettingsSecureHelp": "If true the connection will use TLS when connecting to server. If false then TLS is used if server supports the STARTTLS extension. In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false. (from nodemailer.com/smtp/#authentication)", "LabelEmailSettingsSecureHelp": "Als 'waar', dan gebruikt de verbinding TLS om met de server te verbinden. Als 'onwaar', dan wordt TLS gebruikt als de server de STARTTLS-extensie ondersteunt. In de meeste gevallen kies je voor 'waar' verbindt met poort 465. Voo poort 587 of 25, laat op 'onwaar'. (van nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Test Address", "LabelEmailSettingsTestAddress": "Test-adres",
"LabelEmbeddedCover": "Ingesloten cover", "LabelEmbeddedCover": "Ingesloten cover",
"LabelEnable": "Inschakelen", "LabelEnable": "Inschakelen",
"LabelEnd": "Einde", "LabelEnd": "Einde",
@@ -252,16 +275,19 @@
"LabelFinished": "Voltooid", "LabelFinished": "Voltooid",
"LabelFolder": "Map", "LabelFolder": "Map",
"LabelFolders": "Mappen", "LabelFolders": "Mappen",
"LabelFontScale": "Font scale", "LabelFontFamily": "Lettertypefamilie",
"LabelFormat": "Format", "LabelFontScale": "Lettertype schaal",
"LabelFormat": "Formaat",
"LabelGenre": "Genre", "LabelGenre": "Genre",
"LabelGenres": "Genres", "LabelGenres": "Genres",
"LabelHardDeleteFile": "Hard-delete bestand", "LabelHardDeleteFile": "Hard-delete bestand",
"LabelHasEbook": "Has ebook", "LabelHasEbook": "Heeft ebook",
"LabelHasSupplementaryEbook": "Has supplementary ebook", "LabelHasSupplementaryEbook": "Heeft supplementair ebook",
"LabelHighestPriority": "Highest priority",
"LabelHost": "Host", "LabelHost": "Host",
"LabelHour": "Uur", "LabelHour": "Uur",
"LabelIcon": "Icoon", "LabelIcon": "Icoon",
"LabelImageURLFromTheWeb": "Image URL from the web",
"LabelIncludeInTracklist": "Includeer in tracklijst", "LabelIncludeInTracklist": "Includeer in tracklijst",
"LabelIncomplete": "Incompleet", "LabelIncomplete": "Incompleet",
"LabelInProgress": "Bezig", "LabelInProgress": "Bezig",
@@ -285,22 +311,26 @@
"LabelLastTime": "Laatste keer", "LabelLastTime": "Laatste keer",
"LabelLastUpdate": "Laatste update", "LabelLastUpdate": "Laatste update",
"LabelLayout": "Layout", "LabelLayout": "Layout",
"LabelLayoutSinglePage": "Single page", "LabelLayoutSinglePage": "Enkele pagina",
"LabelLayoutSplitPage": "Split page", "LabelLayoutSplitPage": "Gesplitste pagina",
"LabelLess": "Minder", "LabelLess": "Minder",
"LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken", "LabelLibrariesAccessibleToUser": "Voor gebruiker toegankelijke bibliotheken",
"LabelLibrary": "Bibliotheek", "LabelLibrary": "Bibliotheek",
"LabelLibraryItem": "Library Item", "LabelLibraryItem": "Bibliotheekonderdeel",
"LabelLibraryName": "Library Name", "LabelLibraryName": "Bibliotheeknaam",
"LabelLimit": "Limiet", "LabelLimit": "Limiet",
"LabelLineSpacing": "Line spacing", "LabelLineSpacing": "Regelruimte",
"LabelListenAgain": "Luister opnieuw", "LabelListenAgain": "Luister opnieuw",
"LabelLogLevelDebug": "Debug", "LabelLogLevelDebug": "Debug",
"LabelLogLevelInfo": "Info", "LabelLogLevelInfo": "Info",
"LabelLogLevelWarn": "Waarschuwing", "LabelLogLevelWarn": "Waarschuwing",
"LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum", "LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Mediaspeler", "LabelMediaPlayer": "Mediaspeler",
"LabelMediaType": "Mediatype", "LabelMediaType": "Mediatype",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
"LabelMetadataProvider": "Metadatabron", "LabelMetadataProvider": "Metadatabron",
"LabelMetaTag": "Meta-tag", "LabelMetaTag": "Meta-tag",
"LabelMetaTags": "Meta-tags", "LabelMetaTags": "Meta-tags",
@@ -318,7 +348,7 @@
"LabelNewPassword": "Nieuw wachtwoord", "LabelNewPassword": "Nieuw wachtwoord",
"LabelNextBackupDate": "Volgende back-up datum", "LabelNextBackupDate": "Volgende back-up datum",
"LabelNextScheduledRun": "Volgende geplande run", "LabelNextScheduledRun": "Volgende geplande run",
"LabelNoEpisodesSelected": "No episodes selected", "LabelNoEpisodesSelected": "Geen afleveringen geselecteerd",
"LabelNotes": "Notities", "LabelNotes": "Notities",
"LabelNotFinished": "Niet Voltooid", "LabelNotFinished": "Niet Voltooid",
"LabelNotificationAppriseURL": "Apprise URL(s)", "LabelNotificationAppriseURL": "Apprise URL(s)",
@@ -350,18 +380,18 @@
"LabelPodcast": "Podcast", "LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasts", "LabelPodcasts": "Podcasts",
"LabelPodcastType": "Podcasttype", "LabelPodcastType": "Podcasttype",
"LabelPort": "Port", "LabelPort": "Poort",
"LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)", "LabelPrefixesToIgnore": "Te negeren voorzetsels (ongeacht hoofdlettergebruik)",
"LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen", "LabelPreventIndexing": "Voorkom indexering van je feed door iTunes- en Google podcastmappen",
"LabelPrimaryEbook": "Primary ebook", "LabelPrimaryEbook": "Primair ebook",
"LabelProgress": "Voortgang", "LabelProgress": "Voortgang",
"LabelProvider": "Bron", "LabelProvider": "Bron",
"LabelPubDate": "Publicatiedatum", "LabelPubDate": "Publicatiedatum",
"LabelPublisher": "Uitgever", "LabelPublisher": "Uitgever",
"LabelPublishYear": "Jaar van uitgave", "LabelPublishYear": "Jaar van uitgave",
"LabelRead": "Read", "LabelRead": "Lees",
"LabelReadAgain": "Read Again", "LabelReadAgain": "Lees opnieuw",
"LabelReadEbookWithoutProgress": "Read ebook without keeping progress", "LabelReadEbookWithoutProgress": "Lees ebook zonder voortgang bij te houden",
"LabelRecentlyAdded": "Recent toegevoegd", "LabelRecentlyAdded": "Recent toegevoegd",
"LabelRecentSeries": "Recente series", "LabelRecentSeries": "Recente series",
"LabelRecommended": "Aangeraden", "LabelRecommended": "Aangeraden",
@@ -378,41 +408,39 @@
"LabelSearchTitle": "Zoek titel", "LabelSearchTitle": "Zoek titel",
"LabelSearchTitleOrASIN": "Zoek titel of ASIN", "LabelSearchTitleOrASIN": "Zoek titel of ASIN",
"LabelSeason": "Seizoen", "LabelSeason": "Seizoen",
"LabelSelectAllEpisodes": "Select all episodes", "LabelSelectAllEpisodes": "Selecteer alle afleveringen",
"LabelSelectEpisodesShowing": "Select {0} episodes showing", "LabelSelectEpisodesShowing": "Selecteer {0} afleveringen laten zien",
"LabelSendEbookToDevice": "Send Ebook to...", "LabelSelectUsers": "Select users",
"LabelSendEbookToDevice": "Stuur ebook naar...",
"LabelSequence": "Sequentie", "LabelSequence": "Sequentie",
"LabelSeries": "Serie", "LabelSeries": "Serie",
"LabelSeriesName": "Naam serie", "LabelSeriesName": "Naam serie",
"LabelSeriesProgress": "Voortgang serie", "LabelSeriesProgress": "Voortgang serie",
"LabelSetEbookAsPrimary": "Set as primary", "LabelSetEbookAsPrimary": "Stel in als primair",
"LabelSetEbookAsSupplementary": "Set as supplementary", "LabelSetEbookAsSupplementary": "Stel in als supplementair",
"LabelSettingsAudiobooksOnly": "Audiobooks only", "LabelSettingsAudiobooksOnly": "Alleen audiobooks",
"LabelSettingsAudiobooksOnlyHelp": "Enabling this setting will ignore ebook files unless they are inside an audiobook folder in which case they will be set as supplementary ebooks", "LabelSettingsAudiobooksOnlyHelp": "Deze instelling inschakelen zorgt ervoor dat ebook-bestanden genegeerd worden tenzij ze in een audiobook-map staan, in welk geval ze worden ingesteld als supplementaire ebooks",
"LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken", "LabelSettingsBookshelfViewHelp": "Skeumorphisch design met houten planken",
"LabelSettingsChromecastSupport": "Chromecast support", "LabelSettingsChromecastSupport": "Chromecast support",
"LabelSettingsDateFormat": "Datum format", "LabelSettingsDateFormat": "Datum format",
"LabelSettingsDisableWatcher": "Watcher uitschakelen", "LabelSettingsDisableWatcher": "Watcher uitschakelen",
"LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen", "LabelSettingsDisableWatcherForLibrary": "Map-watcher voor bibliotheek uitschakelen",
"LabelSettingsDisableWatcherHelp": "Schakelt het automatisch toevoegen/bijwerken van onderdelen wanneer bestandswijzigingen gedetecteerd zijn uit. *Vereist herstart server", "LabelSettingsDisableWatcherHelp": "Schakelt het automatisch toevoegen/bijwerken van onderdelen wanneer bestandswijzigingen gedetecteerd zijn uit. *Vereist herstart server",
"LabelSettingsEnableWatcher": "Watcher inschakelen",
"LabelSettingsEnableWatcherForLibrary": "Map-watcher voor bibliotheek inschakelen",
"LabelSettingsEnableWatcherHelp": "Zorgt voor het automatisch toevoegen/bijwerken van onderdelen als bestandswijzigingen worden gedetecteerd. *Vereist herstarten van server",
"LabelSettingsExperimentalFeatures": "Experimentele functies", "LabelSettingsExperimentalFeatures": "Experimentele functies",
"LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.", "LabelSettingsExperimentalFeaturesHelp": "Functies in ontwikkeling die je feedback en testing kunnen gebruiken. Klik om de Github-discussie te openen.",
"LabelSettingsFindCovers": "Zoek covers", "LabelSettingsFindCovers": "Zoek covers",
"LabelSettingsFindCoversHelp": "Als je audioboek geen ingesloten cover of cover in de map heeft, zal de scanner proberen een cover te vinden.<br>Opmerking: Dit zal de scan-duur verlengen", "LabelSettingsFindCoversHelp": "Als je audioboek geen ingesloten cover of cover in de map heeft, zal de scanner proberen een cover te vinden.<br>Opmerking: Dit zal de scan-duur verlengen",
"LabelSettingsHideSingleBookSeries": "Hide single book series", "LabelSettingsHideSingleBookSeries": "Verberg series met een enkel boek",
"LabelSettingsHideSingleBookSeriesHelp": "Series that have a single book will be hidden from the series page and home page shelves.", "LabelSettingsHideSingleBookSeriesHelp": "Series die slechts een enkel boek bevatten worden verborgen op de seriespagina en de homepagina-planken.",
"LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina", "LabelSettingsHomePageBookshelfView": "Boekenplank-view voor homepagina",
"LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek", "LabelSettingsLibraryBookshelfView": "Boekenplank-view voor bibliotheek",
"LabelSettingsOverdriveMediaMarkers": "Gebruik Overdrive media markers voor hoofdstukken",
"LabelSettingsOverdriveMediaMarkersHelp": "MP3-bestanden van Overdrive hebben hoofdstuktiming ingesloten als custom ingesloten metadata. Door dit in te schakelen worden deze tags voor hoofdstuktiming automatisch gebruikt.",
"LabelSettingsParseSubtitles": "Parseer subtitel", "LabelSettingsParseSubtitles": "Parseer subtitel",
"LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"", "LabelSettingsParseSubtitlesHelp": "Haal subtitels uit mapnaam van audioboek.<br>Subtitel moet gescheiden zijn met \" - \"<br>b.v. \"Boektitel - Een Subtitel Hier\" heeft als subtitel \"Een Subtitel Hier\"",
"LabelSettingsPreferAudioMetadata": "Prefereer audio-metadata",
"LabelSettingsPreferAudioMetadataHelp": "Audiobestand ID3 metatags zullen worden gebruikt voor boekdetails in plaats van mapnamen",
"LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata", "LabelSettingsPreferMatchedMetadata": "Prefereer gematchte metadata",
"LabelSettingsPreferMatchedMetadataHelp": "Gematchte data zal onderdeeldetails overschrijven bij gebruik van Quick Match. Standaard vult Quick Match uitsluitend ontbrekende details aan.", "LabelSettingsPreferMatchedMetadataHelp": "Gematchte data zal onderdeeldetails overschrijven bij gebruik van Quick Match. Standaard vult Quick Match uitsluitend ontbrekende details aan.",
"LabelSettingsPreferOPFMetadata": "Prefereer OPF-metadata",
"LabelSettingsPreferOPFMetadataHelp": "OPF-bestand metadata zal worden gebruik in plaats van mapnamen",
"LabelSettingsSkipMatchingBooksWithASIN": "Sla matchen van boeken over die al over een ASIN beschikken", "LabelSettingsSkipMatchingBooksWithASIN": "Sla matchen van boeken over die al over een ASIN beschikken",
"LabelSettingsSkipMatchingBooksWithISBN": "Sla matchen van boeken over die al over een ISBN beschikken", "LabelSettingsSkipMatchingBooksWithISBN": "Sla matchen van boeken over die al over een ISBN beschikken",
"LabelSettingsSortingIgnorePrefixes": "Negeer voorvoegsels bij sorteren", "LabelSettingsSortingIgnorePrefixes": "Negeer voorvoegsels bij sorteren",
@@ -422,11 +450,12 @@
"LabelSettingsStoreCoversWithItem": "Bewaar covers bij onderdeel", "LabelSettingsStoreCoversWithItem": "Bewaar covers bij onderdeel",
"LabelSettingsStoreCoversWithItemHelp": "Standaard worden covers bewaard in /metadata/items, door deze instelling in te schakelen zullen covers in de map van je bibliotheekonderdeel bewaard worden. Slechts een bestand genaamd \"cover\" zal worden bewaard", "LabelSettingsStoreCoversWithItemHelp": "Standaard worden covers bewaard in /metadata/items, door deze instelling in te schakelen zullen covers in de map van je bibliotheekonderdeel bewaard worden. Slechts een bestand genaamd \"cover\" zal worden bewaard",
"LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel", "LabelSettingsStoreMetadataWithItem": "Bewaar metadata bij onderdeel",
"LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden. Gebruikt .abs-extensie", "LabelSettingsStoreMetadataWithItemHelp": "Standaard worden metadata-bestanden bewaard in /metadata/items, door deze instelling in te schakelen zullen metadata bestanden in de map van je bibliotheekonderdeel bewaard worden",
"LabelSettingsTimeFormat": "Tijdformat", "LabelSettingsTimeFormat": "Tijdformat",
"LabelShowAll": "Toon alle", "LabelShowAll": "Toon alle",
"LabelSize": "Grootte", "LabelSize": "Grootte",
"LabelSleepTimer": "Slaaptimer", "LabelSleepTimer": "Slaaptimer",
"LabelSlug": "Slug",
"LabelStart": "Start", "LabelStart": "Start",
"LabelStarted": "Gestart", "LabelStarted": "Gestart",
"LabelStartedAt": "Gestart op", "LabelStartedAt": "Gestart op",
@@ -453,9 +482,9 @@
"LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker", "LabelTagsAccessibleToUser": "Tags toegankelijk voor de gebruiker",
"LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker", "LabelTagsNotAccessibleToUser": "Tags niet toegankelijk voor de gebruiker",
"LabelTasks": "Lopende taken", "LabelTasks": "Lopende taken",
"LabelTheme": "Theme", "LabelTheme": "Thema",
"LabelThemeDark": "Dark", "LabelThemeDark": "Donker",
"LabelThemeLight": "Light", "LabelThemeLight": "Licht",
"LabelTimeBase": "Tijdsbasis", "LabelTimeBase": "Tijdsbasis",
"LabelTimeListened": "Tijd geluisterd", "LabelTimeListened": "Tijd geluisterd",
"LabelTimeListenedToday": "Tijd geluisterd vandaag", "LabelTimeListenedToday": "Tijd geluisterd vandaag",
@@ -474,7 +503,8 @@
"LabelTrackFromMetadata": "Track vanuit metadata", "LabelTrackFromMetadata": "Track vanuit metadata",
"LabelTracks": "Tracks", "LabelTracks": "Tracks",
"LabelTracksMultiTrack": "Multi-track", "LabelTracksMultiTrack": "Multi-track",
"LabelTracksSingleTrack": "Single-track", "LabelTracksNone": "Geen tracks",
"LabelTracksSingleTrack": "Enkele track",
"LabelType": "Type", "LabelType": "Type",
"LabelUnabridged": "Onverkort", "LabelUnabridged": "Onverkort",
"LabelUnknown": "Onbekend", "LabelUnknown": "Onbekend",
@@ -514,16 +544,21 @@
"MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk", "MessageChapterErrorStartLtPrev": "Ongeldig: starttijd moet be groter zijn dan of equal aan starttijd van vorig hoofdstuk",
"MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek", "MessageChapterStartIsAfter": "Start van hoofdstuk is na het einde van je audioboek",
"MessageCheckingCron": "Cron aan het checken...", "MessageCheckingCron": "Cron aan het checken...",
"MessageConfirmCloseFeed": "Are you sure you want to close this feed?",
"MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?", "MessageConfirmDeleteBackup": "Weet je zeker dat je de backup voor {0} wil verwijderen?",
"MessageConfirmDeleteFile": "This will delete the file from your file system. Are you sure?", "MessageConfirmDeleteFile": "Dit verwijdert het bestand uit het bestandssysteem. Weet je het zeker?",
"MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?", "MessageConfirmDeleteLibrary": "Weet je zeker dat je de bibliotheek \"{0}\" permanent wil verwijderen?",
"MessageConfirmDeleteLibraryItem": "This will delete the library item from the database and your file system. Are you sure?",
"MessageConfirmDeleteLibraryItems": "This will delete {0} library items from the database and your file system. Are you sure?",
"MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?", "MessageConfirmDeleteSession": "Weet je zeker dat je deze sessie wil verwijderen?",
"MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?", "MessageConfirmForceReScan": "Weet je zeker dat je geforceerd opnieuw wil scannen?",
"MessageConfirmMarkAllEpisodesFinished": "Are you sure you want to mark all episodes as finished?", "MessageConfirmMarkAllEpisodesFinished": "Weet je zeker dat je alle afleveringen als voltooid wil markeren?",
"MessageConfirmMarkAllEpisodesNotFinished": "Are you sure you want to mark all episodes as not finished?", "MessageConfirmMarkAllEpisodesNotFinished": "Weet je zeker dat je alle afleveringen als niet-voltooid wil markeren?",
"MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?", "MessageConfirmMarkSeriesFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als voltooid?",
"MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?", "MessageConfirmMarkSeriesNotFinished": "Weet je zeker dat je alle boeken in deze serie wil markeren als niet voltooid?",
"MessageConfirmQuickEmbed": "Warning! Quick embed will not backup your audio files. Make sure that you have a backup of your audio files. <br><br>Would you like to continue?",
"MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?", "MessageConfirmRemoveAllChapters": "Weet je zeker dat je alle hoofdstukken wil verwijderen?",
"MessageConfirmRemoveAuthor": "Weet je zeker dat je auteur \"{0}\" wil verwijderen?",
"MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?", "MessageConfirmRemoveCollection": "Weet je zeker dat je de collectie \"{0}\" wil verwijderen?",
"MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?", "MessageConfirmRemoveEpisode": "Weet je zeker dat je de aflevering \"{0}\" wil verwijderen?",
"MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?", "MessageConfirmRemoveEpisodes": "Weet je zeker dat je {0} afleveringen wil verwijderen?",
@@ -535,7 +570,8 @@
"MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?", "MessageConfirmRenameTag": "Weet je zeker dat je tag \"{0}\" wil hernoemen naar\"{1}\" voor alle onderdelen?",
"MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.", "MessageConfirmRenameTagMergeNote": "Opmerking: Deze tag bestaat al, dus zullen ze worden samengevoegd.",
"MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".", "MessageConfirmRenameTagWarning": "Waarschuwing! Een gelijknamige tag met ander hoofdlettergebruik bestaat al: \"{0}\".",
"MessageConfirmSendEbookToDevice": "Are you sure you want to send {0} ebook \"{1}\" to device \"{2}\"?", "MessageConfirmReScanLibraryItems": "Are you sure you want to re-scan {0} items?",
"MessageConfirmSendEbookToDevice": "Weet je zeker dat je {0} ebook \"{1}\" naar apparaat \"{2}\" wil sturen?",
"MessageDownloadingEpisode": "Aflevering aan het dowloaden", "MessageDownloadingEpisode": "Aflevering aan het dowloaden",
"MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde", "MessageDragFilesIntoTrackOrder": "Sleep bestanden in de juiste trackvolgorde",
"MessageEmbedFinished": "Insluiting voltooid!", "MessageEmbedFinished": "Insluiting voltooid!",
@@ -554,8 +590,8 @@
"MessageM4BFailed": "M4B mislukt!", "MessageM4BFailed": "M4B mislukt!",
"MessageM4BFinished": "M4B voltooid!", "MessageM4BFinished": "M4B voltooid!",
"MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden", "MessageMapChapterTitles": "Map hoofdstuktitels naar je bestaande audioboekhoofdstukken zonder aanpassing van tijden",
"MessageMarkAllEpisodesFinished": "Mark all episodes finished", "MessageMarkAllEpisodesFinished": "Markeer alle afleveringen als voltooid",
"MessageMarkAllEpisodesNotFinished": "Mark all episodes not finished", "MessageMarkAllEpisodesNotFinished": "Markeer alle afleveringen als niet voltooid",
"MessageMarkAsFinished": "Markeer als Voltooid", "MessageMarkAsFinished": "Markeer als Voltooid",
"MessageMarkAsNotFinished": "Markeer als Niet Voltooid", "MessageMarkAsNotFinished": "Markeer als Niet Voltooid",
"MessageMatchBooksDescription": "zal proberen boeken in de bibliotheek te matchen met een boek uit de geselecteerde bron en lege details en coverafbeelding te vullen. Overschrijft details niet.", "MessageMatchBooksDescription": "zal proberen boeken in de bibliotheek te matchen met een boek uit de geselecteerde bron en lege details en coverafbeelding te vullen. Overschrijft details niet.",
@@ -691,8 +727,8 @@
"ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie", "ToastRemoveItemFromCollectionSuccess": "Onderdeel verwijderd uit collectie",
"ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt", "ToastRSSFeedCloseFailed": "Sluiten RSS-feed mislukt",
"ToastRSSFeedCloseSuccess": "RSS-feed gesloten", "ToastRSSFeedCloseSuccess": "RSS-feed gesloten",
"ToastSendEbookToDeviceFailed": "Failed to Send Ebook to device", "ToastSendEbookToDeviceFailed": "Ebook naar apparaat sturen mislukt",
"ToastSendEbookToDeviceSuccess": "Ebook sent to device \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook verstuurd naar apparaat \"{0}\"",
"ToastSeriesUpdateFailed": "Bijwerken serie mislukt", "ToastSeriesUpdateFailed": "Bijwerken serie mislukt",
"ToastSeriesUpdateSuccess": "Bijwerken serie gelukt", "ToastSeriesUpdateSuccess": "Bijwerken serie gelukt",
"ToastSessionDeleteFailed": "Verwijderen sessie mislukt", "ToastSessionDeleteFailed": "Verwijderen sessie mislukt",

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