Compare commits

...

89 Commits

Author SHA1 Message Date
Bogdan
4321c1d40c Catch search engine related error messages for MyAnonaMouse 2024-12-28 23:42:14 +02:00
Mark McDowall
bb2548a08d Don't send session information to Sentry
(cherry picked from commit fae24e98fb9230c2f3701caef457332952c6723f)
2024-12-28 15:22:41 +02:00
Weblate
3a9b841fad Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Tommy Au <smarttommyau@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: marapavelka <mara.pavelka@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2024-12-27 22:55:30 +02:00
Bogdan
31203d1370 Add more links for info FlareSolverr and category 8000 2024-12-27 22:53:53 +02:00
Bogdan
c8a910eaf4 Fixed: (RuTracker) Update categories
Co-authored-by: garfield69 <garfield69@outlook.com>
2024-12-27 22:53:53 +02:00
Bogdan
9ab3c3e6c7 Update how to get cookies info for Cardigann
Co-authored-by: garfield69 <garfield69@outlook.com>
2024-12-27 22:53:53 +02:00
Bogdan
4659cb706a Fixed: (Knaben) Update base url
Co-authored-by: garfield69 <garfield69@outlook.com>
2024-12-27 22:53:53 +02:00
Bogdan
500759bf1f Bump version to 1.29.1 2024-12-22 13:24:47 +02:00
Bogdan
43c7c43257 Bump Microsoft.Data.SqlClient to 2.1.7 2024-12-18 12:56:44 +02:00
Bogdan
9c2fced391 Bump System.Text.Json to 6.0.10 2024-12-18 02:34:29 +02:00
Bogdan
52ec5b6ff6 Bump MailKit to 4.8.0 2024-12-18 02:34:29 +02:00
zodihax
b46e657976 Fixed: (NorBits) Searching UTF-8 characters with full search disabled (#2305)
Co-authored-by: zodihaxx <parity.umpires-0m@icloud.com>
2024-12-17 23:04:05 +02:00
Bogdan
51fd30ba10 Use message from error response for Gazelle indexers 2024-12-17 15:30:25 +02:00
Mark McDowall
5fbb347108 Upgrade typescript-eslint packages to 8.181.1
(cherry picked from commit ed10b63fa0c161cac7e0a2084e53785ab1798208)
2024-12-17 14:09:24 +02:00
Mark McDowall
54d3d44620 Upgrade Font Awesome to 6.7.1
(cherry picked from commit 016b5718386593c030f14fcac307c93ee1ceeca6)
2024-12-17 14:04:46 +02:00
Mark McDowall
5ca18683ca Upgrade babel to 7.26.0
(cherry picked from commit bfcd017012730c97eb587ae2d2e91f72ee7a1de3)
2024-12-17 13:59:56 +02:00
Bogdan
6bdf5f5d69 Use error message from Redacted response 2024-12-16 22:25:55 +02:00
Bogdan
7cba7152f1 Bump version to 1.29.0 2024-12-16 22:11:18 +02:00
Bogdan
cf012eb001 Use minor version for core-js in babel/preset-env 2024-12-16 13:26:25 +02:00
Weblate
6b8a7993ff Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2024-12-15 18:40:20 +02:00
Mark McDowall
c6440bb21b Upgrade TypeScript and core-js
(cherry picked from commit 148480909917f69ff3b2ca547ccb4716dd56606e)
2024-12-15 15:37:10 +02:00
Mark McDowall
b95eac98b9 Fixed: Error getting processes in some cases
(cherry picked from commit b552d4e9f7ca7388404aa0d52566010a54cb0244)
2024-12-15 15:37:10 +02:00
Bogdan
0eb19ce834 Bump version to 1.28.2 2024-12-15 10:05:45 +02:00
Weblate
4b8016d95d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2024-12-14 02:34:32 +02:00
Bogdan
31d8d2419a Fixed: Refresh backup list on deletion
Fixes #2300
2024-12-11 14:36:59 +02:00
Weblate
d29ccd7749 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
Co-authored-by: Robin Dadswell <robin@robindadswell.tech>
Co-authored-by: Rodion <rodyon009@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: farebyting <farelbyting@gmail.com>
Co-authored-by: hhjuhl <hans@kopula.dk>
Co-authored-by: keysuck <joshkkim@gmail.com>
Co-authored-by: mryx007 <mryx@mail.de>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_HANS/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/
Translation: Servarr/Prowlarr
2024-12-10 14:12:15 +02:00
Mark McDowall
e789f4ec54 Sync TimeSpanConverter with upstream
(cherry picked from commit 1374240321f08d1400faf95e84217e4b7a2d116b)
2024-12-09 14:09:23 +02:00
Bogdan
58d495d618 Bump version to 1.28.1 2024-12-08 12:25:51 +02:00
Bogdan
f3328863e1 Fixed: (M-Team) IMDb removed from releases response 2024-12-07 14:08:48 +02:00
Bogdan
a23d792781 Fixed: Syncing Newznab indexers with expired VIP expiration dates to apps 2024-12-07 12:10:45 +02:00
Bogdan
f066cf399d Fixed: Link to TMDb shows in search history
Fixes #2294
2024-12-07 10:37:29 +02:00
Servarr
61e863cb31 Automated API Docs update 2024-12-03 00:26:48 -06:00
soup
b2afbc6872 New: Add config file setting for CGNAT authentication bypass
(cherry picked from commit 4c41a4f368046f73f82306bbd73bec992392938b)
2024-12-03 00:07:27 -06:00
Elias Benbourenane
aace65f88e Allow GetFileSize to follow symlinks
(cherry picked from commit ca0bb14027f3409014e7cf9ffa8e04e577001d77)

Don't fail if symlink target can't be resolved

(cherry picked from commit 8cb58a63d8ec1b290bc57ad2cf1e90809ceebce9)
2024-12-02 03:18:30 +02:00
Bogdan
9ab2d8b444 Bump IPAddressRange, Npgsql and Polly 2024-12-02 03:14:36 +02:00
Mark McDowall
bc314061ef Fixed: Prevent lack of internet from stopping all health checks from running
(cherry picked from commit dba3a8243988d3e9870b841696303191e1703a0d)
2024-12-02 03:10:32 +02:00
Mark McDowall
87b3dcd780 Support Postgres with non-standard version string
(cherry picked from commit 40f4ef27b22113c1dae0d0cbdee8205132bed68a)
2024-12-02 03:06:47 +02:00
Gylesie
f3b99f68f6 Remove unnecessary heap allocations in local IP check
(cherry picked from commit ed536a85ad5f2062bf6f01f80efddb19fa935f63)
2024-12-02 03:05:29 +02:00
Mark McDowall
c4a90e8ba4 Webpack web target
(cherry picked from commit a90866a73e6cff9a286c23e60c74672f4c0d317a)
2024-11-27 12:26:23 +02:00
Bogdan
41320ca2dc Bump version to 1.28.0 2024-11-26 19:27:15 +02:00
Bogdan
b8b32f8708 Fixed: (ImmortalSeed) Update relogin check 2024-11-24 11:45:55 +02:00
Weblate
30c4bb24e8 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Mizuyoru_TW <mizuyoru.tw@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2024-11-24 07:44:46 +02:00
Alexander Bruun
b447db5d08 Fixed: (RED) Update indexer url (#2285)
* Updated RED CNAME record
* Added LegacyUrls
2024-11-23 22:41:21 -06:00
Weblate
299001a513 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: 4kwins <hanszimmerme@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2024-11-19 20:37:31 -06:00
Bogdan
2871f1f2a2 Bump version to 1.27.0 2024-11-19 03:11:37 +02:00
Bogdan
a9b93df0c9 Pin ReportGenerator in Azure Pipelines for .NET 6
(cherry picked from commit 50ce480abf043140e209d2d2959fbea8dd5dd2ab)
2024-11-15 15:43:29 -06:00
Weblate
2726787ee9 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: My name is Svetoslav Kolev <slubchev@yahoo.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2024-11-14 20:56:24 -06:00
bakerboy448
b917932f19 Improve No Results Messaging 2024-11-14 19:30:12 -06:00
bakerboy448
06ae85e6d1 Fixed: Updates Page Translations 2024-11-12 21:14:38 -06:00
Weblate
b1c7e98664 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lars <lars.erik.heloe@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: mytelegrambot <lacsonluxur@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translation: Servarr/Prowlarr
2024-11-08 13:45:13 +02:00
Bogdan
62479737a7 Fixed: (Torrent RSS) Clear old cookies on edit
Fixes #2275
2024-11-04 14:23:29 +02:00
Bogdan
8e69415d64 Check for disabled till value in filtering blocked providers 2024-11-03 18:16:39 +02:00
Bogdan
222dfb1821 Bump version to 1.26.1 2024-11-03 11:43:41 +02:00
Weblate
94f439e238 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: HUi <huynguyeexn@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Kuzmich <kuzmich55@gmail.com>
Co-authored-by: Moon55 <dylan.gurdak@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2024-11-02 21:13:55 +02:00
Bogdan
903a88c121 Update timezone offset for FL 2024-11-01 17:56:47 +02:00
Bogdan
9690ab6883 Fixed: (IPTorrents) Search IMDb ID in descriptions 2024-11-01 17:19:28 +02:00
Bogdan
1e1a2b3b4a Fixed: (BeyondHD) Enforce length for API and RSS keys 2024-11-01 12:59:11 +02:00
bakerboy448
9dc2d3669c Fixed: NzbIndex removed, API not supported 2024-10-31 09:31:25 +02:00
Bogdan
511c76e219 Update JetBrains logos 2024-10-29 10:06:00 +02:00
Bogdan
78329b7b92 Improve exception message for invalid torrent files 2024-10-28 17:35:17 +02:00
Bogdan
4240048853 Add Knaben as native indexer 2024-10-28 08:23:42 +02:00
Bogdan
432af42ffd Fixed indexer names for no definitions check 2024-10-27 16:04:17 +02:00
Weblate
0d6c03f8d4 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ardenet <1213193613@qq.com>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2024-10-27 16:02:41 +02:00
Bogdan
96830f975e Cleaning paths for top level root folders
(cherry picked from commit a00121695715feb2cf8f04da246dc18262ab3237)
2024-10-27 15:12:00 +02:00
Mark McDowall
13c538ff58 Ignore extra spaces in path when not running on Windows
(cherry picked from commit 6d0f10b877912edef21232c64339cc6548d9690e)
2024-10-27 15:10:34 +02:00
Mark McDowall
14250e9634 Fixed getting parents from different OS paths
(cherry picked from commit e791f4b743d9660b0ad1decc4c5ed0e864f3b243)
2024-10-27 15:08:13 +02:00
Hadrien Patte
e2f7890d76 Use OperatingSystem class to get OS information
(cherry picked from commit 135b5c2ddd8f0a274b0d59eb07f75aaf1446b9da)
2024-10-27 09:06:21 +02:00
Bogdan
257d38de66 Inherit trigger from pushed command models
(cherry picked from commit 0bc4903954b955fce0c368ef7fd2a6f3761d6a93)
2024-10-27 09:05:38 +02:00
Bogdan
fd2a14e01b Fix settings fetching failure for updates 2024-10-27 09:01:07 +02:00
Bogdan
b4d76c7138 Fixed: Initial state for qBittorrent v5.0
(cherry picked from commit ff724b7f4099284b8062f1625cf07b7822782edf)
2024-10-27 08:57:54 +02:00
Bogdan
9655f37fa8 Trim directory separators in GetRelativePath
(cherry picked from commit 240a0339bee7d407e564df6b6575a2ade6ac03cd)
2024-10-27 08:56:57 +02:00
Bogdan
246fb9b855 Update check returns error if build older than 180 days 2024-10-24 08:14:07 +03:00
Bogdan
25afadc9b2 Bump version to 1.26.0 2024-10-22 05:51:30 +03:00
Bogdan
3f547f0856 Cleanse exceptions in event logs 2024-10-20 13:39:43 +03:00
Bogdan
11e322b6d7 Bump version to 1.25.4 2024-10-20 08:05:32 +03:00
Weblate
02ff133a62 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Kuzmich55 <kuzmich55@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_TW/
Translation: Servarr/Prowlarr
2024-10-20 04:42:29 +03:00
Bogdan
47268aac87 Fix stable branch label in updates 2024-10-20 04:36:52 +03:00
Bogdan
8aad1ac554 New: Allow major version updates to be installed (#2260)
* New: Allow major version updates to be installed

(cherry picked from commit 0e95ba2021b23cc65bce0a0620dd48e355250dab)

* fixup! New: Allow major version updates to be installed

---------

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-10-19 09:01:23 +03:00
Bogdan
9037cde439 Rename ApplicationCheckUpdate to ApplicationUpdateCheck 2024-10-19 07:13:31 +03:00
Mark McDowall
2afafd79e4 Fixed: Don't block updates under docker unless configured in package_info
(cherry picked from commit 5a7e34e291c2715aa67161e5c455d25e80f498df)
2024-10-19 07:13:31 +03:00
Bogdan
f4fa2517d2 Sort indexers by name when syncing to applications 2024-10-18 23:12:57 +03:00
Stevie Robinson
37bc46c1cd Translate System pages
(cherry picked from commit 93e8ff0ac7610fa8739f2e577ece98c2c06c8881)
2024-10-18 11:44:20 +03:00
Weblate
3e3a7ed4f0 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: JoseFilipeFerreira <jose.filipe.matos.ferreira@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translation: Servarr/Prowlarr
2024-10-16 04:09:51 +03:00
Bogdan
04fa7d366d Fixed: (Cardigann) Redirect warnings with "Refresh" header 2024-10-13 20:08:54 +03:00
Bogdan
ed9a3214a2 Fix redirect url in HttpClient development warning message 2024-10-13 19:56:32 +03:00
Bogdan
66a9e1a653 Bump dotnet to 6.0.35 2024-10-13 19:32:37 +03:00
Bogdan
8cb59c35fb New: Sync UI updates for providers 2024-10-13 07:23:10 +03:00
Bogdan
94e9c05d60 Natural sorting for tags list in the UI 2024-10-13 07:21:27 +03:00
Bogdan
8d2c4e1246 Bump version to 1.25.3 2024-10-13 07:20:52 +03:00
149 changed files with 3816 additions and 2229 deletions

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1.3318" y1="43.7371" x2="67.0419" y2="26.0967">
<stop offset="0.1237" style="stop-color:#7866FF"/>
<stop offset="0.5376" style="stop-color:#FE2EB6"/>
<stop offset="0.8548" style="stop-color:#FD0486"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);" points="67.3,16 43.7,0 0,31.1 11.1,70 58.9,60.3 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="45.9148" y1="38.9098" x2="67.6577" y2="9.0989">
<stop offset="0.1237" style="stop-color:#FF0080"/>
<stop offset="0.2587" style="stop-color:#FE0385"/>
<stop offset="0.4109" style="stop-color:#FA0C92"/>
<stop offset="0.5713" style="stop-color:#F41BA9"/>
<stop offset="0.7363" style="stop-color:#EB2FC8"/>
<stop offset="0.8656" style="stop-color:#E343E6"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);" points="67.3,16 43.7,0 38,15.7 38,47.8 70,47.8 "/>
</g>
<g>
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.4" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<g>
<path style="fill:#FFFFFF;" d="M17.4,19.1h6.9c5.6,0,9.5,3.8,9.5,8.9V28c0,5-3.9,8.9-9.5,8.9h-6.9V19.1z M21.4,22.7v10.7h3
c3.2,0,5.4-2.2,5.4-5.3V28c0-3.2-2.2-5.4-5.4-5.4H21.4z"/>
<polygon style="fill:#FFFFFF;" points="40.3,22.7 34.9,22.7 34.9,19.1 49.6,19.1 49.6,22.7 44.2,22.7 44.2,37 40.3,37 "/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="120.1px" height="130.2px" viewBox="0 0 120.1 130.2" style="enable-background:new 0 0 120.1 130.2;" xml:space="preserve"
>
<g>
<linearGradient id="XMLID_2_" gradientUnits="userSpaceOnUse" x1="31.8412" y1="120.5578" x2="110.2402" y2="73.24">
<stop offset="0" style="stop-color:#FCEE39"/>
<stop offset="1" style="stop-color:#F37B3D"/>
</linearGradient>
<path id="XMLID_3041_" style="fill:url(#XMLID_2_);" d="M118.6,71.8c0.9-0.8,1.4-1.9,1.5-3.2c0.1-2.6-1.8-4.7-4.4-4.9
c-1.2-0.1-2.4,0.4-3.3,1.1l0,0l-83.8,45.9c-1.9,0.8-3.6,2.2-4.7,4.1c-2.9,4.8-1.3,11,3.6,13.9c3.4,2,7.5,1.8,10.7-0.2l0,0l0,0
c0.2-0.2,0.5-0.3,0.7-0.5l78-54.8C117.3,72.9,118.4,72.1,118.6,71.8L118.6,71.8L118.6,71.8z"/>
<linearGradient id="XMLID_3_" gradientUnits="userSpaceOnUse" x1="48.3607" y1="6.9083" x2="119.9179" y2="69.5546">
<stop offset="0" style="stop-color:#EF5A6B"/>
<stop offset="0.57" style="stop-color:#F26F4E"/>
<stop offset="1" style="stop-color:#F37B3D"/>
</linearGradient>
<path id="XMLID_3049_" style="fill:url(#XMLID_3_);" d="M118.8,65.1L118.8,65.1L55,2.5C53.6,1,51.6,0,49.3,0
c-4.3,0-7.7,3.5-7.7,7.7v0c0,2.1,0.8,3.9,2.1,5.3l0,0l0,0c0.4,0.4,0.8,0.7,1.2,1l67.4,57.7l0,0c0.8,0.7,1.8,1.2,3,1.3
c2.6,0.1,4.7-1.8,4.9-4.4C120.2,67.3,119.7,66,118.8,65.1z"/>
<linearGradient id="XMLID_4_" gradientUnits="userSpaceOnUse" x1="52.9467" y1="63.6407" x2="10.5379" y2="37.1562">
<stop offset="0" style="stop-color:#7C59A4"/>
<stop offset="0.3852" style="stop-color:#AF4C92"/>
<stop offset="0.7654" style="stop-color:#DC4183"/>
<stop offset="0.957" style="stop-color:#ED3D7D"/>
</linearGradient>
<path id="XMLID_3042_" style="fill:url(#XMLID_4_);" d="M57.1,59.5C57,59.5,17.7,28.5,16.9,28l0,0l0,0c-0.6-0.3-1.2-0.6-1.8-0.9
c-5.8-2.2-12.2,0.8-14.4,6.6c-1.9,5.1,0.2,10.7,4.6,13.4l0,0l0,0C6,47.5,6.6,47.8,7.3,48c0.4,0.2,45.4,18.8,45.4,18.8l0,0
c1.8,0.8,3.9,0.3,5.1-1.2C59.3,63.7,59,61,57.1,59.5z"/>
<linearGradient id="XMLID_5_" gradientUnits="userSpaceOnUse" x1="52.1736" y1="3.7019" x2="10.7706" y2="37.8971">
<stop offset="0" style="stop-color:#EF5A6B"/>
<stop offset="0.364" style="stop-color:#EE4E72"/>
<stop offset="1" style="stop-color:#ED3D7D"/>
</linearGradient>
<path id="XMLID_3057_" style="fill:url(#XMLID_5_);" d="M49.3,0c-1.7,0-3.3,0.6-4.6,1.5L4.9,28.3c-0.1,0.1-0.2,0.1-0.2,0.2l-0.1,0
l0,0c-1.7,1.2-3.1,3-3.9,5.1C-1.5,39.4,1.5,45.9,7.3,48c3.6,1.4,7.5,0.7,10.4-1.4l0,0l0,0c0.7-0.5,1.3-1,1.8-1.6l34.6-31.2l0,0
c1.8-1.4,3-3.6,3-6.1v0C57.1,3.5,53.6,0,49.3,0z"/>
<g id="XMLID_3008_">
<rect id="XMLID_3033_" x="34.6" y="37.4" style="fill:#000000;" width="51" height="51"/>
<rect id="XMLID_3032_" x="39" y="78.8" style="fill:#FFFFFF;" width="19.1" height="3.2"/>
<g id="XMLID_3009_">
<path id="XMLID_3030_" style="fill:#FFFFFF;" d="M38.8,50.8l1.5-1.4c0.4,0.5,0.8,0.8,1.3,0.8c0.6,0,0.9-0.4,0.9-1.2l0-5.3l2.3,0
l0,5.3c0,1-0.3,1.8-0.8,2.3c-0.5,0.5-1.3,0.8-2.3,0.8C40.2,52.2,39.4,51.6,38.8,50.8z"/>
<path id="XMLID_3028_" style="fill:#FFFFFF;" d="M45.3,43.8l6.7,0v1.9l-4.4,0V47l4,0l0,1.8l-4,0l0,1.3l4.5,0l0,2l-6.7,0
L45.3,43.8z"/>
<path id="XMLID_3026_" style="fill:#FFFFFF;" d="M55,45.8l-2.5,0l0-2l7.3,0l0,2l-2.5,0l0,6.3l-2.3,0L55,45.8z"/>
<path id="XMLID_3022_" style="fill:#FFFFFF;" d="M39,54l4.3,0c1,0,1.8,0.3,2.3,0.7c0.3,0.3,0.5,0.8,0.5,1.4v0
c0,1-0.5,1.5-1.3,1.9c1,0.3,1.6,0.9,1.6,2v0c0,1.4-1.2,2.3-3.1,2.3l-4.3,0L39,54z M43.8,56.6c0-0.5-0.4-0.7-1-0.7l-1.5,0l0,1.5
l1.4,0C43.4,57.3,43.8,57.1,43.8,56.6L43.8,56.6z M43,59l-1.8,0l0,1.5H43c0.7,0,1.1-0.3,1.1-0.8v0C44.1,59.2,43.7,59,43,59z"/>
<path id="XMLID_3019_" style="fill:#FFFFFF;" d="M46.8,54l3.9,0c1.3,0,2.1,0.3,2.7,0.9c0.5,0.5,0.7,1.1,0.7,1.9v0
c0,1.3-0.7,2.1-1.7,2.6l2,2.9l-2.6,0l-1.7-2.5h-1l0,2.5l-2.3,0L46.8,54z M50.6,58c0.8,0,1.2-0.4,1.2-1v0c0-0.7-0.5-1-1.2-1
l-1.5,0v2H50.6z"/>
<path id="XMLID_3016_" style="fill:#FFFFFF;" d="M56.8,54l2.2,0l3.5,8.4l-2.5,0l-0.6-1.5l-3.2,0l-0.6,1.5l-2.4,0L56.8,54z
M58.8,59l-0.9-2.3L57,59L58.8,59z"/>
<path id="XMLID_3014_" style="fill:#FFFFFF;" d="M62.8,54l2.3,0l0,8.3l-2.3,0L62.8,54z"/>
<path id="XMLID_3012_" style="fill:#FFFFFF;" d="M65.7,54l2.1,0l3.4,4.4l0-4.4l2.3,0l0,8.3l-2,0L68,57.8l0,4.6l-2.3,0L65.7,54z"
/>
<path id="XMLID_3010_" style="fill:#FFFFFF;" d="M73.7,61.1l1.3-1.5c0.8,0.7,1.7,1,2.7,1c0.6,0,1-0.2,1-0.6v0
c0-0.4-0.3-0.5-1.4-0.8c-1.8-0.4-3.1-0.9-3.1-2.6v0c0-1.5,1.2-2.7,3.2-2.7c1.4,0,2.5,0.4,3.4,1.1l-1.2,1.6
c-0.8-0.5-1.6-0.8-2.3-0.8c-0.6,0-0.8,0.2-0.8,0.5v0c0,0.4,0.3,0.5,1.4,0.8c1.9,0.4,3.1,1,3.1,2.6v0c0,1.7-1.3,2.7-3.4,2.7
C76.1,62.5,74.7,62,73.7,61.1z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="22.9451" y1="75.7869" x2="74.7868" y2="20.6415">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.4044" style="stop-color:#C41E57"/>
<stop offset="0.4677" style="stop-color:#C41E57"/>
<stop offset="0.6505" style="stop-color:#EB8523"/>
<stop offset="0.9516" style="stop-color:#FEBD11"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);" points="49.8,15.2 36,36.7 58.4,70 70,23.1 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="17.7187" y1="73.2922" x2="69.5556" y2="18.1519">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.4044" style="stop-color:#C41E57"/>
<stop offset="0.4677" style="stop-color:#C41E57"/>
<stop offset="0.7043" style="stop-color:#EB8523"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);" points="51.1,15.7 49,0 18.8,33.6 27.6,42.3 20.8,70 58.4,70 "/>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1.8281" y1="53.4275" x2="48.8245" y2="9.2255">
<stop offset="1.612903e-002" style="stop-color:#B35BA3"/>
<stop offset="0.6613" style="stop-color:#C41E57"/>
</linearGradient>
<polygon style="fill:url(#SVGID_3_);" points="49,0 11.6,0 0,47.1 55.6,47.1 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="49.8935" y1="-11.5569" x2="48.8588" y2="24.0352">
<stop offset="0.5" style="stop-color:#C41E57"/>
<stop offset="0.6668" style="stop-color:#D13F48"/>
<stop offset="0.7952" style="stop-color:#D94F39"/>
<stop offset="0.8656" style="stop-color:#DD5433"/>
</linearGradient>
<polygon style="fill:url(#SVGID_4_);" points="55.3,47.1 51.1,15.7 49,0 41.7,23 "/>
</g>
<g>
<rect x="13.4" y="13.5" transform="matrix(-1 2.577289e-003 -2.577289e-003 -1 70.0288 70.081)" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.6" y="48.6" transform="matrix(1 -2.577289e-003 2.577289e-003 1 -0.1287 6.634109e-002)" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<path style="fill:#FFFFFF;" d="M17.4,19.1l8.2,0c2.3,0,4,0.6,5.2,1.8c1,1,1.5,2.4,1.5,4.1l0,0.1c0,1.5-0.3,2.6-1.1,3.5
c-0.7,0.9-1.6,1.6-2.8,2l4.4,6.4l-4.6,0l-3.7-5.5l-3.3,0l0,5.5l-3.9,0L17.4,19.1z M25.3,27.8c1,0,1.7-0.2,2.2-0.7
c0.5-0.5,0.8-1.1,0.8-1.8l0-0.1c0-0.9-0.3-1.5-0.8-1.9c-0.5-0.4-1.3-0.6-2.3-0.6l-3.9,0l0,5.1L25.3,27.8z"/>
<path style="fill:#FFFFFF;" d="M36,33.2l-1.9,0l0-3.3l2.5,0l0.6-3.8l-2.3,0l0-3.3l2.8,0l0.6-3.7l3.4,0l-0.6,3.7l3.7,0l0.6-3.7
l3.4,0l-0.6,3.7l1.9,0l0,3.3l-2.5,0L47,29.9l2.3,0l0,3.3l-2.8,0L45.8,37l-3.4,0l0.7-3.8l-3.7,0L38.7,37l-3.4,0L36,33.2z
M43.7,29.9l0.6-3.8l-3.7,0L40,29.9L43.7,29.9z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<defs>
<linearGradient id="linear-gradient" x1="70.22612" y1="27.79912" x2="-5.13024" y2="63.12242" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#c90f5e"/>
<stop offset="0.22111" stop-color="#c90f5e"/>
<stop offset="0.2356" stop-color="#c90f5e"/>
<stop offset="0.35559" stop-color="#ca135c"/>
<stop offset="0.46633" stop-color="#ce1e57"/>
<stop offset="0.5735" stop-color="#d4314e"/>
<stop offset="0.67844" stop-color="#dc4b41"/>
<stop offset="0.78179" stop-color="#e66d31"/>
<stop offset="0.88253" stop-color="#f3961d"/>
<stop offset="0.94241" stop-color="#fcb20f"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="24.65904" y1="61.99608" x2="46.04762" y2="2.93445" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
<stop offset="0.04188" stop-color="#077cfb"/>
<stop offset="0.44503" stop-color="#c90f5e"/>
<stop offset="0.95812" stop-color="#077cfb"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="17.39552" y1="63.34592" x2="33.19389" y2="7.20092" gradientTransform="matrix(1, 0, 0, -1, 0, 71.27997)" gradientUnits="userSpaceOnUse">
<stop offset="0.27749" stop-color="#c90f5e"/>
<stop offset="0.97382" stop-color="#fcb20f"/>
</linearGradient>
</defs>
<title>rider</title>
<g>
<polygon points="70 27.237 63.391 23.75 20.926 0 3.827 17.921 21.619 41.068 60.537 44.397 70 27.237" fill="url(#linear-gradient)"/>
<polygon points="50.423 16.132 44.271 1.107 27.643 17.471 11.768 50.194 49.411 70 70 57.98 50.423 16.132" fill="url(#linear-gradient-2)"/>
<polygon points="20.926 0 0 14.095 7.779 62.172 27.848 69.889 53.78 48.823 20.926 0" fill="url(#linear-gradient-3)"/>
</g>
<g>
<rect x="13.30219" y="13.19311" width="43.61371" height="43.61371"/>
<g>
<path d="M17.22741,18.86293h8.39564a7.38416,7.38416,0,0,1,5.34268,1.85358,5.86989,5.86989,0,0,1,1.52648,4.1433h0A5.74339,5.74339,0,0,1,28.567,30.5296l4.47041,6.54206H28.34891L24.42368,31.1838h-3.162v5.88785H17.22741V18.86293h0ZM25.296,27.69471c1.96262,0,3.053-1.09034,3.053-2.61682h0c0-1.74455-1.19938-2.61682-3.162-2.61682H21.15265v5.23365H25.296Z" fill="#fff"/>
<path d="M36.09034,18.86293H43.2866c5.77882,0,9.70405,3.92523,9.70405,9.15888h0c0,5.12461-3.92523,9.15888-9.70405,9.15888H36.09034V18.86293Zm4.03427,3.59813V33.47352h3.162a5.23727,5.23727,0,0,0,5.56075-5.45171h0a5.26493,5.26493,0,0,0-5.56075-5.56075h-3.162Z" fill="#fff"/>
</g>
<rect x="17.22741" y="48.62925" width="16.35514" height="2.72586" fill="#fff"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="70px" height="70px" viewBox="0 0 70 70" style="enable-background:new 0 0 70 70;" xml:space="preserve">
<g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="25.0676" y1="1.4599" x2="43.1829" y2="66.675">
<stop offset="0.2849" style="stop-color:#00CDD7"/>
<stop offset="0.9409" style="stop-color:#2086D7"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);" points="9.4,63.3 0,7.3 17.5,0.1 28.6,6.7 38.8,1.2 60.1,9.4 48.1,70 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="30.7199" y1="9.7343" x2="61.365" y2="54.6713">
<stop offset="0.1398" style="stop-color:#FFF045"/>
<stop offset="0.3656" style="stop-color:#00CDD7"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);" points="70,23.7 61,1.4 44.6,0 19.3,24.3 26.1,55.6 38.8,64.6 70,46 62.3,31.7 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="61.0819" y1="15.2899" x2="65.1065" y2="29.5436">
<stop offset="0.2849" style="stop-color:#00CDD7"/>
<stop offset="0.9409" style="stop-color:#2086D7"/>
</linearGradient>
<polygon style="fill:url(#SVGID_3_);" points="56,20.4 62.3,31.7 70,23.7 64.4,9.8 "/>
</g>
<g>
<g>
<rect x="13.4" y="13.4" style="fill:#000000;" width="43.2" height="43.2"/>
<rect x="17.5" y="48.5" style="fill:#FFFFFF;" width="16.2" height="2.7"/>
<path style="fill:#FFFFFF;" d="M38.7,34.3l2.3-2.8c1.6,1.3,3.3,2.2,5.3,2.2c1.6,0,2.5-0.6,2.5-1.7v-0.1c0-1-0.6-1.5-3.6-2.3
c-3.6-0.9-5.8-1.9-5.8-5.5v-0.1c0-3.3,2.6-5.4,6.2-5.4c2.6,0,4.8,0.8,6.6,2.3l-2,3c-1.6-1.1-3.1-1.8-4.6-1.8
c-1.5,0-2.3,0.7-2.3,1.6v0.1c0,1.2,0.8,1.6,3.8,2.4c3.6,1,5.6,2.3,5.6,5.4v0.1c0,3.6-2.7,5.6-6.5,5.6
C43.5,37.2,40.8,36.2,38.7,34.3"/>
</g>
<polygon style="fill:#FFFFFF;" points="35.2,19 32.5,29.4 29.5,19 26.5,19 23.4,29.4 20.7,19 16.6,19 21.7,36.9 25,36.9 28,26.5
30.9,36.9 34.3,36.9 39.4,19 "/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -68,16 +68,16 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
## JetBrains
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
Thank you to [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.png" alt="JetBrains" width="96">](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
- [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
- [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
- [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
- [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/ReSharper_icon.png" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/WebStorm_icon.png" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/Rider_icon.png" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
* [<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/dotTrace_icon.png" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
### License
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2022
- Copyright 2010-2024
Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box)

View File

@@ -9,13 +9,13 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.25.2'
majorVersion: '1.29.1'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.424'
dotnetVersion: '6.0.427'
nodeVersion: '20.X'
innoVersion: '6.2.2'
windowsImage: 'windows-2022'
@@ -1190,7 +1190,7 @@ stages:
- task: SonarCloudAnalyze@2
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
- task: reportgenerator@5
- task: reportgenerator@5.3.11
displayName: Generate Coverage Report
inputs:
reports: '$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml'

View File

@@ -25,6 +25,7 @@ module.exports = (env) => {
const config = {
mode: isProduction ? 'production' : 'development',
devtool: isProduction ? 'source-map' : 'eval-source-map',
target: 'web',
stats: {
children: false
@@ -169,7 +170,7 @@ module.exports = (env) => {
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: 3
corejs: '3.39'
}
]
]

View File

@@ -20,7 +20,7 @@ import LogsTableConnector from 'System/Events/LogsTableConnector';
import Logs from 'System/Logs/Logs';
import Status from 'System/Status/Status';
import Tasks from 'System/Tasks/Tasks';
import UpdatesConnector from 'System/Updates/UpdatesConnector';
import Updates from 'System/Updates/Updates';
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
function RedirectWithUrlBase() {
@@ -99,7 +99,7 @@ function AppRoutes() {
<Route path="/system/backup" component={BackupsConnector} />
<Route path="/system/updates" component={UpdatesConnector} />
<Route path="/system/updates" component={Updates} />
<Route path="/system/events" component={LogsTableConnector} />

View File

@@ -7,7 +7,8 @@ import { IndexerCategory } from 'Indexer/Indexer';
import Application from 'typings/Application';
import DownloadClient from 'typings/DownloadClient';
import Notification from 'typings/Notification';
import { UiSettings } from 'typings/UiSettings';
import General from 'typings/Settings/General';
import UiSettings from 'typings/Settings/UiSettings';
export interface AppProfileAppState
extends AppSectionState<Application>,
@@ -28,6 +29,10 @@ export interface DownloadClientAppState
isTestingAll: boolean;
}
export interface GeneralAppState
extends AppSectionItemState<General>,
AppSectionSaveState {}
export interface IndexerCategoryAppState
extends AppSectionState<IndexerCategory>,
AppSectionDeleteState,
@@ -43,6 +48,7 @@ interface SettingsAppState {
appProfiles: AppProfileAppState;
applications: ApplicationAppState;
downloadClients: DownloadClientAppState;
general: GeneralAppState;
indexerCategories: IndexerCategoryAppState;
notifications: NotificationAppState;
ui: UiSettingsAppState;

View File

@@ -141,6 +141,16 @@ class SignalRConnector extends Component {
console.error(`signalR: Unable to find handler for ${name}`);
};
handleApplications = ({ action, resource }) => {
const section = 'settings.applications';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleCommand = (body) => {
if (body.action === 'sync') {
this.props.dispatchFetchCommands();
@@ -150,8 +160,8 @@ class SignalRConnector extends Component {
const resource = body.resource;
const status = resource.status;
// Both sucessful and failed commands need to be
// completed, otherwise they spin until they timeout.
// Both successful and failed commands need to be
// completed, otherwise they spin until they time out.
if (status === 'completed' || status === 'failed') {
this.props.dispatchFinishCommand(resource);
@@ -160,6 +170,16 @@ class SignalRConnector extends Component {
}
};
handleDownloadclient = ({ action, resource }) => {
const section = 'settings.downloadClients';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleHealth = () => {
this.props.dispatchFetchHealth();
};
@@ -168,14 +188,33 @@ class SignalRConnector extends Component {
this.props.dispatchFetchIndexerStatus();
};
handleIndexer = (body) => {
const action = body.action;
handleIndexer = ({ action, resource }) => {
const section = 'indexers';
if (action === 'updated') {
this.props.dispatchUpdateItem({ section, ...body.resource });
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: body.resource.id });
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleIndexerproxy = ({ action, resource }) => {
const section = 'settings.indexerProxies';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};
handleNotification = ({ action, resource }) => {
const section = 'settings.notifications';
if (action === 'created' || action === 'updated') {
this.props.dispatchUpdateItem({ section, ...resource });
} else if (action === 'deleted') {
this.props.dispatchRemoveItem({ section, id: resource.id });
}
};

View File

@@ -257,6 +257,7 @@ class HistoryRow extends Component {
key={parameter.key}
title={parameter.title}
value={data[parameter.key]}
queryType={data.queryType}
/>
);
}

View File

@@ -1,14 +1,16 @@
import React from 'react';
import Link from 'Components/Link/Link';
import { HistoryQueryType } from 'typings/History';
import styles from './HistoryRowParameter.css';
interface HistoryRowParameterProps {
title: string;
value: string;
queryType: HistoryQueryType;
}
function HistoryRowParameter(props: HistoryRowParameterProps) {
const { title, value } = props;
const { title, value, queryType } = props;
const type = title.toLowerCase();
@@ -18,7 +20,13 @@ function HistoryRowParameter(props: HistoryRowParameterProps) {
link = <Link to={`https://imdb.com/title/${value}/`}>{value}</Link>;
} else if (type === 'tmdb') {
link = (
<Link to={`https://www.themoviedb.org/movie/${value}`}>{value}</Link>
<Link
to={`https://www.themoviedb.org/${
queryType === 'tvsearch' ? 'tv' : 'movie'
}/${value}`}
>
{value}
</Link>
);
} else if (type === 'tvdb') {
link = (

View File

@@ -68,6 +68,7 @@ function IndexerHistoryRow(props: IndexerHistoryRowProps) {
key={parameter.key}
title={parameter.title}
value={data[parameter.key as keyof HistoryData].toString()}
queryType={data.queryType}
/>
);
})}

View File

@@ -4,11 +4,13 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchApplications, fetchIndexerProxies, fetchNotifications } from 'Store/Actions/settingsActions';
import { fetchTagDetails, fetchTags } from 'Store/Actions/tagActions';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import sortByProp from 'Utilities/Array/sortByProp';
import Tags from './Tags';
function createMapStateToProps() {
return createSelector(
(state) => state.tags,
createSortedSectionSelector('tags', sortByProp('label')),
(tags) => {
const isFetching = tags.isFetching || tags.details.isFetching;
const error = tags.error || tags.details.error;

View File

@@ -116,6 +116,7 @@ class BackupRow extends Component {
<TableRowCell className={styles.actions}>
<IconButton
title={translate('RestoreBackup')}
name={icons.RESTORE}
onPress={this.onRestorePress}
/>
@@ -138,7 +139,9 @@ class BackupRow extends Component {
isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteBackup')}
message={translate('DeleteBackupMessageText', { name })}
message={translate('DeleteBackupMessageText', {
name
})}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeletePress}
onCancel={this.onConfirmDeleteModalClose}

View File

@@ -109,7 +109,7 @@ class Backups extends Component {
{
!isFetching && !!error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBackups')}
{translate('BackupsLoadError')}
</Alert>
}

View File

@@ -14,7 +14,7 @@ import styles from './RestoreBackupModalContent.css';
function getErrorMessage(error) {
if (!error || !error.responseJSON || !error.responseJSON.message) {
return 'Error restoring backup';
return translate('ErrorRestoringBackup');
}
return error.responseJSON.message;
@@ -146,7 +146,9 @@ class RestoreBackupModalContent extends Component {
<ModalBody>
{
!!id && `Would you like to restore the backup '${name}'?`
!!id && translate('WouldYouLikeToRestoreBackup', {
name
})
}
{
@@ -203,7 +205,7 @@ class RestoreBackupModalContent extends Component {
<ModalFooter>
<div className={styles.additionalInfo}>
Note: Prowlarr will automatically restart and reload the UI during the restore process.
{translate('RestartReloadNote')}
</div>
<Button onPress={onModalClose}>
@@ -216,7 +218,7 @@ class RestoreBackupModalContent extends Component {
isSpinning={isRestoring}
onPress={this.onRestorePress}
>
Restore
{translate('Restore')}
</SpinnerButton>
</ModalFooter>
</ModalContent>

View File

@@ -84,7 +84,7 @@ function LogsTable(props) {
{
isPopulated && !error && !items.length &&
<Alert kind={kinds.INFO}>
No events found
{translate('NoEventsFound')}
</Alert>
}

View File

@@ -28,7 +28,7 @@ function LogsTableDetailsModal(props) {
onModalClose={onModalClose}
>
<ModalHeader>
Details
{translate('Details')}
</ModalHeader>
<ModalBody>

View File

@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Link from 'Components/Link/Link';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
@@ -77,13 +77,15 @@ class LogFiles extends Component {
<PageContentBody>
<Alert>
<div>
Log files are located in: {location}
{translate('LogFilesLocation', {
location
})}
</div>
{
currentLogView === 'Log Files' &&
<div>
The log level defaults to 'Info' and can be changed in <Link to="/settings/general">General Settings</Link>
<InlineMarkdown data={translate('TheLogLevelDefault')} />
</div>
}
</Alert>

View File

@@ -7,6 +7,7 @@ import { executeCommand } from 'Store/Actions/commandActions';
import { fetchLogFiles } from 'Store/Actions/systemActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import combinePath from 'Utilities/String/combinePath';
import translate from 'Utilities/String/translate';
import LogFiles from './LogFiles';
function createMapStateToProps() {
@@ -29,7 +30,7 @@ function createMapStateToProps() {
isFetching,
items,
deleteFilesExecuting,
currentLogView: 'Log Files',
currentLogView: translate('LogFiles'),
location: combinePath(isWindows, appData, ['logs'])
};
}

View File

@@ -4,6 +4,7 @@ import Link from 'Components/Link/Link';
import RelativeDateCell from 'Components/Table/Cells/RelativeDateCell';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import translate from 'Utilities/String/translate';
import styles from './LogFilesTableRow.css';
class LogFilesTableRow extends Component {
@@ -32,7 +33,7 @@ class LogFilesTableRow extends Component {
target="_blank"
noRouter={true}
>
Download
{translate('Download')}
</Link>
</TableRowCell>
</TableRow>

View File

@@ -4,6 +4,7 @@ import Menu from 'Components/Menu/Menu';
import MenuButton from 'Components/Menu/MenuButton';
import MenuContent from 'Components/Menu/MenuContent';
import MenuItem from 'Components/Menu/MenuItem';
import translate from 'Utilities/String/translate';
class LogsNavMenu extends Component {
@@ -50,13 +51,13 @@ class LogsNavMenu extends Component {
<MenuItem
to={'/system/logs/files'}
>
Log Files
{translate('LogFiles')}
</MenuItem>
<MenuItem
to={'/system/logs/files/update'}
>
Updater Log Files
{translate('UpdaterLogFiles')}
</MenuItem>
</MenuContent>
</Menu>

View File

@@ -1,52 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import styles from './UpdateChanges.css';
class UpdateChanges extends Component {
//
// Render
render() {
const {
title,
changes
} = this.props;
if (changes.length === 0) {
return null;
}
const uniqueChanges = [...new Set(changes)];
return (
<div>
<div className={styles.title}>{title}</div>
<ul>
{
uniqueChanges.map((change, index) => {
const checkChange = change.replace(/#\d{3,5}\b/g, (match, contents) => {
return `[${match}](https://github.com/Prowlarr/Prowlarr/issues/${match.substring(1)})`;
});
return (
<li key={index}>
<InlineMarkdown data={checkChange} />
</li>
);
})
}
</ul>
</div>
);
}
}
UpdateChanges.propTypes = {
title: PropTypes.string.isRequired,
changes: PropTypes.arrayOf(PropTypes.string)
};
export default UpdateChanges;

View File

@@ -0,0 +1,43 @@
import React from 'react';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import styles from './UpdateChanges.css';
interface UpdateChangesProps {
title: string;
changes: string[];
}
function UpdateChanges(props: UpdateChangesProps) {
const { title, changes } = props;
if (changes.length === 0) {
return null;
}
const uniqueChanges = [...new Set(changes)];
return (
<div>
<div className={styles.title}>{title}</div>
<ul>
{uniqueChanges.map((change, index) => {
const checkChange = change.replace(
/#\d{3,5}\b/g,
(match) =>
`[${match}](https://github.com/Prowlarr/Prowlarr/issues/${match.substring(
1
)})`
);
return (
<li key={index}>
<InlineMarkdown data={checkChange} />
</li>
);
})}
</ul>
</div>
);
}
export default UpdateChanges;

View File

@@ -1,252 +0,0 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { icons, kinds } from 'Helpers/Props';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import UpdateChanges from './UpdateChanges';
import styles from './Updates.css';
class Updates extends Component {
//
// Render
render() {
const {
currentVersion,
isFetching,
isPopulated,
updatesError,
generalSettingsError,
items,
isInstallingUpdate,
updateMechanism,
isDocker,
updateMechanismMessage,
shortDateFormat,
longDateFormat,
timeFormat,
onInstallLatestPress
} = this.props;
const hasError = !!(updatesError || generalSettingsError);
const hasUpdates = isPopulated && !hasError && items.length > 0;
const noUpdates = isPopulated && !hasError && !items.length;
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
const externalUpdaterPrefix = 'Unable to update Prowlarr directly,';
const externalUpdaterMessages = {
external: 'Prowlarr is configured to use an external update mechanism',
apt: 'use apt to install the update',
docker: 'update the docker container to receive the update'
};
return (
<PageContent title={translate('Updates')}>
<PageContentBody>
{
!isPopulated && !hasError &&
<LoadingIndicator />
}
{
noUpdates &&
<Alert kind={kinds.INFO}>
{translate('NoUpdatesAreAvailable')}
</Alert>
}
{
hasUpdateToInstall &&
<div className={styles.messageContainer}>
{
(updateMechanism === 'builtIn' || updateMechanism === 'script') && !isDocker ?
<SpinnerButton
className={styles.updateAvailable}
kind={kinds.PRIMARY}
isSpinning={isInstallingUpdate}
onPress={onInstallLatestPress}
>
Install Latest
</SpinnerButton> :
<Fragment>
<Icon
name={icons.WARNING}
kind={kinds.WARNING}
size={30}
/>
<div className={styles.message}>
{externalUpdaterPrefix} <InlineMarkdown data={updateMechanismMessage || externalUpdaterMessages[updateMechanism] || externalUpdaterMessages.external} />
</div>
</Fragment>
}
{
isFetching &&
<LoadingIndicator
className={styles.loading}
size={20}
/>
}
</div>
}
{
noUpdateToInstall &&
<div className={styles.messageContainer}>
<Icon
className={styles.upToDateIcon}
name={icons.CHECK_CIRCLE}
size={30}
/>
<div className={styles.message}>
{translate('TheLatestVersionIsAlreadyInstalled')}
</div>
{
isFetching &&
<LoadingIndicator
className={styles.loading}
size={20}
/>
}
</div>
}
{
hasUpdates &&
<div>
{
items.map((update) => {
const hasChanges = !!update.changes;
return (
<div
key={update.version}
className={styles.update}
>
<div className={styles.info}>
<div className={styles.version}>{update.version}</div>
<div className={styles.space}>&mdash;</div>
<div
className={styles.date}
title={formatDateTime(update.releaseDate, longDateFormat, timeFormat)}
>
{formatDate(update.releaseDate, shortDateFormat)}
</div>
{
update.branch === 'master' ?
null:
<Label
className={styles.label}
>
{update.branch}
</Label>
}
{
update.version === currentVersion ?
<Label
className={styles.label}
kind={kinds.SUCCESS}
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
>
Currently Installed
</Label> :
null
}
{
update.version !== currentVersion && update.installedOn ?
<Label
className={styles.label}
kind={kinds.INVERSE}
title={formatDateTime(update.installedOn, longDateFormat, timeFormat)}
>
Previously Installed
</Label> :
null
}
</div>
{
!hasChanges &&
<div>
{translate('MaintenanceRelease')}
</div>
}
{
hasChanges &&
<div className={styles.changes}>
<UpdateChanges
title={translate('New')}
changes={update.changes.new}
/>
<UpdateChanges
title={translate('Fixed')}
changes={update.changes.fixed}
/>
</div>
}
</div>
);
})
}
</div>
}
{
!!updatesError &&
<div>
Failed to fetch updates
</div>
}
{
!!generalSettingsError &&
<div>
Failed to update settings
</div>
}
</PageContentBody>
</PageContent>
);
}
}
Updates.propTypes = {
currentVersion: PropTypes.string.isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
updatesError: PropTypes.object,
generalSettingsError: PropTypes.object,
items: PropTypes.array.isRequired,
isInstallingUpdate: PropTypes.bool.isRequired,
isDocker: PropTypes.bool.isRequired,
updateMechanism: PropTypes.string,
updateMechanismMessage: PropTypes.string,
shortDateFormat: PropTypes.string.isRequired,
longDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,
onInstallLatestPress: PropTypes.func.isRequired
};
export default Updates;

View File

@@ -0,0 +1,303 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import * as commandNames from 'Commands/commandNames';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { icons, kinds } from 'Helpers/Props';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
import { fetchUpdates } from 'Store/Actions/systemActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import { UpdateMechanism } from 'typings/Settings/General';
import formatDate from 'Utilities/Date/formatDate';
import formatDateTime from 'Utilities/Date/formatDateTime';
import translate from 'Utilities/String/translate';
import UpdateChanges from './UpdateChanges';
import styles from './Updates.css';
const VERSION_REGEX = /\d+\.\d+\.\d+\.\d+/i;
function createUpdatesSelector() {
return createSelector(
(state: AppState) => state.system.updates,
(state: AppState) => state.settings.general,
(updates, generalSettings) => {
const { error: updatesError, items } = updates;
const isFetching = updates.isFetching || generalSettings.isFetching;
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
return {
isFetching,
isPopulated,
updatesError,
generalSettingsError: generalSettings.error,
items,
updateMechanism: generalSettings.item.updateMechanism,
};
}
);
}
function Updates() {
const currentVersion = useSelector((state: AppState) => state.app.version);
const { packageUpdateMechanismMessage } = useSelector(
createSystemStatusSelector()
);
const { shortDateFormat, longDateFormat, timeFormat } = useSelector(
createUISettingsSelector()
);
const isInstallingUpdate = useSelector(
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE)
);
const {
isFetching,
isPopulated,
updatesError,
generalSettingsError,
items,
updateMechanism,
} = useSelector(createUpdatesSelector());
const dispatch = useDispatch();
const [isMajorUpdateModalOpen, setIsMajorUpdateModalOpen] = useState(false);
const hasError = !!(updatesError || generalSettingsError);
const hasUpdates = isPopulated && !hasError && items.length > 0;
const noUpdates = isPopulated && !hasError && !items.length;
const externalUpdaterPrefix = translate('UpdateAppDirectlyLoadError');
const externalUpdaterMessages: Partial<Record<UpdateMechanism, string>> = {
external: translate('ExternalUpdater'),
apt: translate('AptUpdater'),
docker: translate('DockerUpdater'),
};
const { isMajorUpdate, hasUpdateToInstall } = useMemo(() => {
const majorVersion = parseInt(
currentVersion.match(VERSION_REGEX)?.[0] ?? '0'
);
const latestVersion = items[0]?.version;
const latestMajorVersion = parseInt(
latestVersion?.match(VERSION_REGEX)?.[0] ?? '0'
);
return {
isMajorUpdate: latestMajorVersion > majorVersion,
hasUpdateToInstall: items.some(
(update) => update.installable && update.latest
),
};
}, [currentVersion, items]);
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
const handleInstallLatestPress = useCallback(() => {
if (isMajorUpdate) {
setIsMajorUpdateModalOpen(true);
} else {
dispatch(executeCommand({ name: commandNames.APPLICATION_UPDATE }));
}
}, [isMajorUpdate, setIsMajorUpdateModalOpen, dispatch]);
const handleInstallLatestMajorVersionPress = useCallback(() => {
setIsMajorUpdateModalOpen(false);
dispatch(
executeCommand({
name: commandNames.APPLICATION_UPDATE,
installMajorUpdate: true,
})
);
}, [setIsMajorUpdateModalOpen, dispatch]);
const handleCancelMajorVersionPress = useCallback(() => {
setIsMajorUpdateModalOpen(false);
}, [setIsMajorUpdateModalOpen]);
useEffect(() => {
dispatch(fetchUpdates());
dispatch(fetchGeneralSettings());
}, [dispatch]);
return (
<PageContent title={translate('Updates')}>
<PageContentBody>
{isPopulated || hasError ? null : <LoadingIndicator />}
{noUpdates ? (
<Alert kind={kinds.INFO}>{translate('NoUpdatesAreAvailable')}</Alert>
) : null}
{hasUpdateToInstall ? (
<div className={styles.messageContainer}>
{updateMechanism === 'builtIn' || updateMechanism === 'script' ? (
<SpinnerButton
kind={kinds.PRIMARY}
isSpinning={isInstallingUpdate}
onPress={handleInstallLatestPress}
>
{translate('InstallLatest')}
</SpinnerButton>
) : (
<>
<Icon name={icons.WARNING} kind={kinds.WARNING} size={30} />
<div className={styles.message}>
{externalUpdaterPrefix}{' '}
<InlineMarkdown
data={
packageUpdateMechanismMessage ||
externalUpdaterMessages[updateMechanism] ||
externalUpdaterMessages.external
}
/>
</div>
</>
)}
{isFetching ? (
<LoadingIndicator className={styles.loading} size={20} />
) : null}
</div>
) : null}
{noUpdateToInstall && (
<div className={styles.messageContainer}>
<Icon
className={styles.upToDateIcon}
name={icons.CHECK_CIRCLE}
size={30}
/>
<div className={styles.message}>{translate('OnLatestVersion')}</div>
{isFetching && (
<LoadingIndicator className={styles.loading} size={20} />
)}
</div>
)}
{hasUpdates && (
<div>
{items.map((update) => {
return (
<div key={update.version} className={styles.update}>
<div className={styles.info}>
<div className={styles.version}>{update.version}</div>
<div className={styles.space}>&mdash;</div>
<div
className={styles.date}
title={formatDateTime(
update.releaseDate,
longDateFormat,
timeFormat
)}
>
{formatDate(update.releaseDate, shortDateFormat)}
</div>
{update.branch === 'master' ? null : (
<Label className={styles.label}>{update.branch}</Label>
)}
{update.version === currentVersion ? (
<Label
className={styles.label}
kind={kinds.SUCCESS}
title={formatDateTime(
update.installedOn,
longDateFormat,
timeFormat
)}
>
{translate('CurrentlyInstalled')}
</Label>
) : null}
{update.version !== currentVersion && update.installedOn ? (
<Label
className={styles.label}
kind={kinds.INVERSE}
title={formatDateTime(
update.installedOn,
longDateFormat,
timeFormat
)}
>
{translate('PreviouslyInstalled')}
</Label>
) : null}
</div>
{update.changes ? (
<div>
<UpdateChanges
title={translate('New')}
changes={update.changes.new}
/>
<UpdateChanges
title={translate('Fixed')}
changes={update.changes.fixed}
/>
</div>
) : (
<div>{translate('MaintenanceRelease')}</div>
)}
</div>
);
})}
</div>
)}
{updatesError ? (
<Alert kind={kinds.WARNING}>
{translate('FailedToFetchUpdates')}
</Alert>
) : null}
{generalSettingsError ? (
<Alert kind={kinds.DANGER}>
{translate('FailedToFetchSettings')}
</Alert>
) : null}
<ConfirmModal
isOpen={isMajorUpdateModalOpen}
kind={kinds.WARNING}
title={translate('InstallMajorVersionUpdate')}
message={
<div>
<div>{translate('InstallMajorVersionUpdateMessage')}</div>
<div>
<InlineMarkdown
data={translate('InstallMajorVersionUpdateMessageLink', {
domain: 'prowlarr.com',
url: 'https://prowlarr.com/#downloads',
})}
/>
</div>
</div>
}
confirmLabel={translate('Install')}
onConfirm={handleInstallLatestMajorVersionPress}
onCancel={handleCancelMajorVersionPress}
/>
</PageContentBody>
</PageContent>
);
}
export default Updates;

View File

@@ -1,101 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import * as commandNames from 'Commands/commandNames';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
import { fetchUpdates } from 'Store/Actions/systemActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import Updates from './Updates';
function createMapStateToProps() {
return createSelector(
(state) => state.app.version,
createSystemStatusSelector(),
(state) => state.system.updates,
(state) => state.settings.general,
createUISettingsSelector(),
createSystemStatusSelector(),
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
(
currentVersion,
status,
updates,
generalSettings,
uiSettings,
systemStatus,
isInstallingUpdate
) => {
const {
error: updatesError,
items
} = updates;
const isFetching = updates.isFetching || generalSettings.isFetching;
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
return {
currentVersion,
isFetching,
isPopulated,
updatesError,
generalSettingsError: generalSettings.error,
items,
isInstallingUpdate,
isDocker: systemStatus.isDocker,
updateMechanism: generalSettings.item.updateMechanism,
updateMechanismMessage: status.packageUpdateMechanismMessage,
shortDateFormat: uiSettings.shortDateFormat,
longDateFormat: uiSettings.longDateFormat,
timeFormat: uiSettings.timeFormat
};
}
);
}
const mapDispatchToProps = {
dispatchFetchUpdates: fetchUpdates,
dispatchFetchGeneralSettings: fetchGeneralSettings,
dispatchExecuteCommand: executeCommand
};
class UpdatesConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.dispatchFetchUpdates();
this.props.dispatchFetchGeneralSettings();
}
//
// Listeners
onInstallLatestPress = () => {
this.props.dispatchExecuteCommand({ name: commandNames.APPLICATION_UPDATE });
};
//
// Render
render() {
return (
<Updates
onInstallLatestPress={this.onInstallLatestPress}
{...this.props}
/>
);
}
}
UpdatesConnector.propTypes = {
dispatchFetchUpdates: PropTypes.func.isRequired,
dispatchFetchGeneralSettings: PropTypes.func.isRequired,
dispatchExecuteCommand: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(UpdatesConnector);

View File

@@ -17,7 +17,7 @@ export async function fetchTranslations(): Promise<boolean> {
translations = data.Strings;
resolve(true);
} catch (error) {
} catch {
resolve(false);
}
});

View File

@@ -1,5 +1,12 @@
import ModelBase from 'App/ModelBase';
export type HistoryQueryType =
| 'search'
| 'tvsearch'
| 'movie'
| 'book'
| 'music';
export interface HistoryData {
source: string;
host: string;
@@ -7,7 +14,7 @@ export interface HistoryData {
offset: number;
elapsedTime: number;
query: string;
queryType: string;
queryType: HistoryQueryType;
}
interface History extends ModelBase {

View File

@@ -0,0 +1,45 @@
export type UpdateMechanism =
| 'builtIn'
| 'script'
| 'external'
| 'apt'
| 'docker';
export default interface General {
bindAddress: string;
port: number;
sslPort: number;
enableSsl: boolean;
launchBrowser: boolean;
authenticationMethod: string;
authenticationRequired: string;
analyticsEnabled: boolean;
username: string;
password: string;
passwordConfirmation: string;
logLevel: string;
consoleLogLevel: string;
branch: string;
apiKey: string;
sslCertPath: string;
sslCertPassword: string;
urlBase: string;
instanceName: string;
applicationUrl: string;
updateAutomatically: boolean;
updateMechanism: UpdateMechanism;
updateScriptPath: string;
proxyEnabled: boolean;
proxyType: string;
proxyHostname: string;
proxyPort: number;
proxyUsername: string;
proxyPassword: string;
proxyBypassFilter: string;
proxyBypassLocalAddresses: boolean;
certificateValidation: string;
backupFolder: string;
backupInterval: number;
backupRetention: number;
id: number;
}

View File

@@ -1,4 +1,4 @@
export interface UiSettings {
export default interface UiSettings {
theme: 'auto' | 'dark' | 'light';
showRelativeDates: boolean;
shortDateFormat: string;

View File

@@ -22,6 +22,7 @@ interface SystemStatus {
osVersion: string;
packageAuthor: string;
packageUpdateMechanism: string;
packageUpdateMechanismMessage: string;
packageVersion: string;
runtimeName: string;
runtimeVersion: string;

View File

@@ -23,10 +23,10 @@
"defaults"
],
"dependencies": {
"@fortawesome/fontawesome-free": "6.6.0",
"@fortawesome/fontawesome-svg-core": "6.6.0",
"@fortawesome/free-regular-svg-icons": "6.6.0",
"@fortawesome/free-solid-svg-icons": "6.6.0",
"@fortawesome/fontawesome-free": "6.7.1",
"@fortawesome/fontawesome-svg-core": "6.7.1",
"@fortawesome/free-regular-svg-icons": "6.7.1",
"@fortawesome/free-solid-svg-icons": "6.7.1",
"@fortawesome/react-fontawesome": "0.2.2",
"@juggle/resize-observer": "3.4.0",
"@microsoft/signalr": "6.0.25",
@@ -81,30 +81,30 @@
"redux-thunk": "2.4.2",
"reselect": "4.1.8",
"stacktrace-js": "2.0.2",
"typescript": "5.1.6"
"typescript": "5.7.2"
},
"devDependencies": {
"@babel/core": "7.25.8",
"@babel/eslint-parser": "7.25.8",
"@babel/plugin-proposal-export-default-from": "7.25.8",
"@babel/core": "7.26.0",
"@babel/eslint-parser": "7.25.9",
"@babel/plugin-proposal-export-default-from": "7.25.9",
"@babel/plugin-syntax-dynamic-import": "7.8.3",
"@babel/preset-env": "7.25.8",
"@babel/preset-react": "7.25.7",
"@babel/preset-typescript": "7.25.7",
"@babel/preset-env": "7.26.0",
"@babel/preset-react": "7.26.3",
"@babel/preset-typescript": "7.26.0",
"@types/lodash": "4.14.195",
"@types/react-document-title": "2.0.10",
"@types/react-router-dom": "5.3.3",
"@types/react-text-truncate": "0.19.0",
"@types/react-window": "1.8.8",
"@types/webpack-livereload-plugin": "2.3.6",
"@typescript-eslint/eslint-plugin": "6.21.0",
"@typescript-eslint/parser": "6.21.0",
"@typescript-eslint/eslint-plugin": "8.18.1",
"@typescript-eslint/parser": "8.18.1",
"are-you-es5": "2.1.2",
"autoprefixer": "10.4.20",
"babel-loader": "9.2.1",
"babel-plugin-inline-classnames": "2.0.1",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
"core-js": "3.38.1",
"core-js": "3.39.0",
"css-loader": "6.7.3",
"css-modules-typescript-loader": "4.0.1",
"eslint": "8.57.1",

View File

@@ -21,9 +21,28 @@ namespace NzbDrone.Common.Test.ExtensionTests
[TestCase("1.2.3.4")]
[TestCase("172.55.0.1")]
[TestCase("192.55.0.1")]
[TestCase("100.64.0.1")]
[TestCase("100.127.255.254")]
public void should_return_false_for_public_ip_address(string ipAddress)
{
IPAddress.Parse(ipAddress).IsLocalAddress().Should().BeFalse();
}
[TestCase("100.64.0.1")]
[TestCase("100.127.255.254")]
[TestCase("100.100.100.100")]
public void should_return_true_for_cgnat_ip_address(string ipAddress)
{
IPAddress.Parse(ipAddress).IsCgnatIpAddress().Should().BeTrue();
}
[TestCase("1.2.3.4")]
[TestCase("192.168.5.1")]
[TestCase("100.63.255.255")]
[TestCase("100.128.0.0")]
public void should_return_false_for_non_cgnat_ip_address(string ipAddress)
{
IPAddress.Parse(ipAddress).IsCgnatIpAddress().Should().BeFalse();
}
}
}

View File

@@ -133,11 +133,16 @@ namespace NzbDrone.Common.Test
[TestCase(@"C:\test\", @"C:\Test\mydir")]
[TestCase(@"C:\test", @"C:\Test\mydir\")]
public void path_should_be_parent_on_windows_only(string parentPath, string childPath)
public void windows_path_should_be_parent(string parentPath, string childPath)
{
var expectedResult = OsInfo.IsWindows;
parentPath.IsParentPath(childPath).Should().Be(true);
}
parentPath.IsParentPath(childPath).Should().Be(expectedResult);
[TestCase("/test", "/test/mydir/")]
[TestCase("/test/", "/test/mydir")]
public void posix_path_should_be_parent(string parentPath, string childPath)
{
parentPath.IsParentPath(childPath).Should().Be(true);
}
[TestCase(@"C:\Test\mydir", @"C:\Test")]
@@ -145,20 +150,57 @@ namespace NzbDrone.Common.Test
[TestCase(@"C:\", null)]
[TestCase(@"\\server\share", null)]
[TestCase(@"\\server\share\test", @"\\server\share")]
public void path_should_return_parent_windows(string path, string parentPath)
public void windows_path_should_return_parent(string path, string parentPath)
{
WindowsOnly();
path.GetParentPath().Should().Be(parentPath);
}
[TestCase(@"/", null)]
[TestCase(@"/test", "/")]
public void path_should_return_parent_mono(string path, string parentPath)
[TestCase(@"/test/tv", "/test")]
public void unix_path_should_return_parent(string path, string parentPath)
{
PosixOnly();
path.GetParentPath().Should().Be(parentPath);
}
[TestCase(@"C:\Test\mydir", "Test")]
[TestCase(@"C:\Test\", @"C:\")]
[TestCase(@"C:\Test", @"C:\")]
[TestCase(@"C:\", null)]
[TestCase(@"\\server\share", null)]
[TestCase(@"\\server\share\test", @"\\server\share")]
public void path_should_return_parent_name_windows(string path, string parentPath)
{
path.GetParentName().Should().Be(parentPath);
}
[TestCase(@"/", null)]
[TestCase(@"/test", "/")]
[TestCase(@"/test/tv", "test")]
public void path_should_return_parent_name_mono(string path, string parentPath)
{
path.GetParentName().Should().Be(parentPath);
}
[TestCase(@"C:\Test\mydir", "mydir")]
[TestCase(@"C:\Test\", "Test")]
[TestCase(@"C:\Test", "Test")]
[TestCase(@"C:\", "C:\\")]
[TestCase(@"\\server\share", @"\\server\share")]
[TestCase(@"\\server\share\test", "test")]
public void path_should_return_directory_name_windows(string path, string parentPath)
{
path.GetDirectoryName().Should().Be(parentPath);
}
[TestCase(@"/", "/")]
[TestCase(@"/test", "test")]
[TestCase(@"/test/tv", "tv")]
public void path_should_return_directory_name_mono(string path, string parentPath)
{
path.GetDirectoryName().Should().Be(parentPath);
}
[Test]
public void path_should_return_parent_for_oversized_path()
{
@@ -166,7 +208,7 @@ namespace NzbDrone.Common.Test
// This test will fail on Windows if long path support is not enabled: https://www.howtogeek.com/266621/how-to-make-windows-10-accept-file-paths-over-260-characters/
// It will also fail if the app isn't configured to use long path (such as resharper): https://blogs.msdn.microsoft.com/jeremykuhne/2016/07/30/net-4-6-2-and-long-paths-on-windows-10/
var path = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories".AsOsAgnostic();
var path = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories".AsOsAgnostic();
var parentPath = @"C:\media\2e168617-f2ae-43fb-b88c-3663af1c8eea\downloads\sabnzbd\nzbdrone\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing\With.Alot.Of.Nested.Directories\Some.Real.Big.Thing".AsOsAgnostic();
path.GetParentPath().Should().Be(parentPath);
@@ -350,5 +392,46 @@ namespace NzbDrone.Common.Test
PosixOnly();
path.AsOsAgnostic().IsPathValid(PathValidationType.CurrentOs).Should().BeFalse();
}
[TestCase(@"C:\", @"C:\")]
[TestCase(@"C:\\", @"C:\")]
[TestCase(@"C:\Test", @"C:\Test")]
[TestCase(@"C:\Test\", @"C:\Test")]
[TestCase(@"\\server\share", @"\\server\share")]
[TestCase(@"\\server\share\", @"\\server\share")]
public void windows_path_should_return_clean_path(string path, string cleanPath)
{
path.GetCleanPath().Should().Be(cleanPath);
}
[TestCase("/", "/")]
[TestCase("//", "/")]
[TestCase("/test", "/test")]
[TestCase("/test/", "/test")]
[TestCase("/test//", "/test")]
public void unix_path_should_return_clean_path(string path, string cleanPath)
{
path.GetCleanPath().Should().Be(cleanPath);
}
[TestCase(@"C:\Test\", @"C:\Test\Series Title", "Series Title")]
[TestCase(@"C:\Test\", @"C:\Test\Collection\Series Title", @"Collection\Series Title")]
[TestCase(@"C:\Test\mydir\", @"C:\Test\mydir\Collection\Series Title", @"Collection\Series Title")]
[TestCase(@"\\server\share", @"\\server\share\Series Title", "Series Title")]
[TestCase(@"\\server\share\mydir\", @"\\server\share\mydir\/Collection\Series Title", @"Collection\Series Title")]
public void windows_path_should_return_relative_path(string parentPath, string childPath, string relativePath)
{
parentPath.GetRelativePath(childPath).Should().Be(relativePath);
}
[TestCase(@"/test", "/test/Series Title", "Series Title")]
[TestCase(@"/test/", "/test/Collection/Series Title", "Collection/Series Title")]
[TestCase(@"/test/mydir", "/test/mydir/Series Title", "Series Title")]
[TestCase(@"/test/mydir/", "/test/mydir/Collection/Series Title", "Collection/Series Title")]
[TestCase(@"/test/mydir/", @"/test/mydir/\Collection/Series Title", "Collection/Series Title")]
public void unix_path_should_return_relative_path(string parentPath, string childPath, string relativePath)
{
parentPath.GetRelativePath(childPath).Should().Be(relativePath);
}
}
}

View File

@@ -189,6 +189,25 @@ namespace NzbDrone.Common.Disk
}
var fi = new FileInfo(path);
try
{
// If the file is a symlink, resolve the target path and get the size of the target file.
if (fi.Attributes.HasFlag(FileAttributes.ReparsePoint))
{
var targetPath = fi.ResolveLinkTarget(true)?.FullName;
if (targetPath != null)
{
fi = new FileInfo(targetPath);
}
}
}
catch (IOException ex)
{
Logger.Trace(ex, "Unable to resolve symlink target for {0}", path);
}
return fi.Length;
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Common.Disk
@@ -9,6 +10,8 @@ namespace NzbDrone.Common.Disk
private readonly string _path;
private readonly OsPathKind _kind;
private static readonly Regex UncPathRegex = new Regex(@"(?<unc>^\\\\(?:\?\\UNC\\)?[^\\]+\\[^\\]+)(?:\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public OsPath(string path)
{
if (path == null)
@@ -96,6 +99,29 @@ namespace NzbDrone.Common.Disk
return path;
}
private static string TrimTrailingSlash(string path, OsPathKind kind)
{
switch (kind)
{
case OsPathKind.Windows when !path.EndsWith(":\\"):
while (!path.EndsWith(":\\") && path.EndsWith('\\'))
{
path = path[..^1];
}
return path;
case OsPathKind.Unix when path != "/":
while (path != "/" && path.EndsWith('/'))
{
path = path[..^1];
}
return path;
}
return path;
}
public OsPathKind Kind => _kind;
public bool IsWindowsPath => _kind == OsPathKind.Windows;
@@ -130,7 +156,19 @@ namespace NzbDrone.Common.Disk
if (index == -1)
{
return new OsPath(null);
return Null;
}
var rootLength = GetRootLength();
if (rootLength == _path.Length)
{
return Null;
}
if (rootLength > index + 1)
{
return new OsPath(_path.Substring(0, rootLength));
}
return new OsPath(_path.Substring(0, index), _kind).AsDirectory();
@@ -139,6 +177,8 @@ namespace NzbDrone.Common.Disk
public string FullPath => _path;
public string PathWithoutTrailingSlash => TrimTrailingSlash(_path, _kind);
public string FileName
{
get
@@ -161,6 +201,29 @@ namespace NzbDrone.Common.Disk
}
}
public string Name
{
// Meant to behave similar to DirectoryInfo.Name
get
{
var index = GetFileNameIndex();
if (index == -1)
{
return PathWithoutTrailingSlash;
}
var rootLength = GetRootLength();
if (rootLength > index + 1)
{
return _path.Substring(0, rootLength);
}
return TrimTrailingSlash(_path.Substring(index).TrimStart('/', '\\'), _kind);
}
}
public bool IsValid => _path.IsPathValid(PathValidationType.CurrentOs);
private int GetFileNameIndex()
@@ -190,11 +253,50 @@ namespace NzbDrone.Common.Disk
return index;
}
private int GetRootLength()
{
if (!IsRooted)
{
return 0;
}
if (_kind == OsPathKind.Unix)
{
return 1;
}
if (_kind == OsPathKind.Windows)
{
if (HasWindowsDriveLetter(_path))
{
return 3;
}
var uncMatch = UncPathRegex.Match(_path);
// \\?\UNC\server\share\ or \\server\share
if (uncMatch.Success)
{
return uncMatch.Groups["unc"].Length;
}
// \\?\C:\
if (_path.StartsWith(@"\\?\"))
{
return 7;
}
}
return 0;
}
private string[] GetFragments()
{
return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
}
public static OsPath Null => new (null);
public override string ToString()
{
return _path;
@@ -267,6 +369,11 @@ namespace NzbDrone.Common.Disk
}
public bool Equals(OsPath other)
{
return Equals(other, false);
}
public bool Equals(OsPath other, bool ignoreTrailingSlash)
{
if (ReferenceEquals(other, null))
{
@@ -278,8 +385,8 @@ namespace NzbDrone.Common.Disk
return true;
}
var left = _path;
var right = other._path;
var left = ignoreTrailingSlash ? PathWithoutTrailingSlash : _path;
var right = ignoreTrailingSlash ? other.PathWithoutTrailingSlash : other._path;
if (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows)
{

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using NLog;
@@ -25,22 +24,25 @@ namespace NzbDrone.Common.EnvironmentInfo
static OsInfo()
{
var platform = Environment.OSVersion.Platform;
switch (platform)
if (OperatingSystem.IsWindows())
{
case PlatformID.Win32NT:
{
Os = Os.Windows;
break;
}
case PlatformID.MacOSX:
case PlatformID.Unix:
{
Os = GetPosixFlavour();
break;
}
Os = Os.Windows;
}
else if (OperatingSystem.IsMacOS())
{
Os = Os.Osx;
}
else if (OperatingSystem.IsFreeBSD())
{
Os = Os.Bsd;
}
else
{
#if ISMUSL
Os = Os.LinuxMusl;
#else
Os = Os.Linux;
#endif
}
}
@@ -84,59 +86,6 @@ namespace NzbDrone.Common.EnvironmentInfo
IsDocker = true;
}
}
private static Os GetPosixFlavour()
{
var output = RunAndCapture("uname", "-s");
if (output.StartsWith("Darwin"))
{
return Os.Osx;
}
else if (output.Contains("BSD"))
{
return Os.Bsd;
}
else
{
#if ISMUSL
return Os.LinuxMusl;
#else
return Os.Linux;
#endif
}
}
private static string RunAndCapture(string filename, string args)
{
var processStartInfo = new ProcessStartInfo
{
FileName = filename,
Arguments = args,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
};
var output = string.Empty;
try
{
using (var p = Process.Start(processStartInfo))
{
// To avoid deadlocks, always read the output stream first and then wait.
output = p.StandardOutput.ReadToEnd();
p.WaitForExit(1000);
}
}
catch (Exception)
{
output = string.Empty;
}
return output;
}
}
public interface IOsInfo

View File

@@ -39,18 +39,24 @@ namespace NzbDrone.Common.Extensions
private static bool IsLocalIPv4(byte[] ipv4Bytes)
{
// Link local (no IP assigned by DHCP): 169.254.0.0 to 169.254.255.255 (169.254.0.0/16)
bool IsLinkLocal() => ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
var isLinkLocal = ipv4Bytes[0] == 169 && ipv4Bytes[1] == 254;
// Class A private range: 10.0.0.0 10.255.255.255 (10.0.0.0/8)
bool IsClassA() => ipv4Bytes[0] == 10;
var isClassA = ipv4Bytes[0] == 10;
// Class B private range: 172.16.0.0 172.31.255.255 (172.16.0.0/12)
bool IsClassB() => ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
var isClassB = ipv4Bytes[0] == 172 && ipv4Bytes[1] >= 16 && ipv4Bytes[1] <= 31;
// Class C private range: 192.168.0.0 192.168.255.255 (192.168.0.0/16)
bool IsClassC() => ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
var isClassC = ipv4Bytes[0] == 192 && ipv4Bytes[1] == 168;
return IsLinkLocal() || IsClassA() || IsClassC() || IsClassB();
return isLinkLocal || isClassA || isClassC || isClassB;
}
public static bool IsCgnatIpAddress(this IPAddress ipAddress)
{
var bytes = ipAddress.GetAddressBytes();
return bytes.Length == 4 && bytes[0] == 100 && bytes[1] >= 64 && bytes[1] <= 127;
}
}
}

View File

@@ -25,8 +25,6 @@ namespace NzbDrone.Common.Extensions
private static readonly string UPDATE_CLIENT_FOLDER_NAME = "Prowlarr.Update" + Path.DirectorySeparatorChar;
private static readonly string UPDATE_LOG_FOLDER_NAME = "UpdateLogs" + Path.DirectorySeparatorChar;
private static readonly Regex PARENT_PATH_END_SLASH_REGEX = new Regex(@"(?<!:)\\$", RegexOptions.Compiled);
public static string CleanFilePath(this string path)
{
if (path.IsNotNullOrWhiteSpace())
@@ -87,55 +85,50 @@ namespace NzbDrone.Common.Extensions
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
}
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
return childPath.Substring(parentPath.Length).Trim('\\', '/');
}
public static string GetParentPath(this string childPath)
{
var cleanPath = OsInfo.IsWindows
? PARENT_PATH_END_SLASH_REGEX.Replace(childPath, "")
: childPath.TrimEnd(Path.DirectorySeparatorChar);
var path = new OsPath(childPath).Directory;
if (cleanPath.IsNullOrWhiteSpace())
{
return null;
}
return path == OsPath.Null ? null : path.PathWithoutTrailingSlash;
}
return Directory.GetParent(cleanPath)?.FullName;
public static string GetParentName(this string childPath)
{
var path = new OsPath(childPath).Directory;
return path == OsPath.Null ? null : path.Name;
}
public static string GetDirectoryName(this string childPath)
{
var path = new OsPath(childPath);
return path == OsPath.Null ? null : path.Name;
}
public static string GetCleanPath(this string path)
{
var cleanPath = OsInfo.IsWindows
? PARENT_PATH_END_SLASH_REGEX.Replace(path, "")
: path.TrimEnd(Path.DirectorySeparatorChar);
var osPath = new OsPath(path);
return cleanPath;
return osPath == OsPath.Null ? null : osPath.PathWithoutTrailingSlash;
}
public static bool IsParentPath(this string parentPath, string childPath)
{
if (parentPath != "/" && !parentPath.EndsWith(":\\"))
{
parentPath = parentPath.TrimEnd(Path.DirectorySeparatorChar);
}
var parent = new OsPath(parentPath);
var child = new OsPath(childPath);
if (childPath != "/" && !parentPath.EndsWith(":\\"))
while (child.Directory != OsPath.Null)
{
childPath = childPath.TrimEnd(Path.DirectorySeparatorChar);
}
var parent = new DirectoryInfo(parentPath);
var child = new DirectoryInfo(childPath);
while (child.Parent != null)
{
if (child.Parent.FullName.Equals(parent.FullName, DiskProviderBase.PathStringComparison))
if (child.Directory.Equals(parent, true))
{
return true;
}
child = child.Parent;
child = child.Directory;
}
return false;
@@ -150,14 +143,14 @@ namespace NzbDrone.Common.Extensions
return false;
}
if (path.Trim() != path)
{
return false;
}
// Only check for leading or trailing spaces for path when running on Windows.
if (OsInfo.IsWindows)
{
if (path.Trim() != path)
{
return false;
}
var directoryInfo = new DirectoryInfo(path);
while (directoryInfo != null)

View File

@@ -109,7 +109,7 @@ namespace NzbDrone.Common.Http
if (response.HasHttpRedirect && !RuntimeInfo.IsProduction)
{
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]);
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.RedirectUrl);
}
if (!request.SuppressHttpError && response.HasHttpError && (request.SuppressHttpErrorStatusCodes == null || !request.SuppressHttpErrorStatusCodes.Contains(response.StatusCode)))

View File

@@ -119,7 +119,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
o.Environment = BuildInfo.Branch;
// Crash free run statistics (sends a ping for healthy and for crashes sessions)
o.AutoSessionTracking = true;
o.AutoSessionTracking = false;
// Caches files in the event device is offline
// Sentry creates a 'sentry' sub directory, no need to concat here
@@ -148,7 +148,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
_debounce = new SentryDebounce();
// initialize to true and reconfigure later
// Otherwise it will default to false and any errors occuring
// Otherwise it will default to false and any errors occurring
// before config file gets read will not be filtered
FilterEvents = true;
SentryEnabled = true;
@@ -207,9 +207,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
private void OnError(Exception ex)
{
var webException = ex as WebException;
if (webException != null)
if (ex is WebException webException)
{
var response = webException.Response as HttpWebResponse;
var statusCode = response?.StatusCode;

View File

@@ -6,4 +6,5 @@ public class AuthOptions
public bool? Enabled { get; set; }
public string Method { get; set; }
public string Required { get; set; }
public bool? TrustCgnatIpAddresses { get; set; }
}

View File

@@ -313,7 +313,7 @@ namespace NzbDrone.Common.Processes
processInfo = new ProcessInfo();
processInfo.Id = process.Id;
processInfo.Name = process.ProcessName;
processInfo.StartPath = process.MainModule.FileName;
processInfo.StartPath = process.MainModule?.FileName;
if (process.Id != GetCurrentProcessId() && process.HasExited)
{

View File

@@ -5,17 +5,18 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
<PackageReference Include="IPAddressRange" Version="6.0.0" />
<PackageReference Include="IPAddressRange" Version="6.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.3.3" />
<PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.0" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.12" />
<PackageReference Include="Npgsql" Version="7.0.8" />
<PackageReference Include="Npgsql" Version="7.0.9" />
<PackageReference Include="Sentry" Version="4.0.2" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Text.Json" Version="6.0.10" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />

View File

@@ -0,0 +1,43 @@
using System;
using System.Data.SQLite;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Converters;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Converters;
[TestFixture]
public class TimeSpanConverterFixture : CoreTest<TimeSpanConverter>
{
private SQLiteParameter _param;
[SetUp]
public void Setup()
{
_param = new SQLiteParameter();
}
[Test]
public void should_return_string_when_saving_timespan_to_db()
{
var span = TimeSpan.FromMilliseconds(10);
Subject.SetValue(_param, span);
_param.Value.Should().Be(span.ToString());
}
[Test]
public void should_return_timespan_when_getting_string_from_db()
{
var span = TimeSpan.FromMilliseconds(10);
Subject.Parse(span.ToString()).Should().Be(span);
}
[Test]
public void should_return_zero_timespan_for_db_null_value_when_getting_from_db()
{
Subject.Parse(null).Should().Be(TimeSpan.Zero);
}
}

View File

@@ -0,0 +1,38 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Test.Datastore;
[TestFixture]
public class DatabaseVersionParserFixture
{
[TestCase("3.44.2", 3, 44, 2)]
public void should_parse_sqlite_database_version(string serverVersion, int majorVersion, int minorVersion, int buildVersion)
{
var version = DatabaseVersionParser.ParseServerVersion(serverVersion);
version.Should().NotBeNull();
version.Major.Should().Be(majorVersion);
version.Minor.Should().Be(minorVersion);
version.Build.Should().Be(buildVersion);
}
[TestCase("14.8 (Debian 14.8-1.pgdg110+1)", 14, 8, null)]
[TestCase("16.3 (Debian 16.3-1.pgdg110+1)", 16, 3, null)]
[TestCase("16.3 - Percona Distribution", 16, 3, null)]
[TestCase("17.0 - Percona Server", 17, 0, null)]
public void should_parse_postgres_database_version(string serverVersion, int majorVersion, int minorVersion, int? buildVersion)
{
var version = DatabaseVersionParser.ParseServerVersion(serverVersion);
version.Should().NotBeNull();
version.Major.Should().Be(majorVersion);
version.Minor.Should().Be(minorVersion);
if (buildVersion.HasValue)
{
version.Build.Should().Be(buildVersion.Value);
}
}
}

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
torrentInfo.InfoUrl.Should().Be("https://filelist.io/details.php?id=665873");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 19:20:19"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 20:20:19"));
torrentInfo.Size.Should().Be(8300512414);
torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -46,8 +46,8 @@ namespace NzbDrone.Core.Test.IndexerTests.RedactedTests
torrentInfo.Title.Should().Be("Red Hot Chili Peppers - Californication (1999) [Album] [US / Reissue 2020] [FLAC 24bit Lossless / Vinyl]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("https://redacted.ch/ajax.php?action=download&id=3892313");
torrentInfo.InfoUrl.Should().Be("https://redacted.ch/torrents.php?id=16720&torrentid=3892313");
torrentInfo.DownloadUrl.Should().Be("https://redacted.sh/ajax.php?action=download&id=3892313");
torrentInfo.InfoUrl.Should().Be("https://redacted.sh/torrents.php?id=16720&torrentid=3892313");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2022-12-17 08:02:35"));

View File

@@ -35,18 +35,18 @@ namespace NzbDrone.Core.Test.UpdateTests
{
_updatePackage = new UpdatePackage
{
FileName = "NzbDrone.develop.2.0.0.0.tar.gz",
FileName = "NzbDrone.develop.1.0.0.0.tar.gz",
Url = "http://download.sonarr.tv/v2/develop/mono/NzbDrone.develop.tar.gz",
Version = new Version("2.0.0.0")
Version = new Version("1.0.0.0")
};
}
else
{
_updatePackage = new UpdatePackage
{
FileName = "NzbDrone.develop.2.0.0.0.zip",
FileName = "NzbDrone.develop.1.0.0.0.zip",
Url = "http://download.sonarr.tv/v2/develop/windows/NzbDrone.develop.zip",
Version = new Version("2.0.0.0")
Version = new Version("1.0.0.0")
};
}
@@ -90,17 +90,6 @@ namespace NzbDrone.Core.Test.UpdateTests
.Returns(true);
}
[Test]
public void should_not_update_if_inside_docker()
{
Mocker.GetMock<IOsInfo>().Setup(x => x.IsDocker).Returns(true);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[Test]
public void should_delete_sandbox_before_update_if_folder_exists()
{
@@ -338,6 +327,28 @@ namespace NzbDrone.Core.Test.UpdateTests
.Verify(v => v.SaveConfigDictionary(It.Is<Dictionary<string, object>>(d => d.ContainsKey("Branch") && (string)d["Branch"] == "fake")), Times.Once());
}
[Test]
public void should_not_update_with_built_in_updater_inside_docker_container()
{
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.PackageUpdateMechanism).Returns(UpdateMechanism.Docker);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[Test]
public void should_not_update_with_built_in_updater_when_external_updater_is_configured()
{
Mocker.GetMock<IDeploymentInfoProvider>().Setup(x => x.IsExternalUpdateMechanism).Returns(true);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IProcessProvider>()
.Verify(c => c.Start(It.IsAny<string>(), It.Is<string>(s => s.StartsWith("12")), null, null, null), Times.Never());
}
[TearDown]
public void TearDown()
{

View File

@@ -53,7 +53,7 @@ namespace NzbDrone.Core.Applications
foreach (var application in applications)
{
if (blockedApplications.TryGetValue(application.Definition.Id, out var blockedApplicationStatus))
if (blockedApplications.TryGetValue(application.Definition.Id, out var blockedApplicationStatus) && blockedApplicationStatus.DisabledTill.HasValue)
{
_logger.Debug("Temporarily ignoring application {0} till {1} due to recent failures.", application.Definition.Name, blockedApplicationStatus.DisabledTill.Value.ToLocalTime());
continue;

View File

@@ -127,6 +127,8 @@ namespace NzbDrone.Core.Applications
private void SyncIndexers(List<IApplication> applications, List<IndexerDefinition> indexers, bool removeRemote = false, bool forceSync = false)
{
var sortedIndexers = indexers.OrderBy(i => i.Name, StringComparer.OrdinalIgnoreCase).ToList();
foreach (var app in applications)
{
var indexerMappings = _appIndexerMapService.GetMappingsForApp(app.Definition.Id);
@@ -157,7 +159,7 @@ namespace NzbDrone.Core.Applications
}
}
foreach (var indexer in indexers)
foreach (var indexer in sortedIndexers)
{
var definition = indexer;

View File

@@ -65,6 +65,7 @@ namespace NzbDrone.Core.Configuration
string PostgresPassword { get; }
string PostgresMainDb { get; }
string PostgresLogDb { get; }
bool TrustCgnatIpAddresses { get; }
}
public class ConfigFileProvider : IConfigFileProvider
@@ -479,5 +480,7 @@ namespace NzbDrone.Core.Configuration
SetValue("ApiKey", GenerateApiKey());
_eventAggregator.PublishEvent(new ApiKeyChangedEvent());
}
public bool TrustCgnatIpAddresses => _authOptions.TrustCgnatIpAddresses ?? GetValueBoolean("TrustCgnatIpAddresses", false, persist: false);
}
}

View File

@@ -183,6 +183,12 @@ namespace NzbDrone.Core.Configuration
public string ApplicationUrl => GetValue("ApplicationUrl", string.Empty);
public bool TrustCgnatIpAddresses
{
get { return GetValueBoolean("TrustCgnatIpAddresses", false); }
set { SetValue("TrustCgnatIpAddresses", value); }
}
private string GetValue(string key)
{
return GetValue(key, string.Empty);

View File

@@ -2,18 +2,17 @@ using System;
using System.Data;
using Dapper;
namespace NzbDrone.Core.Datastore.Converters
{
public class DapperTimeSpanConverter : SqlMapper.TypeHandler<TimeSpan>
{
public override void SetValue(IDbDataParameter parameter, TimeSpan value)
{
parameter.Value = value.ToString();
}
namespace NzbDrone.Core.Datastore.Converters;
public override TimeSpan Parse(object value)
{
return TimeSpan.Parse((string)value);
}
public class TimeSpanConverter : SqlMapper.TypeHandler<TimeSpan>
{
public override void SetValue(IDbDataParameter parameter, TimeSpan value)
{
parameter.Value = value.ToString();
}
public override TimeSpan Parse(object value)
{
return value is string str ? TimeSpan.Parse(str) : TimeSpan.Zero;
}
}

View File

@@ -2,7 +2,6 @@ using System;
using System.Data;
using System.Data.Common;
using System.Data.SQLite;
using System.Text.RegularExpressions;
using Dapper;
using NLog;
using NzbDrone.Common.Instrumentation;
@@ -52,9 +51,8 @@ namespace NzbDrone.Core.Datastore
{
using var db = _datamapperFactory();
var dbConnection = db as DbConnection;
var version = Regex.Replace(dbConnection.ServerVersion, @"\(.*?\)", "");
return new Version(version);
return DatabaseVersionParser.ParseServerVersion(dbConnection.ServerVersion);
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.Datastore;
public static class DatabaseVersionParser
{
private static readonly Regex VersionRegex = new (@"^[^ ]+", RegexOptions.Compiled);
public static Version ParseServerVersion(string serverVersion)
{
var match = VersionRegex.Match(serverVersion);
return match.Success ? new Version(match.Value) : null;
}
}

View File

@@ -109,7 +109,6 @@ namespace NzbDrone.Core.Datastore
SqlMapper.RemoveTypeMap(typeof(DateTime));
SqlMapper.AddTypeHandler(new DapperUtcConverter());
SqlMapper.AddTypeHandler(new DapperTimeSpanConverter());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Dictionary<string, string>>());
SqlMapper.AddTypeHandler(new CookieConverter());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>());
@@ -123,6 +122,9 @@ namespace NzbDrone.Core.Datastore
SqlMapper.RemoveTypeMap(typeof(Guid));
SqlMapper.RemoveTypeMap(typeof(Guid?));
SqlMapper.AddTypeHandler(new GuidConverter());
SqlMapper.RemoveTypeMap(typeof(TimeSpan));
SqlMapper.RemoveTypeMap(typeof(TimeSpan?));
SqlMapper.AddTypeHandler(new TimeSpanConverter());
SqlMapper.AddTypeHandler(new CommandConverter());
SqlMapper.AddTypeHandler(new SystemVersionConverter());
}

View File

@@ -25,8 +25,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
Dictionary<string, QBittorrentLabel> GetLabels(QBittorrentSettings settings);
void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, QBittorrentSettings settings);
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
void PauseTorrent(string hash, QBittorrentSettings settings);
void ResumeTorrent(string hash, QBittorrentSettings settings);
void SetForceStart(string hash, bool enabled, QBittorrentSettings settings);
}

View File

@@ -146,7 +146,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
{
request.AddFormParameter("paused", true);
}
@@ -176,7 +176,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
{
request.AddFormParameter("paused", true);
}
@@ -212,7 +212,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// if setCategory fails due to method not being found, then try older setLabel command for qBittorrent < v.3.3.5
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
{
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
.Post()
@@ -254,7 +254,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// qBittorrent rejects all Prio commands with 403: Forbidden if Options -> BitTorrent -> Torrent Queueing is not enabled
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Forbidden)
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Forbidden)
{
return;
}
@@ -263,22 +263,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
}
public void PauseTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/pause")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void ResumeTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/resume")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/setForceStart")

View File

@@ -246,14 +246,20 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
request.AddFormParameter("category", category);
}
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
// Avoid extraneous API version check if initial state is ForceStart
if ((QBittorrentState)settings.InitialState is QBittorrentState.Start or QBittorrentState.Stop)
{
request.AddFormParameter("paused", false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Pause)
{
request.AddFormParameter("paused", true);
var stoppedParameterName = GetApiVersion(settings) >= new Version(2, 11, 0) ? "stopped" : "paused";
// Note: ForceStart is handled by separate api call
if ((QBittorrentState)settings.InitialState == QBittorrentState.Start)
{
request.AddFormParameter(stoppedParameterName, false);
}
else if ((QBittorrentState)settings.InitialState == QBittorrentState.Stop)
{
request.AddFormParameter(stoppedParameterName, true);
}
}
if (settings.SequentialOrder)
@@ -291,7 +297,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// setShareLimits was added in api v2.0.1 so catch it case of the unlikely event that someone has api v2.0
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.NotFound)
{
return;
}
@@ -313,7 +319,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
catch (DownloadClientException ex)
{
// qBittorrent rejects all Prio commands with 409: Conflict if Options -> BitTorrent -> Torrent Queueing is not enabled
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.Conflict)
if (ex.InnerException is HttpException httpException && httpException.Response.StatusCode == HttpStatusCode.Conflict)
{
return;
}
@@ -322,22 +328,6 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
}
public void PauseTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/pause")
.Post()
.AddFormParameter("hashes", hash);
ProcessRequest(request, settings);
}
public void ResumeTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/resume")
.Post()
.AddFormParameter("hashes", hash);
ProcessRequest(request, settings);
}
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/api/v2/torrents/setForceStart")

View File

@@ -1,9 +1,16 @@
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public enum QBittorrentState
{
[FieldOption(Label = "Started")]
Start = 0,
[FieldOption(Label = "Force Started")]
ForceStart = 1,
Pause = 2
[FieldOption(Label = "Stopped")]
Stop = 2
}
}

View File

@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download
foreach (var client in clients)
{
if (blockedClients.TryGetValue(client.Definition.Id, out var downloadClientStatus))
if (blockedClients.TryGetValue(client.Definition.Id, out var downloadClientStatus) && downloadClientStatus.DisabledTill.HasValue)
{
_logger.Debug("Temporarily ignoring download client {0} till {1} due to recent failures.", client.Definition.Name, downloadClientStatus.DisabledTill.Value.ToLocalTime());
continue;

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
private readonly IHttpRequestBuilderFactory _cloudRequestBuilder;
private readonly Logger _logger;
public SystemTimeCheck(IHttpClient client, IProwlarrCloudRequestBuilder cloudRequestBuilder, ILocalizationService localizationService, Logger logger)
public SystemTimeCheck(IHttpClient client, IProwlarrCloudRequestBuilder cloudRequestBuilder, Logger logger, ILocalizationService localizationService)
: base(localizationService)
{
_client = client;
@@ -29,19 +29,26 @@ namespace NzbDrone.Core.HealthCheck.Checks
return new HealthCheck(GetType());
}
var request = _cloudRequestBuilder.Create()
.Resource("/time")
.Build();
var response = _client.Execute(request);
var result = Json.Deserialize<ServiceTimeResponse>(response.Content);
var systemTime = DateTime.UtcNow;
// +/- more than 1 day
if (Math.Abs(result.DateTimeUtc.Subtract(systemTime).TotalDays) >= 1)
try
{
_logger.Error("System time mismatch. SystemTime: {0} Expected Time: {1}. Update system time", systemTime, result.DateTimeUtc);
return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("SystemTimeCheckMessage"));
var request = _cloudRequestBuilder.Create()
.Resource("/time")
.Build();
var response = _client.Execute(request);
var result = Json.Deserialize<ServiceTimeResponse>(response.Content);
var systemTime = DateTime.UtcNow;
// +/- more than 1 day
if (Math.Abs(result.DateTimeUtc.Subtract(systemTime).TotalDays) >= 1)
{
_logger.Error("System time mismatch. SystemTime: {0} Expected Time: {1}. Update system time", systemTime, result.DateTimeUtc);
return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("SystemTimeHealthCheckMessage"), "#system-time-off");
}
}
catch (Exception e)
{
_logger.Warn(e, "Unable to verify system time");
}
return new HealthCheck(GetType());

View File

@@ -93,7 +93,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
if (latestAvailable != null)
{
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
BuildInfo.BuildDateTime.Before(DateTime.UtcNow.AddDays(-180)) ? HealthCheckResult.Error : HealthCheckResult.Warning,
_localizationService.GetLocalizedString("UpdateAvailableHealthCheckMessage", new Dictionary<string, object>
{
{ "version", $"v{latestAvailable.Version}" }

View File

@@ -326,8 +326,8 @@ namespace NzbDrone.Core.Indexers.Definitions
{
public BeyondHDSettingsValidator()
{
RuleFor(c => c.ApiKey).NotEmpty();
RuleFor(c => c.RssKey).NotEmpty();
RuleFor(c => c.ApiKey).NotEmpty().Length(32);
RuleFor(c => c.RssKey).NotEmpty().Length(32);
}
}

View File

@@ -39,22 +39,22 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
var indexerLogging = _configService.LogIndexerResponse;
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
if (indexerResponse.HttpResponse.HasHttpRedirect && indexerResponse.HttpResponse.RedirectUrl.IsNotNullOrWhiteSpace())
{
if (indexerResponse.HttpResponse.HasHttpRedirect)
_logger.Warn("Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
if (indexerResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("/login.php"))
{
_logger.Warn("Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
if (indexerResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("/login.php"))
{
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer.");
}
throw new IndexerException(indexerResponse, $"Redirected to {indexerResponse.HttpResponse.RedirectUrl} from indexer request");
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie or credentials and try testing the indexer.");
}
throw new IndexerException(indexerResponse, $"Redirected to {indexerResponse.HttpResponse.RedirectUrl} from indexer request");
}
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
}

View File

@@ -77,7 +77,7 @@ public class FileListParser : IParseIndexerResponse
InfoUrl = GetInfoUrl(id),
Seeders = row.Seeders,
Peers = row.Leechers + row.Seeders,
PublishDate = DateTime.Parse(row.UploadDate + " +0300", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
PublishDate = DateTime.Parse(row.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
Description = row.SmallDescription,
Genres = row.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
ImdbId = imdbId,

View File

@@ -95,3 +95,8 @@ public class GazelleIndexResponse
public string Authkey { get; set; }
public string Passkey { get; set; }
}
public class GazelleErrorResponse
{
public string Error { get; init; }
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Net;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -32,7 +33,9 @@ public class GazelleParser : IParseIndexerResponse
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
STJson.TryDeserialize<GazelleErrorResponse>(indexerResponse.Content, out var errorResponse);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request: {errorResponse?.Error ?? "Check the logs for more information."}");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))

View File

@@ -7,6 +7,7 @@ using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Gazelle;
@@ -148,7 +149,9 @@ public class GreatPosterWallParser : GazelleParser
throw new IndexerException(indexerResponse, $"Redirected to {indexerResponse.HttpResponse.RedirectUrl} from indexer request");
}
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
STJson.TryDeserialize<GazelleErrorResponse>(indexerResponse.Content, out var errorResponse);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request: {errorResponse?.Error ?? "Check the logs for more information."}");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))

View File

@@ -189,7 +189,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var qc = new NameValueCollection();
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories))
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Distinct())
{
qc.Add(cat, string.Empty);
}
@@ -203,10 +203,13 @@ namespace NzbDrone.Core.Indexers.Definitions
{
// ipt uses sphinx, which supports boolean operators and grouping
qc.Add("q", "+(" + imdbId + ")");
// search in description
qc.Add("qf", "all");
}
// changed from else if to if to support searching imdbid + season/episode in the same query
if (!string.IsNullOrWhiteSpace(term))
// changed from "else if" to "if" to support searching imdbid + season/episode in the same query
if (term.IsNotNullOrWhiteSpace())
{
// similar to above
qc.Add("q", "+(" + term + ")");

View File

@@ -80,7 +80,7 @@ namespace NzbDrone.Core.Indexers.Definitions
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return httpResponse.Content.Contains("You do not have permission to access this page.");
return !httpResponse.Content.Contains("logout.php");
}
private IndexerCapabilities SetCapabilities()

View File

@@ -0,0 +1,349 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
using static Newtonsoft.Json.Formatting;
namespace NzbDrone.Core.Indexers.Definitions
{
public class Knaben : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "Knaben";
public override string[] IndexerUrls => new[] { "https://knaben.org/" };
public override string[] LegacyUrls => new[] { "https://knaben.eu/" };
public override string Description => "Knaben is a Public torrent meta-search engine";
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
public override IndexerCapabilities Capabilities => SetCapabilities();
public Knaben(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
}
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new KnabenRequestGenerator(Capabilities);
}
public override IParseIndexerResponse GetParser()
{
return new KnabenParser(Capabilities.Categories);
}
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
};
caps.Categories.AddCategoryMapping(1000000, NewznabStandardCategory.Audio, "Audio");
caps.Categories.AddCategoryMapping(1001000, NewznabStandardCategory.AudioMP3, "MP3");
caps.Categories.AddCategoryMapping(1002000, NewznabStandardCategory.AudioLossless, "Lossless");
caps.Categories.AddCategoryMapping(1003000, NewznabStandardCategory.AudioAudiobook, "Audiobook");
caps.Categories.AddCategoryMapping(1004000, NewznabStandardCategory.AudioVideo, "Audio Video");
caps.Categories.AddCategoryMapping(1005000, NewznabStandardCategory.AudioOther, "Radio");
caps.Categories.AddCategoryMapping(1006000, NewznabStandardCategory.AudioOther, "Audio Other");
caps.Categories.AddCategoryMapping(2000000, NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping(2001000, NewznabStandardCategory.TVHD, "TV HD");
caps.Categories.AddCategoryMapping(2002000, NewznabStandardCategory.TVSD, "TV SD");
caps.Categories.AddCategoryMapping(2003000, NewznabStandardCategory.TVUHD, "TV UHD");
caps.Categories.AddCategoryMapping(2004000, NewznabStandardCategory.TVDocumentary, "Documentary");
caps.Categories.AddCategoryMapping(2005000, NewznabStandardCategory.TVForeign, "TV Foreign");
caps.Categories.AddCategoryMapping(2006000, NewznabStandardCategory.TVSport, "Sport");
caps.Categories.AddCategoryMapping(2007000, NewznabStandardCategory.TVOther, "Cartoon");
caps.Categories.AddCategoryMapping(2008000, NewznabStandardCategory.TVOther, "TV Other");
caps.Categories.AddCategoryMapping(3000000, NewznabStandardCategory.Movies, "Movies");
caps.Categories.AddCategoryMapping(3001000, NewznabStandardCategory.MoviesHD, "Movies HD");
caps.Categories.AddCategoryMapping(3002000, NewznabStandardCategory.MoviesSD, "Movies SD");
caps.Categories.AddCategoryMapping(3003000, NewznabStandardCategory.MoviesUHD, "Movies UHD");
caps.Categories.AddCategoryMapping(3004000, NewznabStandardCategory.MoviesDVD, "Movies DVD");
caps.Categories.AddCategoryMapping(3005000, NewznabStandardCategory.MoviesForeign, "Movies Foreign");
caps.Categories.AddCategoryMapping(3006000, NewznabStandardCategory.MoviesForeign, "Movies Bollywood");
caps.Categories.AddCategoryMapping(3007000, NewznabStandardCategory.Movies3D, "Movies 3D");
caps.Categories.AddCategoryMapping(3008000, NewznabStandardCategory.MoviesOther, "Movies Other");
caps.Categories.AddCategoryMapping(4000000, NewznabStandardCategory.PC, "PC");
caps.Categories.AddCategoryMapping(4001000, NewznabStandardCategory.PCGames, "Games");
caps.Categories.AddCategoryMapping(4002000, NewznabStandardCategory.PC0day, "Software");
caps.Categories.AddCategoryMapping(4003000, NewznabStandardCategory.PCMac, "Mac");
caps.Categories.AddCategoryMapping(4004000, NewznabStandardCategory.PCISO, "Unix");
caps.Categories.AddCategoryMapping(5000000, NewznabStandardCategory.XXX, "XXX");
caps.Categories.AddCategoryMapping(5001000, NewznabStandardCategory.XXXx264, "XXX Video");
caps.Categories.AddCategoryMapping(5002000, NewznabStandardCategory.XXXImageSet, "XXX ImageSet");
caps.Categories.AddCategoryMapping(5003000, NewznabStandardCategory.XXXOther, "XXX Games");
caps.Categories.AddCategoryMapping(5004000, NewznabStandardCategory.XXXOther, "XXX Hentai");
caps.Categories.AddCategoryMapping(5005000, NewznabStandardCategory.XXXOther, "XXX Other");
caps.Categories.AddCategoryMapping(6000000, NewznabStandardCategory.TVAnime, "Anime");
caps.Categories.AddCategoryMapping(6001000, NewznabStandardCategory.TVAnime, "Anime Subbed");
caps.Categories.AddCategoryMapping(6002000, NewznabStandardCategory.TVAnime, "Anime Dubbed");
caps.Categories.AddCategoryMapping(6003000, NewznabStandardCategory.TVAnime, "Anime Dual audio");
caps.Categories.AddCategoryMapping(6004000, NewznabStandardCategory.TVAnime, "Anime Raw");
caps.Categories.AddCategoryMapping(6005000, NewznabStandardCategory.AudioVideo, "Music Video");
caps.Categories.AddCategoryMapping(6006000, NewznabStandardCategory.BooksOther, "Literature");
caps.Categories.AddCategoryMapping(6007000, NewznabStandardCategory.AudioOther, "Music");
caps.Categories.AddCategoryMapping(6008000, NewznabStandardCategory.TVAnime, "Anime non-english translated");
caps.Categories.AddCategoryMapping(7000000, NewznabStandardCategory.Console, "Console");
caps.Categories.AddCategoryMapping(7001000, NewznabStandardCategory.ConsolePS4, "PS4");
caps.Categories.AddCategoryMapping(7002000, NewznabStandardCategory.ConsolePS3, "PS3");
caps.Categories.AddCategoryMapping(7003000, NewznabStandardCategory.ConsolePS3, "PS2");
caps.Categories.AddCategoryMapping(7004000, NewznabStandardCategory.ConsolePS3, "PS1");
caps.Categories.AddCategoryMapping(7005000, NewznabStandardCategory.ConsolePSVita, "PS Vita");
caps.Categories.AddCategoryMapping(7006000, NewznabStandardCategory.ConsolePSP, "PSP");
caps.Categories.AddCategoryMapping(7007000, NewznabStandardCategory.ConsoleXBox360, "Xbox 360");
caps.Categories.AddCategoryMapping(7008000, NewznabStandardCategory.ConsoleXBox, "Xbox");
caps.Categories.AddCategoryMapping(7009000, NewznabStandardCategory.ConsoleNDS, "Switch");
caps.Categories.AddCategoryMapping(7010000, NewznabStandardCategory.ConsoleNDS, "NDS");
caps.Categories.AddCategoryMapping(7011000, NewznabStandardCategory.ConsoleWii, "Wii");
caps.Categories.AddCategoryMapping(7012000, NewznabStandardCategory.ConsoleWiiU, "WiiU");
caps.Categories.AddCategoryMapping(7013000, NewznabStandardCategory.Console3DS, "3DS");
caps.Categories.AddCategoryMapping(7014000, NewznabStandardCategory.ConsoleWii, "GameCube");
caps.Categories.AddCategoryMapping(7015000, NewznabStandardCategory.ConsoleOther, "Other");
caps.Categories.AddCategoryMapping(8000000, NewznabStandardCategory.PCMobileOther, "Mobile");
caps.Categories.AddCategoryMapping(8001000, NewznabStandardCategory.PCMobileAndroid, "Android");
caps.Categories.AddCategoryMapping(8002000, NewznabStandardCategory.PCMobileiOS, "IOS");
caps.Categories.AddCategoryMapping(8003000, NewznabStandardCategory.PCMobileOther, "PC Other");
caps.Categories.AddCategoryMapping(9000000, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(9001000, NewznabStandardCategory.BooksEBook, "EBooks");
caps.Categories.AddCategoryMapping(9002000, NewznabStandardCategory.BooksComics, "Comics");
caps.Categories.AddCategoryMapping(9003000, NewznabStandardCategory.BooksMags, "Magazines");
caps.Categories.AddCategoryMapping(9004000, NewznabStandardCategory.BooksTechnical, "Technical");
caps.Categories.AddCategoryMapping(9005000, NewznabStandardCategory.BooksOther, "Books Other");
caps.Categories.AddCategoryMapping(10000000, NewznabStandardCategory.Other, "Other");
caps.Categories.AddCategoryMapping(10001000, NewznabStandardCategory.OtherMisc, "Other Misc");
return caps;
}
}
public class KnabenRequestGenerator : IIndexerRequestGenerator
{
private const string ApiSearchEndpoint = "https://api.knaben.org/v1";
private readonly IndexerCapabilities _capabilities;
public KnabenRequestGenerator(IndexerCapabilities capabilities)
{
_capabilities = capabilities;
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedTvSearchString));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(CreateRequest(searchCriteria, searchCriteria.SanitizedSearchTerm));
return pageableRequests;
}
private IEnumerable<IndexerRequest> CreateRequest(SearchCriteriaBase searchCriteria, string searchTerm)
{
var body = new Dictionary<string, object>
{
{ "order_by", "date" },
{ "order_direction", "desc" },
{ "from", 0 },
{ "size", 100 },
{ "hide_unsafe", true }
};
var searchQuery = searchTerm.Trim();
if (searchQuery.IsNotNullOrWhiteSpace())
{
body.Add("search_type", "100%");
body.Add("search_field", "title");
body.Add("query", searchQuery);
}
var categories = _capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
if (categories is { Count: > 0 })
{
body.Add("categories", categories.Select(int.Parse).Distinct().ToArray());
}
var request = new HttpRequest(ApiSearchEndpoint, HttpAccept.Json)
{
Headers =
{
ContentType = "application/json"
},
Method = HttpMethod.Post
};
request.SetContent(body.ToJson());
request.ContentSummary = body.ToJson(None);
yield return new IndexerRequest(request);
}
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class KnabenParser : IParseIndexerResponse
{
private static readonly Regex DateTimezoneRegex = new (@"[+-]\d{2}:\d{2}$", RegexOptions.Compiled);
private readonly IndexerCapabilitiesCategories _categories;
public KnabenParser(IndexerCapabilitiesCategories categories)
{
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var indexerHttpResponse = indexerResponse.HttpResponse;
if (indexerHttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerHttpResponse.StatusCode} code from indexer request");
}
if (!indexerHttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
{
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerHttpResponse.Headers.ContentType} from indexer request, expected {HttpAccept.Json.Value}");
}
var releaseInfos = new List<ReleaseInfo>();
var jsonResponse = STJson.Deserialize<KnabenResponse>(indexerResponse.Content);
if (jsonResponse?.Hits == null)
{
return releaseInfos;
}
var rows = jsonResponse.Hits.Where(r => r.Seeders > 0).ToList();
foreach (var row in rows)
{
// Not all entries have the TZ in the "date" field
var publishDate = row.Date.IsNotNullOrWhiteSpace() && !DateTimezoneRegex.IsMatch(row.Date) ? $"{row.Date}+01:00" : row.Date;
var releaseInfo = new TorrentInfo
{
Guid = row.InfoUrl,
Title = row.Title,
InfoUrl = row.InfoUrl,
DownloadUrl = row.DownloadUrl.IsNotNullOrWhiteSpace() ? row.DownloadUrl : null,
MagnetUrl = row.MagnetUrl.IsNotNullOrWhiteSpace() ? row.MagnetUrl : null,
Categories = row.CategoryIds.SelectMany(cat => _categories.MapTrackerCatToNewznab(cat.ToString())).Distinct().ToList(),
InfoHash = row.InfoHash,
Size = row.Size,
Seeders = row.Seeders,
Peers = row.Leechers + row.Seeders,
PublishDate = DateTime.Parse(publishDate, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
DownloadVolumeFactor = 0,
UploadVolumeFactor = 1
};
releaseInfos.Add(releaseInfo);
}
// order by date
return releaseInfos;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
internal sealed class KnabenResponse
{
public IReadOnlyCollection<KnabenRelease> Hits { get; init; } = Array.Empty<KnabenRelease>();
}
internal sealed class KnabenRelease
{
public string Title { get; init; }
[JsonPropertyName("categoryId")]
public IReadOnlyCollection<int> CategoryIds { get; init; } = Array.Empty<int>();
[JsonPropertyName("hash")]
public string InfoHash { get; init; }
[JsonPropertyName("details")]
public string InfoUrl { get; init; }
[JsonPropertyName("link")]
public string DownloadUrl { get; init; }
public string MagnetUrl { get; init; }
[JsonPropertyName("bytes")]
public long Size { get; init; }
public int Seeders { get; init; }
[JsonPropertyName("peers")]
public int Leechers { get; init; }
public string Date { get; init; }
}
}

View File

@@ -19,7 +19,6 @@ using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -385,11 +384,6 @@ public class MTeamTpParser : IParseIndexerResponse
MinimumSeedTime = 172800 // 2 days
};
if (torrent.Imdb.IsNotNullOrWhiteSpace())
{
release.ImdbId = ParseUtil.GetImdbId(torrent.Imdb.TrimEnd('/').Split('/').LastOrDefault()).GetValueOrDefault();
}
if (torrent.Status?.CreatedDate != null &&
DateTime.TryParseExact($"{torrent.Status.CreatedDate} +08:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var publishDate))
{

View File

@@ -441,6 +441,11 @@ namespace NzbDrone.Core.Indexers.Definitions
return releaseInfos.ToArray();
}
if (jsonResponse.Data == null)
{
throw new IndexerException(indexerResponse, "Unexpected response content from indexer request: {0}", jsonResponse.Message ?? "Check the logs for more information.");
}
var hasUserVip = HasUserVip(httpResponse.GetCookies());
foreach (var item in jsonResponse.Data)
@@ -655,7 +660,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public class MyAnonamouseResponse
{
public string Error { get; set; }
public List<MyAnonamouseTorrent> Data { get; set; }
public IReadOnlyCollection<MyAnonamouseTorrent> Data { get; set; }
public string Message { get; set; }
}
public class MyAnonamouseBuyPersonalFreeleechResponse

View File

@@ -42,7 +42,8 @@ namespace NzbDrone.Core.Indexers.Newznab
RuleFor(c => c.VipExpiration).Must(c => c.IsFutureDate())
.When(c => c.VipExpiration.IsNotNullOrWhiteSpace())
.WithMessage("Must be a future date");
.WithMessage("Must be a future date")
.AsWarning();
}
}

View File

@@ -190,7 +190,7 @@ public class NorBitsRequestGenerator : IIndexerRequestGenerator
}
else if (!string.IsNullOrWhiteSpace(term))
{
searchTerm = "search=" + term.UrlEncode(Encoding.GetEncoding(28591));
searchTerm = "search=" + term.UrlEncode(Encoding.UTF8);
}
searchUrl += "?" + searchTerm + "&" + parameters.GetQueryString();

View File

@@ -20,6 +20,7 @@ using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.Definitions
{
[Obsolete("Site has removed API access.")]
public class NzbIndex : UsenetIndexerBase<NzbIndexSettings>
{
public override string Name => "NZBIndex";

View File

@@ -8,6 +8,7 @@ using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Gazelle;
@@ -252,7 +253,9 @@ namespace NzbDrone.Core.Indexers.Definitions
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
STJson.TryDeserialize<GazelleErrorResponse>(indexerResponse.Content, out var errorResponse);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request: {errorResponse?.Error ?? "Check the logs for more information."}");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))

View File

@@ -8,6 +8,7 @@ using FluentValidation;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Gazelle;
@@ -24,7 +25,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Redacted : TorrentIndexerBase<RedactedSettings>
{
public override string Name => "Redacted";
public override string[] IndexerUrls => new[] { "https://redacted.ch/" };
public override string[] IndexerUrls => new[] { "https://redacted.sh/" };
public override string[] LegacyUrls => new[] { "https://redacted.ch/" };
public override string Description => "REDActed (Aka.PassTheHeadPhones) is one of the most well-known music trackers.";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
@@ -251,7 +253,9 @@ namespace NzbDrone.Core.Indexers.Definitions
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
STJson.TryDeserialize<GazelleErrorResponse>(indexerResponse.Content, out var errorResponse);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request: {errorResponse?.Error ?? "Check the logs for more information."}");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))

View File

@@ -1292,7 +1292,6 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(650, NewznabStandardCategory.PCMobileOther, "Игры для мобильных устройств");
caps.Categories.AddCategoryMapping(2149, NewznabStandardCategory.PCMobileAndroid, "|- Игры для Android");
caps.Categories.AddCategoryMapping(2420, NewznabStandardCategory.ConsoleOther, "|- Игры для Oculus Quest");
caps.Categories.AddCategoryMapping(1001, NewznabStandardCategory.PC, "|- Игры для Java");
caps.Categories.AddCategoryMapping(1004, NewznabStandardCategory.PCMobileOther, "|- Игры для Symbian");
caps.Categories.AddCategoryMapping(1002, NewznabStandardCategory.PCMobileOther, "|- Игры для Windows Mobile");
caps.Categories.AddCategoryMapping(240, NewznabStandardCategory.OtherMisc, "Игровое видео");
@@ -1308,7 +1307,6 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(1379, NewznabStandardCategory.PC, "|- Операционные системы (Linux, Unix)");
caps.Categories.AddCategoryMapping(1381, NewznabStandardCategory.PC, "|- Программное обеспечение (Linux, Unix)");
caps.Categories.AddCategoryMapping(1473, NewznabStandardCategory.PC, "|- Другие ОС и ПО под них");
caps.Categories.AddCategoryMapping(1195, NewznabStandardCategory.PC, "Тестовые диски для настройки аудио/видео аппаратуры");
caps.Categories.AddCategoryMapping(1013, NewznabStandardCategory.PC, "Системные программы");
caps.Categories.AddCategoryMapping(1028, NewznabStandardCategory.PC, "|- Работа с жёстким диском");
caps.Categories.AddCategoryMapping(1029, NewznabStandardCategory.PC, "|- Резервное копирование");
@@ -1350,6 +1348,7 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(1018, NewznabStandardCategory.PC, "|- Шаблоны для сайтов и CMS");
caps.Categories.AddCategoryMapping(1058, NewznabStandardCategory.PC, "|- Разное (Веб-разработка и программирование)");
caps.Categories.AddCategoryMapping(1016, NewznabStandardCategory.PC, "Программы для работы с мультимедиа и 3D");
caps.Categories.AddCategoryMapping(1195, NewznabStandardCategory.PC, "|- Тестовые диски для настройки аудио/видео аппаратуры");
caps.Categories.AddCategoryMapping(1079, NewznabStandardCategory.PC, "|- Программные комплекты");
caps.Categories.AddCategoryMapping(1080, NewznabStandardCategory.PC, "|- Плагины для программ компании Adobe");
caps.Categories.AddCategoryMapping(1081, NewznabStandardCategory.PC, "|- Графические редакторы");

View File

@@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Definitions.Gazelle;
using NzbDrone.Core.Indexers.Exceptions;
@@ -78,7 +79,9 @@ public class SecretCinemaParser : IParseIndexerResponse
// Remove cookie cache
CookiesUpdater(null, null);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request");
STJson.TryDeserialize<GazelleErrorResponse>(indexerResponse.Content, out var errorResponse);
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from indexer request: {errorResponse?.Error ?? "Check the logs for more information."}");
}
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using FluentValidation.Results;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
@@ -44,6 +46,13 @@ namespace NzbDrone.Core.Indexers.Definitions.TorrentRss
}
}
protected override Task<ValidationFailure> TestConnection()
{
UpdateCookies(null, null);
return base.TestConnection();
}
private IndexerDefinition GetDefinition(string name, string description, TorrentRssIndexerSettings settings)
{
return new IndexerDefinition

View File

@@ -650,7 +650,7 @@ namespace NzbDrone.Core.Indexers
{
foreach (var cookie in Cookies)
{
request.HttpRequest.Cookies.Add(cookie.Key, cookie.Value);
request.HttpRequest.Cookies[cookie.Key] = cookie.Value;
}
}
@@ -761,7 +761,7 @@ namespace NzbDrone.Core.Indexers
if (releases.Releases.Empty())
{
return new ValidationFailure(string.Empty, "Query successful, but no results were returned from your indexer. This may be an issue with the indexer, your indexer category settings, or other indexer settings such as search freeleech only etc.");
return new ValidationFailure(string.Empty, "Query successful, but no results were returned from your indexer. This may be an issue with the indexer, your indexer category settings, or other indexer settings such as search freeleech only etc. See the FAQ for details.");
}
}
catch (IndexerAuthException ex)

View File

@@ -242,7 +242,7 @@ namespace NzbDrone.Core.Indexers
foreach (var indexer in indexers)
{
if (blockedIndexers.TryGetValue(indexer.Definition.Id, out var blockedIndexerStatus))
if (blockedIndexers.TryGetValue(indexer.Definition.Id, out var blockedIndexerStatus) && blockedIndexerStatus.DisabledTill.HasValue)
{
_logger.Debug("Temporarily ignoring indexer {0} till {1} due to recent failures.", indexer.Definition.Name, blockedIndexerStatus.DisabledTill.Value.ToLocalTime());
continue;

View File

@@ -1,3 +1,4 @@
using System;
using System.Text;
using MonoTorrent;
using NLog;
@@ -22,10 +23,10 @@ namespace NzbDrone.Core.Indexers
{
Torrent.Load(fileData);
}
catch
catch (Exception ex)
{
_logger.Debug("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
throw;
throw new NotSupportedException($"Invalid torrent file contents. Reason: {ex.Message}", ex);
}
}
}

View File

@@ -60,33 +60,36 @@ namespace NzbDrone.Core.Instrumentation
{
try
{
var log = new Log();
log.Time = logEvent.TimeStamp;
log.Message = CleanseLogMessage.Cleanse(logEvent.FormattedMessage);
log.Logger = logEvent.LoggerName;
var log = new Log
{
Time = logEvent.TimeStamp,
Logger = logEvent.LoggerName,
Level = logEvent.Level.Name
};
if (log.Logger.StartsWith("NzbDrone."))
{
log.Logger = log.Logger.Remove(0, 9);
}
var message = logEvent.FormattedMessage;
if (logEvent.Exception != null)
{
if (string.IsNullOrWhiteSpace(log.Message))
if (string.IsNullOrWhiteSpace(message))
{
log.Message = logEvent.Exception.Message;
message = logEvent.Exception.Message;
}
else
{
log.Message += ": " + logEvent.Exception.Message;
message += ": " + logEvent.Exception.Message;
}
log.Exception = logEvent.Exception.ToString();
log.Exception = CleanseLogMessage.Cleanse(logEvent.Exception.ToString());
log.ExceptionType = logEvent.Exception.GetType().ToString();
}
log.Level = logEvent.Level.Name;
log.Message = CleanseLogMessage.Cleanse(message);
var connectionInfo = _connectionStringFactory.LogDbConnection;

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Jobs
new ScheduledTask
{
Interval = 6 * 60,
TypeName = typeof(ApplicationCheckUpdateCommand).FullName
TypeName = typeof(ApplicationUpdateCheckCommand).FullName
},
new ScheduledTask

View File

@@ -59,14 +59,14 @@
"SelectAll": "اختر الكل",
"SendAnonymousUsageData": "إرسال بيانات الاستخدام المجهولة",
"Style": "أسلوب",
"SystemTimeCheckMessage": "توقف وقت النظام بأكثر من يوم واحد. قد لا تعمل المهام المجدولة بشكل صحيح حتى يتم تصحيح الوقت",
"SystemTimeHealthCheckMessage": "توقف وقت النظام بأكثر من يوم واحد. قد لا تعمل المهام المجدولة بشكل صحيح حتى يتم تصحيح الوقت",
"TableOptionsColumnsMessage": "اختر الأعمدة المرئية والترتيب الذي تظهر به",
"TagCannotBeDeletedWhileInUse": "لا يمكن حذفه أثناء الاستخدام",
"Tasks": "مهام",
"UnableToAddANewAppProfilePleaseTryAgain": "غير قادر على إضافة ملف تعريف جودة جديد ، يرجى المحاولة مرة أخرى.",
"UnableToAddANewDownloadClientPleaseTryAgain": "غير قادر على إضافة عميل تنزيل جديد ، يرجى المحاولة مرة أخرى.",
"UnableToAddANewIndexerPleaseTryAgain": "غير قادر على إضافة مفهرس جديد ، يرجى المحاولة مرة أخرى.",
"UnableToLoadBackups": "تعذر تحميل النسخ الاحتياطية",
"BackupsLoadError": "تعذر تحميل النسخ الاحتياطية",
"UnsavedChanges": "التغييرات غير المحفوظة",
"UpdateUiNotWritableHealthCheckMessage": "لا يمكن تثبيت التحديث لأن مجلد واجهة المستخدم '{uiFolder}' غير قابل للكتابة بواسطة المستخدم '{userName}'",
"UpdateScriptPathHelpText": "المسار إلى برنامج نصي مخصص يأخذ حزمة تحديث مستخرجة ويتعامل مع ما تبقى من عملية التحديث",
@@ -329,7 +329,7 @@
"Queued": "في قائمة الانتظار",
"Remove": "إزالة",
"Replace": "يحل محل",
"TheLatestVersionIsAlreadyInstalled": "تم بالفعل تثبيت أحدث إصدار من {0}",
"OnLatestVersion": "تم بالفعل تثبيت أحدث إصدار من {0}",
"DownloadClientPriorityHelpText": "تحديد أولويات عملاء التنزيل المتعددين. يتم استخدام Round-Robin للعملاء الذين لديهم نفس الأولوية.",
"ApplyTagsHelpTextAdd": "إضافة: أضف العلامات إلى قائمة العلامات الموجودة",
"ApplyTagsHelpTextHowToApplyApplications": "كيفية تطبيق العلامات على الأفلام المختارة",
@@ -361,5 +361,19 @@
"Script": "النصي",
"BuiltIn": "مدمج",
"PublishedDate": "تاريخ النشر",
"AllSearchResultsHiddenByFilter": "يتم إخفاء جميع النتائج بواسطة عامل التصفية المطبق"
"AllSearchResultsHiddenByFilter": "يتم إخفاء جميع النتائج بواسطة عامل التصفية المطبق",
"NoEventsFound": "لم يتم العثور على أحداث",
"RestartReloadNote": "ملاحظة: سيتم إعادة تشغيل {appName} تلقائيًا وإعادة تحميل واجهة المستخدم أثناء عملية الاستعادة.",
"UpdateAppDirectlyLoadError": "تعذر تحديث {appName} مباشرة ،",
"DockerUpdater": "تحديث حاوية عامل الإرساء لتلقي التحديث",
"Download": "تحميل",
"ErrorRestoringBackup": "خطأ في استعادة النسخة الاحتياطية",
"ExternalUpdater": "تم تكوين {appName} لاستخدام آلية تحديث خارجية",
"InstallLatest": "تثبيت الأحدث",
"AptUpdater": "استخدم apt لتثبيت التحديث",
"Clone": "قريب",
"Stats": "الحالة",
"CurrentlyInstalled": "مثبتة حاليا",
"Season": "السبب",
"Mixed": "ثابت"
}

View File

@@ -90,7 +90,7 @@
"SSLPort": "SSL порт",
"Status": "Състояние",
"System": "Система",
"SystemTimeCheckMessage": "Системното време е изключено с повече от 1 ден. Планираните задачи може да не се изпълняват правилно, докато времето не бъде коригирано",
"SystemTimeHealthCheckMessage": "Системното време е изключено с повече от 1 ден. Планираните задачи може да не се изпълняват правилно, докато времето не бъде коригирано",
"TestAll": "Тествайте всички",
"Title": "Заглавие",
"Today": "Днес",
@@ -153,7 +153,7 @@
"UISettings": "Настройки на потребителския интерфейс",
"UnableToAddANewApplicationPleaseTryAgain": "Не може да се добави ново известие, моля, опитайте отново.",
"UnableToAddANewAppProfilePleaseTryAgain": "Не може да се добави нов качествен профил, моля, опитайте отново.",
"UnableToLoadBackups": "Архивите не могат да се заредят",
"BackupsLoadError": "Архивите не могат да се заредят",
"AllIndexersHiddenDueToFilter": "Всички филми са скрити поради приложен филтър.",
"Level": "Ниво",
"ApplicationStatusCheckAllClientMessage": "Всички списъци са недостъпни поради неуспехи",
@@ -329,7 +329,7 @@
"Queued": "На опашка",
"Remove": "Премахване",
"Replace": "Сменете",
"TheLatestVersionIsAlreadyInstalled": "Вече е инсталирана най-новата версия на {0}",
"OnLatestVersion": "Вече е инсталирана най-новата версия на {0}",
"Genre": "Жанрове",
"ApplyTagsHelpTextRemove": "Премахване: Премахнете въведените тагове",
"ApplyTagsHelpTextHowToApplyIndexers": "Как да приложите тагове към избраните филми",
@@ -361,5 +361,20 @@
"BuiltIn": "Вграден",
"Script": "Сценарий",
"PublishedDate": "Дата на публикуване",
"AllSearchResultsHiddenByFilter": "Всички резултати са скрити от приложения филтър"
"AllSearchResultsHiddenByFilter": "Всички резултати са скрити от приложения филтър",
"DockerUpdater": "актуализирайте контейнера на докера, за да получите актуализацията",
"Download": "Изтегли",
"ErrorRestoringBackup": "Грешка при възстановяване на архивиране",
"ExternalUpdater": "{appName} е конфигуриран да използва външен механизъм за актуализация",
"NoEventsFound": "Няма намерени събития",
"RestartReloadNote": "Забележка: {appName} автоматично ще рестартира и презареди потребителския интерфейс по време на процеса на възстановяване.",
"UpdateAppDirectlyLoadError": "Не може да се актуализира {appName} директно,",
"AptUpdater": "Използвайте apt, за да инсталирате актуализацията",
"InstallLatest": "Инсталирайте най-новите",
"Clone": "Близо",
"ActiveApps": "Активни приложения",
"ActiveIndexers": "Активни индиксатори",
"AddApplication": "добави приложение",
"Season": "Причина",
"CurrentlyInstalled": "Понастоящем инсталиран"
}

View File

@@ -43,7 +43,7 @@
"Type": "Tipus",
"UILanguageHelpTextWarning": "Es requereix una recàrrega del navegador",
"UISettings": "Configuració de la interfície",
"UnableToLoadBackups": "No es poden carregar còpies de seguretat",
"BackupsLoadError": "No es poden carregar còpies de seguretat",
"DownloadClientsLoadError": "No es poden carregar els clients de baixada",
"UnableToLoadTags": "No es poden carregar les etiquetes",
"UnableToLoadUISettings": "No es pot carregar la configuració de la IU",
@@ -136,7 +136,7 @@
"Priority": "Prioritat",
"SendAnonymousUsageData": "Envia dades d'ús anònimes",
"SetTags": "Estableix etiquetes",
"SystemTimeCheckMessage": "L'hora del sistema està apagada durant més d'1 dia. És possible que les tasques programades no s'executin correctament fins que no es corregeixi l'hora",
"SystemTimeHealthCheckMessage": "L'hora del sistema està apagada durant més d'1 dia. És possible que les tasques programades no s'executin correctament fins que no es corregeixi l'hora",
"TableOptions": "Opcions de taula",
"TableOptionsColumnsMessage": "Trieu quines columnes són visibles i en quin ordre apareixen",
"Columns": "Columnes",
@@ -340,7 +340,7 @@
"UILanguageHelpText": "Idioma que utilitzarà {appName} per a la interfície d'usuari",
"Remove": "Elimina",
"Replace": "Substitueix",
"TheLatestVersionIsAlreadyInstalled": "La darrera versió de {appName} ja està instal·lada",
"OnLatestVersion": "La darrera versió de {appName} ja està instal·lada",
"ThemeHelpText": "Canvieu el tema de la interfície d'usuari de l'aplicació, el tema \"Automàtic\" utilitzarà el tema del vostre sistema operatiu per configurar el mode clar o fosc. Inspirat en {inspiredBy}.",
"ApplicationURL": "URL de l'aplicació",
"Publisher": "Editor",
@@ -485,5 +485,20 @@
"PublishedDate": "Data de publicació",
"Redirected": "Redirecció",
"AllSearchResultsHiddenByFilter": "Tots els resultats estan ocults pel filtre aplicat",
"HealthMessagesInfoBox": "Podeu trobar més informació sobre la causa d'aquests missatges de comprovació de salut fent clic a l'enllaç wiki (icona del llibre) al final de la fila o consultant els vostres [registres]({link}). Si teniu problemes per a interpretar aquests missatges, podeu posar-vos en contacte amb el nostre suport als enllaços següents."
"HealthMessagesInfoBox": "Podeu trobar més informació sobre la causa d'aquests missatges de comprovació de salut fent clic a l'enllaç wiki (icona del llibre) al final de la fila o consultant els vostres [registres]({link}). Si teniu problemes per a interpretar aquests missatges, podeu posar-vos en contacte amb el nostre suport als enllaços següents.",
"AptUpdater": "Utilitzeu apt per a instal·lar l'actualització",
"DockerUpdater": "actualitzeu el contenidor Docker per a rebre l'actualització",
"Download": "Baixa",
"ErrorRestoringBackup": "S'ha produït un error en restaurar la còpia de seguretat",
"ExternalUpdater": "{appName} està configurat per a utilitzar un mecanisme d'actualització extern",
"FailedToFetchUpdates": "No s'han pogut obtenir les actualitzacions",
"LogFilesLocation": "Els fitxers de registre es troben a: {location}",
"Logout": "Tanca la sessió",
"NoEventsFound": "No s'han trobat esdeveniments",
"RestartReloadNote": "Nota: {appName} es reiniciarà i tornarà a carregar automàticament la interfície d'usuari durant el procés de restauració.",
"TheLogLevelDefault": "El nivell de registre per defecte és \"Info\" i es pot canviar a [Configuració general](/configuració/general)",
"UpdateAppDirectlyLoadError": "No es pot actualitzar {appName} directament,",
"WouldYouLikeToRestoreBackup": "Voleu restaurar la còpia de seguretat '{name}'?",
"InstallLatest": "Instal·la l'últim",
"CurrentlyInstalled": "Instal·lat actualment"
}

View File

@@ -1,6 +1,6 @@
{
"Add": "Přidat",
"CertificateValidation": "Ověření certifikátu",
"CertificateValidation": "Ověřování certifikátu",
"DeleteBackupMessageText": "Opravdu chcete odstranit zálohu '{name}'?",
"YesCancel": "Ano, zrušit",
"About": "O aplikaci",
@@ -18,7 +18,7 @@
"Usenet": "Usenet",
"AddDownloadClient": "Přidat klienta pro stahování",
"Backups": "Zálohy",
"CancelPendingTask": "Opravdu chcete zrušit tento nevyřízený úkol?",
"CancelPendingTask": "Opravdu chcete zrušit tento úkol čekající na vyřízení?",
"MovieIndexScrollBottom": "Rejstřík filmů: Posun dolů",
"ProxyType": "Typ serveru proxy",
"Reddit": "Reddit",
@@ -69,23 +69,23 @@
"UnselectAll": "Odznačit vše",
"UpdateStartupNotWritableHealthCheckMessage": "Aktualizaci nelze nainstalovat, protože spouštěcí složku „{startupFolder}“ nelze zapisovat uživatelem „{userName}“.",
"Version": "Verze",
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery {appName}u. To zahrnuje informace o vašem prohlížeči, které stránky {appName} WebUI používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k upřednostnění funkcí a oprav chyb.",
"AnalyticsEnabledHelpText": "Odesílejte anonymní informace o použití a chybách na servery {appName}u. To zahrnuje informace o vašem prohlížeči, které stránky webového rozhraní {appName}u používáte, hlášení chyb a také verzi operačního systému a běhového prostředí. Tyto informace použijeme k určení priorit funkcí a oprav chyb.",
"ApiKey": "Klíč API",
"AppDataDirectory": "Adresář AppData",
"AppDataLocationHealthCheckMessage": "Aktualizace nebude možná, aby se zabránilo odstranění AppData při aktualizaci",
"ApplicationStatusCheckAllClientMessage": "Všechny seznamy nejsou k dispozici z důvodu selhání",
"ApplicationStatusCheckSingleClientMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}",
"ApplicationStatusCheckAllClientMessage": "Všechny aplikace jsou nedostupné z důvodu poruch",
"ApplicationStatusCheckSingleClientMessage": "Aplikace nedostupné z důvodu poruch: {0}",
"Apply": "Použít",
"Branch": "Větev",
"BranchUpdate": "Pobočka, která se má použít k aktualizaci {appName}",
"BranchUpdate": "Větev použitá k aktualizaci {appName}u",
"EditIndexer": "Upravit indexátor",
"ForMoreInformationOnTheIndividualDownloadClients": "Další informace o jednotlivých klientech pro stahování získáte kliknutím na informační tlačítka.",
"General": "Všeobecné",
"CloseCurrentModal": "Zavřít aktuální modální",
"CloseCurrentModal": "Zavřít aktuální modální okno",
"Columns": "Sloupce",
"ConnectionLost": "Spojení ztraceno",
"ConnectionLost": "Ztráta spojení",
"ConnectSettings": "Nastavení připojení",
"Custom": "Zvyk",
"Custom": "Vlastní",
"Error": "Chyba",
"Failed": "Selhalo",
"FeatureRequests": "Žádosti o funkce",
@@ -106,7 +106,7 @@
"Test": "Test",
"UnableToLoadTags": "Značky nelze načíst",
"IndexerProxyStatusAllUnavailableHealthCheckMessage": "Všechny indexery nejsou k dispozici z důvodu selhání",
"ApplyTags": "Použít značky",
"ApplyTags": "Použít štítky",
"MoreInfo": "Více informací",
"System": "Systém",
"Enabled": "Povoleno",
@@ -171,15 +171,15 @@
"UseProxy": "Použij proxy",
"Username": "Uživatelské jméno",
"Yesterday": "Včera",
"AutomaticSearch": "Vyhledat automaticky",
"BackupFolderHelpText": "Relativní cesty budou v adresáři AppData společnosti {appName}",
"AutomaticSearch": "Automatické vyhledávání",
"BackupFolderHelpText": "Relativní cesty budou v adresáři AppData {appName}u",
"BackupIntervalHelpText": "Interval mezi automatickými zálohami",
"BackupNow": "Ihned zálohovat",
"BackupNow": "Zálohovat nyní",
"BackupRetentionHelpText": "Automatické zálohy starší než doba uchovávání budou automaticky vyčištěny",
"BeforeUpdate": "Před zálohováním",
"BeforeUpdate": "Před aktualizací",
"BindAddress": "Vázat adresu",
"BindAddressHelpText": "Platná IP adresa, localhost nebo '*' pro všechna rozhraní",
"BranchUpdateMechanism": "Větev používaná externím aktualizačním mechanismem",
"BindAddressHelpText": "Platná IP adresa, localhost nebo * pro všechna rozhraní",
"BranchUpdateMechanism": "Větev použitá externím aktualizačním mechanismem",
"BypassProxyForLocalAddresses": "Obcházení proxy serveru pro místní adresy",
"DeleteIndexerProxyMessageText": "Opravdu chcete smazat značku „{0}“?",
"DeleteTag": "Smazat značku",
@@ -198,7 +198,7 @@
"SSLCertPasswordHelpText": "Heslo pro soubor pfx",
"SSLCertPath": "Cesta certifikátu SSL",
"SSLCertPathHelpText": "Cesta k souboru pfx",
"UnableToLoadBackups": "Nelze načíst zálohy",
"BackupsLoadError": "Nelze načíst zálohy",
"DownloadClientsLoadError": "Nelze načíst klienty pro stahování",
"UnableToLoadGeneralSettings": "Nelze načíst obecná nastavení",
"DeleteNotification": "Smazat oznámení",
@@ -221,29 +221,29 @@
"Restore": "Obnovit",
"SettingsShowRelativeDates": "Zobrazit relativní data",
"SettingsShowRelativeDatesHelpText": "Zobrazit relativní (dnes / včera / atd.) Nebo absolutní data",
"SystemTimeCheckMessage": "Systémový čas je vypnutý o více než 1 den. Naplánované úlohy nemusí fungovat správně, dokud nebude čas opraven",
"AddingTag": "Přidání značky",
"SystemTimeHealthCheckMessage": "Systémový čas je vypnutý o více než 1 den. Naplánované úlohy nemusí fungovat správně, dokud nebude čas opraven",
"AddingTag": "Přidáštítku",
"Age": "Stáří",
"All": "Vše",
"AllIndexersHiddenDueToFilter": "Všechny filmy jsou skryty kvůli použitému filtru.",
"AllIndexersHiddenDueToFilter": "Všechny indexery jsou skryty kvůli použitému filtru.",
"Analytics": "Analýzy",
"EnableRss": "Povolit RSS",
"NoChange": "Žádná změna",
"Authentication": "Ověřování",
"AuthenticationMethodHelpText": "Vyžadovat uživatelské jméno a heslo pro přístup k {appName}",
"AuthenticationMethodHelpText": "Vyžadovat uživatelské jméno a heslo pro přístup k {appName}u",
"Automatic": "Automatický",
"Backup": "Záloha",
"Cancel": "Zrušit",
"CertificateValidationHelpText": "Změňte, jak přísné je ověření certifikace HTTPS",
"CertificateValidationHelpText": "Změňte přísnost ověřování certifikace HTTPS",
"ChangeHasNotBeenSavedYet": "Změna ještě nebyla uložena",
"Clear": "Vyčistit",
"Clear": "Vymazat",
"ClientPriority": "Priorita klienta",
"CloneProfile": "Klonovat profil",
"Close": "Zavřít",
"CouldNotConnectSignalR": "Nelze se připojit k SignalR, uživatelské rozhraní se neaktualizuje",
"CustomFilters": "Vlastní filtry",
"Date": "datum",
"Dates": "Termíny",
"Date": "Datum",
"Dates": "Data",
"DatabaseMigration": "Migrace databáze",
"Delete": "Vymazat",
"DeleteApplicationMessageText": "Opravdu chcete smazat oznámení „{0}“?",
@@ -320,8 +320,8 @@
"UnableToLoadIndexers": "Nelze načíst indexery",
"Yes": "Ano",
"GrabReleases": "Uchopte uvolnění",
"ApplicationLongTermStatusCheckSingleClientMessage": "Indexery nedostupné z důvodu selhání po dobu delší než 6 hodin: {0}",
"ApplicationLongTermStatusCheckAllClientMessage": "Všechny indexery nejsou k dispozici z důvodu selhání po dobu delší než 6 hodin",
"ApplicationLongTermStatusCheckSingleClientMessage": "Aplikace nedostupné z důvodu poruchy po dobu delší než 6 hodin: {0}",
"ApplicationLongTermStatusCheckAllClientMessage": "Všechny aplikace jsou z důvodu poruchy nedostupné déle než 6 hodin",
"Ended": "Skončil",
"LastDuration": "lastDuration",
"LastExecution": "Poslední poprava",
@@ -329,44 +329,44 @@
"Queued": "Ve frontě",
"Remove": "Odstranit",
"Replace": "Nahradit",
"TheLatestVersionIsAlreadyInstalled": "Nejnovější verze aplikace {appName} je již nainstalována",
"OnLatestVersion": "Nejnovější verze aplikace {appName} je již nainstalována",
"More": "Více",
"ApplyTagsHelpTextAdd": "Přidat: Přidá značky k již existujícímu seznamu",
"ApplyTagsHelpTextHowToApplyApplications": "Jak použít značky na vybrané filmy",
"ApplyTagsHelpTextAdd": "Přidat: Přidat štítky do existujícího seznamu štítků",
"ApplyTagsHelpTextHowToApplyApplications": "Jak použít štítky na vybrané aplikace",
"DeleteSelectedDownloadClients": "Odstranit klienta pro stahování",
"DeleteSelectedIndexersMessageText": "Opravdu chcete smazat {count} vybraný(ch) indexer(ů)?",
"DeleteSelectedApplicationsMessageText": "Opravdu chcete odstranit indexer „{0}“?",
"DeleteSelectedDownloadClientsMessageText": "Opravdu chcete smazat {count} vybraných klientů pro stahování?",
"Year": "Rok",
"ApplyTagsHelpTextRemove": "Odebrat: Odebrat zadané značky",
"ApplyTagsHelpTextRemove": "Odebrat: Odebrat zadané štítky",
"DownloadClientPriorityHelpText": "Upřednostněte více klientů pro stahování. Round-Robin se používá pro klienty se stejnou prioritou.",
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít značky na vybrané indexery",
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit značky zadanými značkami (prázdné pole vymaže všechny značky)",
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít štítky na vybrané indexery",
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit štítky zadanými štítky (prázdné pole vymaže všechny štítky)",
"Track": "Stopa",
"Genre": "Žánry",
"ConnectionLostReconnect": "{appName} se pokusí připojit automaticky, nebo můžete kliknout na tlačítko znovunačtení níže.",
"RecentChanges": "Nedávné změny",
"WhatsNew": "Co je nového?",
"DeleteAppProfileMessageText": "Opravdu chcete smazat kvalitní profil {0}",
"ConnectionLostToBackend": "{appName} ztratil spojení s backendem a pro obnovení funkčnosti bude třebaho znovu načíst.",
"ConnectionLostToBackend": "{appName} ztratil spojení s backendem a pro obnovení funkčnosti bude potřeba ho znovu načíst.",
"minutes": "Minut",
"ApplicationURL": "URL aplikace",
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základní adresy URL",
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základu URL",
"ApplyChanges": "Použít změny",
"ApiKeyValidationHealthCheckMessage": "Aktualizujte svůj klíč API tak, aby měl alespoň {length} znaků. Můžete to provést prostřednictvím nastavení nebo konfiguračního souboru",
"AppUpdated": "{appName} aktualizován",
"AddDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}",
"AuthenticationRequired": "Vyžadované ověření",
"AuthenticationRequiredHelpText": "Změnit, pro které požadavky je vyžadováno ověření. Pokud nerozumíte rizikům, neměňte je.",
"AddDownloadClientImplementation": "Přidat klienta pro stahování {implementationName}",
"AuthenticationRequired": "Vyžadováno ověření",
"AuthenticationRequiredHelpText": "Změnit, pro které požadavky je vyžadováno ověření. Neměňte, pokud nerozumíte rizikům.",
"AddCustomFilter": "Přidat vlastní filtr",
"AddConnection": "Přidat spojení",
"AddConnectionImplementation": "Přidat spojení - {implementationName}",
"AddIndexerImplementation": "Přidat indexer - {implementationName}",
"AddConnectionImplementation": "Přidat spojení {implementationName}",
"AddIndexerImplementation": "Přidat indexer {implementationName}",
"Publisher": "Vydavatel",
"Categories": "Kategorie",
"Notification": "Oznámení",
"AddApplicationImplementation": "Přidat spojení - {implementationName}",
"AddIndexerProxyImplementation": "Přidat indexátor - {implementationName}",
"AddApplicationImplementation": "Přidat aplikaci {implementationName}",
"AddIndexerProxyImplementation": "Přidat proxy server indexeru {implementationName}",
"Artist": "Umělec",
"EditIndexerImplementation": "Upravit indexer - {implementationName}",
"Episode": "epizoda",
@@ -392,36 +392,91 @@
"None": "Žádný",
"ResetAPIKeyMessageText": "Opravdu chcete resetovat klíč API?",
"Database": "Databáze",
"CountDownloadClientsSelected": "{count} vybraných klientů ke stahování",
"CountDownloadClientsSelected": "{count} vybraných klientů pro stahování",
"CountIndexersSelected": "{count} vybraných indexerů",
"EditIndexerProxyImplementation": "Přidat indexátor - {implementationName}",
"AuthBasic": "Základní (vyskakovací okno prohlížeče)",
"AuthenticationRequiredWarning": "Aby se zabránilo vzdálenému přístupu bez ověření, vyžaduje nyní {appName} povolení ověření. Ověřování z místních adres můžete volitelně zakázat.",
"AuthenticationRequiredWarning": "Aby se zabránilo vzdálenému přístupu bez ověření, vyžaduje nyní {appName}, aby bylo povoleno ověřování. Volitelně můžete zakázat ověřování z místních adres.",
"RestartProwlarr": "Restartujte {appName}",
"Duration": "Trvání",
"EditSelectedDownloadClients": "Upravit vybrané klienty pro stahování",
"EditSelectedIndexers": "Upravit vybrané indexery",
"AuthenticationMethod": "Metoda ověřování",
"AuthenticationRequiredPasswordHelpTextWarning": "Vložte nové heslo",
"AuthenticationRequiredUsernameHelpTextWarning": "Vložte nové uživatelské jméno",
"AuthenticationMethodHelpTextWarning": "Prosím vyberte platnou metodu ověřování",
"AuthenticationRequiredPasswordHelpTextWarning": "Zadejte nové heslo",
"AuthenticationRequiredUsernameHelpTextWarning": "Zadejte nové uživatelské jméno",
"AuthenticationMethodHelpTextWarning": "Vyberte platnou metodu ověřování",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Potvrďte nové heslo",
"days": "dnů",
"Id": "ID",
"CountApplicationsSelected": "Vybráno {0} kolekcí",
"CountApplicationsSelected": "{count} vybraných aplikací",
"IndexerHDBitsSettingsCodecs": "Kodek",
"IndexerHDBitsSettingsMediums": "Střední",
"Directory": "Adresář",
"CustomFilter": "Vlastní filtry",
"CustomFilter": "Vlastní filtr",
"ProxyValidationBadRequest": "Nepodařilo se otestovat proxy. StatusCode: {statusCode}",
"Default": "Výchozí",
"GrabRelease": "Uchopte uvolnění",
"Category": "Kategorie",
"BlackholeFolderHelpText": "Složka do které {appName} uloží {extension} soubor",
"BlackholeFolderHelpText": "Složka, do které {appName} uloží soubor {extension}",
"DownloadClientSettingsUrlBaseHelpText": "Přidá předponu do {connectionName} url, jako např. {url}",
"Any": "Jakákoliv",
"BuiltIn": "Vestavěný",
"Script": "Skript",
"PublishedDate": "Datum zveřejnění",
"AllSearchResultsHiddenByFilter": "Všechny výsledky jsou schovány použitým filtrem"
"AllSearchResultsHiddenByFilter": "Všechny výsledky vyhledávání jsou skryty použitým filtrem.",
"DockerUpdater": "aktualizujte kontejner dockeru, abyste aktualizaci obdrželi",
"Download": "Stažení",
"ErrorRestoringBackup": "Chyba při obnovování zálohy",
"ExternalUpdater": "{appName} je nakonfigurován pro použití externího aktualizačního mechanismu",
"FailedToFetchUpdates": "Nepodařilo se načíst aktualizace",
"NoEventsFound": "Nebyly nalezeny žádné události",
"RestartReloadNote": "Poznámka: {appName} se během procesu obnovy automaticky restartuje a znovu načte uživatelské rozhraní.",
"UpdateAppDirectlyLoadError": "{appName} nelze aktualizovat přímo,",
"AptUpdater": "K instalaci aktualizace používat apt",
"InstallLatest": "Nainstalujte nejnovější",
"Stats": "Postavení",
"CurrentlyInstalled": "Aktuálně nainstalováno",
"Mixed": "Pevný",
"ActiveIndexers": "Aktivní indexery",
"ActiveApps": "Aktivní aplikace",
"AppSettingsSummary": "Aplikace a nastavení pro konfiguraci interakce {appName}u s vašimi programy PVR",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "Pokud je torrent blokován pomocí hash, nemusí být u některých indexerů správně odmítnut během RSS/vyhledávání. Povolení této funkce umožní jeho odmítnutí po zachycení torrentu, ale před jeho odesláním klientovi.",
"ApplicationsLoadError": "Nelze načíst seznam aplikací",
"AppProfileInUse": "Používaný profil aplikace",
"AppsMinimumSeedersHelpText": "Minimální počet seederů požadovaných aplikacemi pro indexer, výchozí hodnota synchronizačního profilu je prázdná",
"AverageGrabs": "Průměrné získání",
"AverageQueries": "Průměrné dotazy",
"AdvancedSettingsShownClickToHide": "Rozšířená nastavení jsou zobrazená, klikněte pro skrytí",
"AdvancedSettingsHiddenClickToShow": "Rozšířená nastavení jsou skrytá, klikněte pro zobrazení",
"AppsMinimumSeeders": "Minimální počet seederů aplikací",
"AddNewIndexer": "Přidat nový indexer",
"AddToDownloadClient": "Přidat vydání do klienta pro stahování",
"AddIndexerProxy": "Přidat proxy server indexeru",
"AppProfileSelectHelpText": "Profily aplikace slouží k ovládání nastavení RSS, automatického vyhledávání a interaktivního vyhledávání při synchronizaci aplikace",
"BookSearch": "Vyhledávání knihy",
"ClearHistory": "Vymazat historii",
"Auth": "Ověřování",
"ConnectSettingsSummary": "Oznámení a vlastní skripty",
"AreYouSureYouWantToDeleteIndexer": "Opravdu chcete odstranit {name} z {appName}u?",
"AuthQueries": "Ověřovací dotazy",
"CountIndexersAvailable": "{count} dostupných indexerů",
"ApplicationTagsHelpText": "Synchronizovat s touto aplikací indexery, které mají jeden nebo více shodných štítků. Pokud zde nejsou uvedeny žádné štítky, nebude synchronizace žádných indexerů znemožněna kvůli jejich štítkům.",
"ApplicationTagsHelpTextWarning": "Štítky je potřeba používat opatrně, mohou mít nechtěné účinky. Aplikace se štítkem se bude synchronizovat pouze s indexery se stejným štítkem.",
"BasicSearch": "Základní vyhledávání",
"ClearHistoryMessageText": "Opravdu chcete vymazat celou historii {appName}u?",
"AddDownloadClientToProwlarr": "Přidání klienta pro stahování umožňuje {appName} odesílat vydání přímo z uživatelského rozhraní při ručním vyhledávání.",
"AddRemoveOnly": "Pouze přidat a odebrat",
"AudioSearch": "Vyhledávání audia",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashes": "Synchronizovat odmítnuté blokované hashe torrentů při získávání",
"Apps": "Aplikace",
"ClickToChangeQueryOptions": "Kliknutím změníte možnosti dotazu",
"Author": "Autor",
"AverageResponseTimesMs": "Průměrné doby odezvy indexerů (ms)",
"Book": "Kniha",
"BookSearchTypes": "Typy vyhledávání knihy",
"AddApplication": "Přidat aplikaci",
"AddSyncProfile": "Přidat synchronizační profil",
"AddedToDownloadClient": "Vydání přidáno do klienta",
"AddCategory": "Přidat kategorii",
"AreYouSureYouWantToDeleteCategory": "Opravdu chcete odstranit namapovanou kategorii?"
}

View File

@@ -33,7 +33,7 @@
"CustomFilters": "Bruger Tilpassede Filtere",
"ConnectSettingsSummary": "Notifikationer, forbindelser til medieservere/-afspillere og brugerdefinerede scripts",
"Connections": "Forbindelser",
"ConnectionLost": "Forbindelse Mistet",
"ConnectionLost": "Forbindelse mistet",
"Connect": "Notifikationer",
"Component": "Komponent",
"Columns": "Kolonner",
@@ -57,7 +57,7 @@
"MIA": "MIA",
"ResetAPIKey": "Nulstil API-nøgle",
"SettingsTimeFormat": "Tidsformat",
"SystemTimeCheckMessage": "Systemtiden er slukket mere end 1 dag. Planlagte opgaver kører muligvis ikke korrekt, før tiden er rettet",
"SystemTimeHealthCheckMessage": "Systemtiden er slukket mere end 1 dag. Planlagte opgaver kører muligvis ikke korrekt, før tiden er rettet",
"UnsavedChanges": "Ugemte ændringer",
"Updates": "Opdateringer",
"MoreInfo": "Mere info",
@@ -101,12 +101,12 @@
"CloseCurrentModal": "Luk Nuværende Modal",
"CouldNotConnectSignalR": "Kunne ikke oprette forbindelse til SignalR, UI opdateres ikke",
"DeleteApplicationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?",
"DeleteDownloadClientMessageText": "Er du sikker på, at du vil slette downloadklienten '{0}'?",
"DeleteDownloadClientMessageText": "Er du sikker på, at du vil fjerne downloadklienten »{name}«?",
"DeleteIndexerProxyMessageText": "Er du sikker på, at du vil slette tagget '{0}'?",
"DeleteNotification": "Slet underretning",
"DeleteNotificationMessageText": "Er du sikker på, at du vil slette underretningen '{0}'?",
"DeleteNotificationMessageText": "Er du sikker på, at du vil slette notifikationen »{name}«?",
"DeleteTag": "Slet tag",
"DeleteTagMessageText": "Er du sikker på, at du vil slette tagget '{0}'?",
"DeleteTagMessageText": "Er du sikker på, at du vil slette etiketten »{label}«?",
"Discord": "Discord",
"Docker": "Docker",
"Donations": "Donationer",
@@ -232,7 +232,7 @@
"UnableToAddANewAppProfilePleaseTryAgain": "Kan ikke tilføje en ny kvalitetsprofil, prøv igen.",
"UnableToAddANewDownloadClientPleaseTryAgain": "Kunne ikke tilføje en ny downloadklient. Prøv igen.",
"UnableToAddANewIndexerPleaseTryAgain": "Kunne ikke tilføje en ny indekser. Prøv igen.",
"UnableToLoadBackups": "Kunne ikke indlæse sikkerhedskopier",
"BackupsLoadError": "Kunne ikke indlæse sikkerhedskopier",
"UnableToLoadGeneralSettings": "Kan ikke indlæse generelle indstillinger",
"UnableToLoadNotifications": "Kunne ikke indlæse meddelelser",
"UnableToLoadTags": "Kan ikke indlæse tags",
@@ -266,7 +266,7 @@
"Status": "Status",
"DownloadClientsLoadError": "Kunne ikke indlæse downloadklienter",
"UpdateStartupTranslocationHealthCheckMessage": "Kan ikke installere opdatering, fordi startmappen '{startupFolder}' er i en App Translocation-mappe.",
"UpdateMechanismHelpText": "Brug den indbyggede opdateringsfunktion eller et script",
"UpdateMechanismHelpText": "Brug {appName}s indbyggede opdateringsfunktion eller et script",
"View": "Udsigt",
"Warn": "Advare",
"AddingTag": "Tilføjer tag",
@@ -302,12 +302,12 @@
"InteractiveSearch": "Interaktiv søgning",
"LogFiles": "Logfiler",
"ApiKey": "API-nøgle",
"AppDataDirectory": "AppData-bibliotek",
"AppDataDirectory": "AppData-mappe",
"CertificateValidationHelpText": "Skift, hvor streng HTTPS-certificering er",
"ChangeHasNotBeenSavedYet": "Ændring er endnu ikke gemt",
"ConnectSettings": "Forbind indstillinger",
"DeleteBackup": "Slet sikkerhedskopi",
"DeleteBackupMessageText": "Er du sikker på, at du vil slette sikkerhedskopien '{0}'?",
"DeleteBackupMessageText": "Er du sikker på, at du vil slette sikkerhedskopien »{name}«?",
"DeleteDownloadClient": "Slet Download Client",
"MaintenanceRelease": "Vedligeholdelsesfrigivelse: fejlrettelser og andre forbedringer. Se Github Commit History for flere detaljer",
"Filters": "Filter",
@@ -340,7 +340,7 @@
"Notification": "Notifikationer",
"Remove": "Fjerne",
"Replace": "erstat",
"TheLatestVersionIsAlreadyInstalled": "Den seneste version af {appName} er allerede installeret",
"OnLatestVersion": "Den seneste version af {appName} er allerede installeret",
"Year": "År",
"ApplyTagsHelpTextAdd": "Tilføj: Føj tags til den eksisterende liste over tags",
"ApplyTagsHelpTextHowToApplyApplications": "Sådan anvendes tags på de valgte film",
@@ -360,7 +360,7 @@
"DeleteAppProfileMessageText": "Er du sikker på, at du vil slette kvalitetsprofilen {0}",
"RecentChanges": "Seneste ændringer",
"WhatsNew": "Hvad er nyt?",
"ConnectionLostReconnect": "Radarr vil prøve at tilslutte automatisk, eller du kan klikke genindlæs forneden.",
"ConnectionLostReconnect": "{appName} vil prøve at tilslutte automatisk. Ellers du kan klikke genindlæs forneden.",
"minutes": "Protokoller",
"NotificationStatusAllClientHealthCheckMessage": "Alle lister er utilgængelige på grund af fejl",
"NotificationStatusSingleClientHealthCheckMessage": "Lister utilgængelige på grund af fejl: {notificationNames}",
@@ -375,7 +375,7 @@
"AddConnection": "Tilføj forbindelse",
"EditConnectionImplementation": "Tilføj forbindelse - {implementationName}",
"AddApplicationImplementation": "Tilføj forbindelse - {implementationName}",
"AddIndexerImplementation": "Tilføj betingelse - {implementationName}",
"AddIndexerImplementation": "Tilføj indeksør - {implementationName}",
"ApplyChanges": "Anvend ændringer",
"AddDownloadClientImplementation": "Tilføj downloadklient - {implementationName}",
"Album": "album",
@@ -394,12 +394,35 @@
"IndexerHDBitsSettingsMediums": "Medium",
"CustomFilter": "Bruger Tilpassede Filtere",
"ProxyValidationBadRequest": "Kunne ikke teste proxy. Statuskode: {statusCode}",
"GrabRelease": "Grab Release",
"GrabRelease": "Hent udgivelse",
"Script": "Manuskript",
"BuiltIn": "Indbygget",
"PublishedDate": "Udgivelsesdato",
"AllSearchResultsHiddenByFilter": "Alle resultater skjules af det anvendte filter",
"AddApplication": "Tilføj Applikation",
"AddCategory": "Tilføj Kategori",
"ActiveApps": "Aktive Apps"
"ActiveApps": "Aktive Apps",
"NoEventsFound": "Ingen begivenheder fundet",
"AptUpdater": "Brug apt til at installere opdateringen",
"DockerUpdater": "opdater docker-containeren for at modtage opdateringen",
"Download": "Hent",
"ErrorRestoringBackup": "Fejl ved gendannelse af sikkerhedskopi",
"ExternalUpdater": "{appName} er konfigureret til at bruge en ekstern opdateringsmekanisme",
"RestartReloadNote": "Bemærk: {appName} genstarter automatisk og genindlæser brugergrænsefladen under gendannelsesprocessen.",
"UpdateAppDirectlyLoadError": "Kan ikke opdatere {appName} direkte,",
"InstallLatest": "Installer senest",
"Clone": "Luk",
"CurrentlyInstalled": "Aktuelt installeret",
"Stats": "Status",
"Mixed": "Fast",
"PrioritySettings": "Prioritet: {priority}",
"WouldYouLikeToRestoreBackup": "Vil du gendanne sikkerhedskopien »{name}«?",
"AppProfileSelectHelpText": "App-profiler bruges til at styre indstillinger for RSS, automatisk søgning og interaktiv søgning ved synkronisering med applikationer",
"ActiveIndexers": "Aktive indeksører",
"TheLogLevelDefault": "Logniveauet er som standard 'Info' og kan ændres under [Generelle indstillinger](/settings/general)",
"AddedToDownloadClient": "Udgivelse føjet til klient",
"AdvancedSettingsHiddenClickToShow": "Avancerede indstillinger er skjult. Klik for at vise",
"AdvancedSettingsShownClickToHide": "Avancerede indstillinger vises. Klik for at skjule",
"ApiKeyValidationHealthCheckMessage": "Opdater din API-nøgle til at være på mindste {length} karakterer. Dette kan gøres i indstillingerne eller i konfigurationsfilen",
"AppProfileInUse": "App-profil i brug"
}

View File

@@ -109,7 +109,7 @@
"DownloadClientSettings": "Downloader Einstellungen",
"DownloadClientStatusAllClientHealthCheckMessage": "Alle Download Clients sind aufgrund von Fehlern nicht verfügbar",
"DownloadClientStatusSingleClientHealthCheckMessage": "Download Clients aufgrund von Fehlern nicht verfügbar: {downloadClientNames}",
"DownloadClients": "Downloader",
"DownloadClients": "Download Clients",
"DownloadClientsSettingsSummary": "Download der Client-Konfigurationen für die Integration in die {appName} UI-Suche",
"Duration": "Dauer",
"Edit": "Bearbeiten",
@@ -118,10 +118,10 @@
"ElapsedTime": "Vergangene Zeit",
"Enable": "Aktivieren",
"EnableAutomaticSearch": "Automatische Suche einschalten",
"EnableAutomaticSearchHelpText": "Wird für automatische Suchen genutzt die vom Benutzer oder von {appName} gestartet werden",
"EnableAutomaticSearchHelpText": "Wird verwendet, wenn die automatische Suche über die Benutzeroberfläche oder durch {appName} durchgeführt wird.",
"EnableIndexer": "Indexer aktivieren",
"EnableInteractiveSearch": "Interaktive Suche einschalten",
"EnableInteractiveSearchHelpText": "Wird bei der manuellen Suche benutzt",
"EnableInteractiveSearchHelpText": "Wird verwendet, wenn die interaktive Suche verwendet wird",
"EnableRss": "RSS aktivieren",
"EnableRssHelpText": "RSS-Feed für Indexer aktivieren",
"EnableSSL": "SSL",
@@ -131,13 +131,13 @@
"Encoding": "Codierung",
"Ended": "Beendet",
"Error": "Fehler",
"ErrorLoadingContents": "Fehler beim laden der Inhalte",
"EventType": "Event Typ",
"Events": "Events",
"ErrorLoadingContents": "Fehler beim Laden von Inhalten",
"EventType": "Ereignistyp",
"Events": "Ereignisse",
"Exception": "Ausnahme",
"ExistingTag": "Vorhandener Tag",
"Failed": "Fehlgeschlagen",
"FeatureRequests": "Funktionsanfragen",
"FeatureRequests": "Feature Anfragen",
"Filename": "Dateiname",
"Files": "Dateien",
"Filter": "Filter",
@@ -153,16 +153,16 @@
"GeneralSettingsSummary": "Port, SSL, Benutzername/Passwort, Proxy, Analytik und Updates",
"GrabReleases": "Release erfassen",
"GrabTitle": "Titel holen",
"Grabbed": "Erfasste",
"Grabbed": "Geholt",
"Grabs": "Erfasse",
"Health": "Zustandsüberwachung",
"Health": "Gesundheit",
"NoIssuesWithYourConfiguration": "Keine Probleme mit deiner Konfiguration",
"HideAdvanced": "Erweiterte Ansicht",
"HideAdvanced": "Erweiterte Einstellungen ausblenden",
"History": "Verlauf",
"HistoryCleanup": "Verlaufsbereinigung",
"HistoryCleanupDaysHelpText": "Auf 0 setzen um das automatische leeren des Papierkorbs zu deaktivieren",
"HistoryCleanupDaysHelpTextWarning": "Datien im Papierkorb die älter sind als der gewählte Wert, werden endgültig gelöscht",
"HomePage": "Startseite",
"HomePage": "Hauptseite",
"Host": "Host",
"Hostname": "Hostname",
"Id": "Id",
@@ -176,12 +176,12 @@
"IndexerFlags": "Indexer-Flags",
"IndexerHealthCheckNoIndexers": "Keine Indexer aktiviert, {appName} wird keine Suchergebnisse zurückgeben",
"IndexerInfo": "Indexer-Info",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind wegen über 6 Stunden langen bestehender Fehler nicht verfügbar",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexer wegen über 6 Stunden langen bestehenden Fehlern nicht verfügbar: {indexerNames}",
"IndexerLongTermStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind aufgrund von Fehlern länger als 6 Stunden nicht verfügbar",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexer sind aufgrund von Fehlern länger als 6 Stunden nicht verfügbar: {indexerNames}",
"IndexerName": "Indexer-Name",
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {0}. Bitte entferne und (oder) füge diese neu zu {appName} hinzu",
"IndexerNoDefinitionCheckHealthCheckMessage": "Indexer haben keine Definition und werden nicht funktionieren: {indexerNames}. Bitte entferne und (oder) füge diese neu zu {appName} hinzu",
"IndexerObsoleteCheckMessage": "Indexer sind nicht mehr verfügbar oder wurden aktualiiert: {0}. Bitte enfernen und (oder) neu zu {appName} hinzufügen",
"IndexerPriority": "Priorität",
"IndexerPriority": "Indexer-Priorität",
"IndexerPriorityHelpText": "Indexer Priorität von 1 (höchste) bis 50 (niedrigste). Standard: 25.",
"IndexerProxies": "Indexer-Proxies",
"IndexerProxy": "Indexer-Proxy",
@@ -192,27 +192,27 @@
"IndexerSettingsSummary": "Konfiguration verschiedener globaler Indexer Einstellungen, einschließlich Proxies.",
"IndexerSite": "Indexer-Seite",
"IndexerStatusAllUnavailableHealthCheckMessage": "Alle Indexer sind aufgrund von Fehlern nicht verfügbar",
"IndexerStatusUnavailableHealthCheckMessage": "Indexer aufgrund von Fehlern nicht verfügbar: {indexerNames}",
"IndexerStatusUnavailableHealthCheckMessage": "Indexer nicht verfügbar aufgrund von Fehlern: {indexerNames}",
"IndexerTagsHelpText": "Benutze Tags, um Indexer-Proxies zu spezifizieren, mit welchen Apps der Indexer synchronisiert oder um Indexer zu organisieren.",
"IndexerVipExpiredHealthCheckMessage": "Die VIP Indexer Vorteile sind abgelaufen: {indexerNames}",
"IndexerVipExpiringHealthCheckMessage": "Die Indexer VIP Vorteile verfallen bald: {indexerNames}",
"Indexers": "Indexer",
"Info": "Info",
"InstanceName": "Instanzname",
"InstanceNameHelpText": "Instanzname im Browser-Tab und für Syslog-Anwendungsname",
"InstanceNameHelpText": "Instanzname im Tab und für den Syslog-App-Namen",
"InteractiveSearch": "Interaktive Suche",
"Interval": "Intervall",
"KeyboardShortcuts": "Tastenkürzel",
"Language": "Sprache",
"LastDuration": "Letzte Dauer",
"LastExecution": "Letzte Ausführung",
"LastWriteTime": "Zuletzt beschrieben",
"LastWriteTime": "Letzte Schreibzeit",
"LaunchBrowserHelpText": " Öffne die Startseite von {appName} im Webbrowser nach dem Start.",
"Level": "Stufe",
"Level": "Level",
"Link": "Links",
"LogFiles": "Protokolle",
"LogLevel": "Log Level",
"LogLevelTraceHelpTextWarning": "Trace logging sollte nur kurzzeitig aktiviert werden",
"LogFiles": "Protokolldateien",
"LogLevel": "Protokollstufe",
"LogLevelTraceHelpTextWarning": "Die Trace-Protokollierung sollte nur vorübergehend aktiviert werden",
"Logging": "Protokollierung",
"Logs": "Protokolle",
"MIA": "MIA",
@@ -220,7 +220,7 @@
"Manual": "Manuell",
"MappedDrivesRunningAsService": "Zugeordnete Netzlaufwerke sind nicht verfügbar, wenn {appName} als Windows-Dienst ausgeführt wird. Bitte lesen Sie die FAQ für weitere Informationen",
"MassEditor": "Masseneditor",
"Mechanism": "Verfahren",
"Mechanism": "Mechanismus",
"Message": "Nachricht",
"MinimumSeeders": "Mindest-Seeder",
"MinimumSeedersHelpText": "Minimale Anzahl an Seedern die von der Anwendung benötigt werden um den Indexer zu holen",
@@ -236,41 +236,41 @@
"New": "Neu",
"NextExecution": "Nächste Ausführung",
"No": "Nein",
"NoBackupsAreAvailable": "Es sind keine Backups vorhanden",
"NoBackupsAreAvailable": "Keine Sicherungen verfügbar",
"NoChange": "Keine Änderung",
"NoChanges": "Keine Änderungen",
"NoLeaveIt": "Nein, nicht ändern",
"NoLeaveIt": "Nein, lass es",
"NoLinks": "Keine Links",
"NoLogFiles": "Keine Log-Dateien",
"NoLogFiles": "Keine Logdateien",
"NoSearchResultsFound": "Keine Suchergebnisse gefunden. Versuchen Sie unten eine erneute Suche durchzuführen.",
"NoTagsHaveBeenAddedYet": "Es wurden noch keine Tags erstellt",
"NoTagsHaveBeenAddedYet": "Es wurden noch keine Tags hinzugefügt",
"NoUpdatesAreAvailable": "Es sind keine Updates verfügbar",
"NotSupported": "Nicht unterstützt",
"Notification": "Benachrichtigungen",
"NotificationTriggers": "Benachrichtigungs Auslöser",
"NotificationTriggersHelpText": "Auslöser für diese Benachrichtigung auswählen",
"NotificationTriggers": "Benachrichtigungs-Auslöser",
"NotificationTriggersHelpText": "Wähle aus, welche Ereignisse diese Benachrichtigung auslösen sollen",
"Notifications": "Benachrichtigungen",
"OAuthPopupMessage": "Dein Browser blockiert Pop-ups",
"Ok": "OK",
"Ok": "Ok",
"OnApplicationUpdate": "Bei Anwendungsaktualisierung",
"OnApplicationUpdateHelpText": "Bei Anwendungsaktualisierung",
"OnGrab": "Bei Erfassung",
"OnHealthIssue": "Bei Zustandsproblem",
"OnHealthIssue": "Bei Gesundheitsproblem",
"OnHealthIssueHelpText": "Zustandsproblem",
"OpenBrowserOnStart": "Browser beim Start öffnen",
"OpenThisModal": "Dieses Modal öffnen",
"Options": "Optionen",
"PackageVersion": "Paket Version",
"PackageVersion": "Paketversion",
"PageSize": "Einträge pro Seite",
"PageSizeHelpText": "Anzahl der Einträge pro Seite",
"Parameters": "Parameter",
"Password": "Passwort",
"Peers": "Peers",
"PendingChangesDiscardChanges": "Änderungen verwerfen und schließen",
"PendingChangesMessage": "Es gibt noch ungespeicherte Änderungen, bist du sicher, dass du die Seite verlassen möchtest?",
"PendingChangesStayReview": "Auf der Seite bleiben",
"PendingChangesDiscardChanges": "Änderungen verwerfen und verlassen",
"PendingChangesMessage": "Du hast ungespeicherte Änderungen, bist du sicher, dass du diese Seite verlassen möchtest?",
"PendingChangesStayReview": "Bleiben und Änderungen überprüfen",
"Port": "Port",
"PortNumber": "Port Nummer",
"PortNumber": "Portnummer",
"Presets": "Voreinstellungen",
"Priority": "Priorität",
"Privacy": "Privatsphäre",
@@ -294,7 +294,7 @@
"Queue": "Warteschlange",
"Queued": "In Warteschlange",
"Rss": "RSS",
"RssIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt",
"RssIsNotSupportedWithThisIndexer": "RSS wird mit diesem Indexer nicht unterstützt",
"RawSearchSupported": "Raw-Suche unterstützt",
"ReadTheWikiForMoreInformation": "Lesen Sie das Wiki für weitere Informationen",
"Reddit": "Reddit",
@@ -304,7 +304,7 @@
"RefreshMovie": "Film aktualisieren",
"ReleaseBranchCheckOfficialBranchMessage": "Zweig {0} ist kein gültiger {appName}-Release-Zweig. Sie erhalten keine Updates",
"ReleaseStatus": "Releasestatus",
"Reload": "Neuladen",
"Reload": "Neu laden",
"Remove": "Entfernen",
"RemoveFilter": "Filter entfernen",
"RemovedFromTaskQueue": "Aus der Aufgabenwarteschlange entfernt",
@@ -319,7 +319,7 @@
"Restore": "Wiederherstellen",
"RestoreBackup": "Sicherung wiederherstellen",
"Result": "Ergebnis",
"Retention": "Aufbewahrung ( Retention )",
"Retention": "Aufbewahrung",
"SSLCertPassword": "SSL Zertifikat Passwort",
"SSLCertPasswordHelpText": "Passwort für die PFX Datei",
"SSLCertPath": "Pfad zum SSL Zertifikat",
@@ -329,8 +329,8 @@
"SaveChanges": "Änderungen speichern",
"SaveSettings": "Einstellungen speichern",
"Scheduled": "Geplant",
"ScriptPath": "Script Pfad",
"Search": "Suche",
"ScriptPath": "Skript-Pfad",
"Search": "Suchen",
"SearchCapabilities": "Suchfähigkeiten",
"SearchIndexers": "Indexer suchen",
"SearchType": "Suchtyp",
@@ -360,7 +360,7 @@
"SettingsTimeFormat": "Zeitformat",
"ShowAdvanced": "Erweitert anzeigen",
"ShowSearch": "Suche anzeigen",
"ShowSearchHelpText": "Suchbutton anzeigen beim draufzeigen",
"ShowSearchHelpText": "Suchschaltfläche beim Überfahren anzeigen",
"Shutdown": "Herunterfahren",
"Size": "Größe",
"Sort": "Sortieren",
@@ -379,12 +379,12 @@
"SyncProfile": "Sync-Profile",
"SyncProfiles": "Sync-Profile",
"System": "System",
"SystemTimeCheckMessage": "Die Systemzeit ist um einen Tag versetzt. Bis die Zeit korrigiert wurde, könnten die geplanten Aufgaben nicht korrekt ausgeführt werden",
"SystemTimeHealthCheckMessage": "Die Systemzeit ist um einen Tag versetzt. Bis die Zeit korrigiert wurde, könnten die geplanten Aufgaben nicht korrekt ausgeführt werden",
"TVSearchTypes": "Suchtyp",
"TableOptions": "Tabellen Optionen",
"TableOptions": "Tabellenoptionen",
"TableOptionsColumnsMessage": "Wähle aus welche Spalten angezeigt werden und in welcher Reihenfolge",
"TagCannotBeDeletedWhileInUse": "Kann während der Benutzung nicht gelöscht werden",
"TagIsNotUsedAndCanBeDeleted": "Tag wird nicht benutzt und kann gelöscht werden",
"TagIsNotUsedAndCanBeDeleted": "Tag wird nicht verwendet und kann gelöscht werden",
"Tags": "Tags",
"TagsHelpText": "Wird auf Filme mit mindestens einem passenden Tag angewandt",
"TagsSettingsSummary": "Sehen Sie sich alle Tags und deren Verwendung an. Nicht verwendete Tags können entfernt werden",
@@ -394,7 +394,7 @@
"TestAllApps": "Alle Apps testen",
"TestAllClients": "Prüfe alle Clients",
"TestAllIndexers": "Prüfe alle Indexer",
"TheLatestVersionIsAlreadyInstalled": "Die aktuellste Version ist bereits installiert",
"OnLatestVersion": "Die neueste Version von {appName} ist bereits installiert",
"ThemeHelpText": "Ändere das UI-Theme der Anwendung. Das 'Auto'-Theme verwendet dein Betriebssystem-Theme, um den hellen oder dunklen Modus einzustellen. Inspiriert von {0}",
"Time": "Zeit",
"Title": "Titel",
@@ -419,9 +419,9 @@
"UnableToAddANewNotificationPleaseTryAgain": "Die neue Benachrichtigung konnte nicht hinzugefügt werden, bitte erneut probieren.",
"UnableToLoadAppProfiles": "App-Profile können nicht geladen werden",
"ApplicationsLoadError": "Anwendungsliste kann nicht geladen werden",
"UnableToLoadBackups": "Sicherungen können nicht geladen werden",
"BackupsLoadError": "Sicherungen können nicht geladen werden",
"UnableToLoadDevelopmentSettings": "Entwicklereinstellungen konnten nicht geladen werden",
"DownloadClientsLoadError": "Downloader konnten nicht geladen werden",
"DownloadClientsLoadError": "Download Clients können nicht geladen werden",
"UnableToLoadGeneralSettings": "Allgemeine Einstellungen konnten nicht geladen werden",
"UnableToLoadHistory": "Verlauf konnte nicht geladen werden",
"UnableToLoadIndexerProxies": "Indexer-Proxies können nicht geladen werden",
@@ -454,7 +454,7 @@
"YesCancel": "Ja Abbrechen",
"Yesterday": "Gestern",
"OnHealthRestoredHelpText": "Bei Wiederherstellung des Zustands",
"OnHealthRestored": "Bei Wiederherstellung des Zustands",
"OnHealthRestored": "Bei Wiederherstellung der Gesundheit",
"StopSelecting": "Auswahl stoppen",
"ApplicationURL": "Anwendungs-URL",
"ApplicationUrlHelpText": "Die externe URL dieser Anwendung, einschließlich http(s)://, Port und URL-Basis",
@@ -485,7 +485,7 @@
"More": "Mehr",
"Publisher": "Herausgeber",
"Track": "Trace",
"UpdateAvailableHealthCheckMessage": "Neue Version verfügbar",
"UpdateAvailableHealthCheckMessage": "Ein neues Update ist verfügbar: {version}",
"Year": "Jahr",
"Album": "Album",
"Artist": "Interpret",
@@ -498,8 +498,8 @@
"minutes": "Minuten",
"DeleteAppProfileMessageText": "Qualitätsprofil '{0}' wirklich löschen?",
"AddConnection": "Verbindung hinzufügen",
"NotificationStatusAllClientHealthCheckMessage": "Wegen Fehlern sind keine Applikationen verfügbar",
"NotificationStatusSingleClientHealthCheckMessage": "Applikationen wegen folgender Fehler nicht verfügbar: {notificationNames}",
"NotificationStatusAllClientHealthCheckMessage": "Alle Benachrichtigungen sind aufgrund von Fehlern nicht verfügbar",
"NotificationStatusSingleClientHealthCheckMessage": "Benachrichtigungen nicht verfügbar wegen Fehlern: {notificationNames}",
"AuthBasic": "Basis (Browser-Popup)",
"AuthForm": "Formulare (Anmeldeseite)",
"DisabledForLocalAddresses": "Für lokale Adressen deaktiviert",
@@ -529,18 +529,18 @@
"AuthenticationRequiredWarning": "Um unberechtigte Fernzugriffe zu vermeiden benötigt {appName} jetzt , dass Authentifizierung eingeschaltet ist. Du kannst Authentifizierung optional für lokale Adressen ausschalten.",
"AuthenticationRequired": "Authentifizierung benötigt",
"AuthenticationRequiredHelpText": "Ändern, welche anfragen Authentifizierung benötigen. Ändere nichts wenn du dir nicht des Risikos bewusst bist.",
"AuthenticationRequiredUsernameHelpTextWarning": "Gib einen neuen Benutzernamen ein",
"AuthenticationRequiredUsernameHelpTextWarning": "Neuen Benutzernamen eingeben",
"AuthenticationMethodHelpTextWarning": "Bitte wähle eine gültige Authentifizierungsmethode aus",
"AuthenticationRequiredPasswordHelpTextWarning": "Gib ein neues Passwort ein",
"AuthenticationRequiredPasswordHelpTextWarning": "Neues Passwort eingeben",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Neues Passwort bestätigen",
"DefaultNameCopiedProfile": "{name} Kopieren",
"AuthenticationMethod": "Authentifizierungsmethode",
"Clone": "Klonen",
"CountDownloadClientsSelected": "{count} Download-Client(s) ausgewählt",
"EditConnectionImplementation": "Verbindung hinzufügen - {implementationName}",
"EditDownloadClientImplementation": "Download-Client hinzufügen - {implementationName}",
"EditConnectionImplementation": "Verbindung bearbeiten - {implementationName}",
"EditDownloadClientImplementation": "Download Client bearbeiten - {implementationName}",
"IndexerTagsHelpTextWarning": "Tags sollten mit Vorsicht verwendet werden, da sie ungewollte Effekte haben können. Eine Anwendung mit einem Tag synchronisiert nur Indexer die den Gleichen Tag haben.",
"EditIndexerImplementation": "Indexer hinzufügen - {implementationName}",
"EditIndexerImplementation": "Indexer bearbeiten - {implementationName}",
"EditApplicationImplementation": "Anwendung hinzufügen - {implementationName}",
"EditIndexerProxyImplementation": "Indexer Proxy hinzufügen - {implementationName}",
"CountApplicationsSelected": "{count} Ausgewählte Sammlung(en)",
@@ -563,14 +563,14 @@
"IndexerBeyondHDSettingsSearchTypes": "Suchtyp",
"DownloadClientFloodSettingsUrlBaseHelpText": "Fügt der Flood-API ein Präfix hinzu, z. B. {url}",
"DownloadClientFreeboxSettingsApiUrl": "API-URL",
"DownloadClientFreeboxSettingsApiUrlHelpText": "Definieren Sie die Freebox-API-Basis-URL mit der API-Version, z. B. {url}, standardmäßig ist „{defaultApiUrl}.",
"DownloadClientFreeboxSettingsApiUrlHelpText": "Definiere die Freebox-API-Basis-URL mit der API-Version, z. B. '{url}', standardmäßig '{defaultApiUrl}'.",
"DownloadClientRTorrentSettingsUrlPathHelpText": "Pfad zum XMLRPC-Endpunkt, siehe {url}. Dies ist normalerweise RPC2 oder [Pfad zu ruTorrent]{url2}, wenn ruTorrent verwendet wird.",
"DownloadClientSettingsAddPaused": "Pausiert hinzufügen",
"SelectDownloadClientModalTitle": "{modalTitle} Wähle Download-Client",
"DownloadClientQbittorrentSettingsFirstAndLastFirst": "Erster und Letzter Erster",
"DownloadClientQbittorrentSettingsInitialStateHelpText": "Ausgangszustand für zu qBittorrent hinzugefügte Torrents. Beachten Sie, dass erzwungene Torrents nicht den Seed-Beschränkungen unterliegen",
"IndexerSettingsAppsMinimumSeeders": "Apps Mindestanzahl von Seedern",
"IndexerHDBitsSettingsMediums": "Medium",
"IndexerHDBitsSettingsMediums": "Medien",
"Destination": "Ziel",
"Directory": "Verzeichnis",
"DownloadClientDelugeSettingsUrlBaseHelpText": "Fügt der Deluge-JSON-URL ein Präfix hinzu, siehe {url}",
@@ -590,7 +590,7 @@
"DownloadClientRTorrentSettingsAddStoppedHelpText": "Durch die Aktivierung werden Torrents und Magnete im gestoppten Zustand zu rTorrent hinzugefügt. Dadurch können Magnetdateien beschädigt werden.",
"DownloadClientRTorrentSettingsDirectoryHelpText": "Optionaler Speicherort für Downloads. Lassen Sie das Feld leer, um den standardmäßigen rTorrent-Speicherort zu verwenden",
"DownloadClientRTorrentSettingsUrlPath": "URL-Pfad",
"IndexerHDBitsSettingsCodecs": "Codec",
"IndexerHDBitsSettingsCodecs": "Codecs",
"IndexerSettingsVipExpiration": "VIP Ablaufdatum",
"TorrentBlackholeSaveMagnetFilesHelpText": "Speichern Sie den Magnet-Link, wenn keine .torrent-Datei verfügbar ist (nur nützlich, wenn der Download-Client in einer Datei gespeicherte Magnete unterstützt)",
"TorrentBlackholeTorrentFolder": "Torrent-Ordner",
@@ -605,12 +605,70 @@
"TorrentBlackholeSaveMagnetFiles": "Speicher Magnetdateien",
"TorrentBlackholeSaveMagnetFilesExtension": "Speicher die Magnet-Dateienerweiterung",
"Default": "Standard",
"GrabRelease": "Release erfassen",
"GrabRelease": "Release holen",
"Script": "Skript",
"IndexerDownloadClientHealthCheckMessage": "Indexer mit ungültigen Downloader: {indexerNames}.",
"IndexerDownloadClientHealthCheckMessage": "Indexer mit ungültigen Download-Clients: {indexerNames}.",
"Any": "Beliebig",
"BuiltIn": "Eingebaut",
"PublishedDate": "Veröffentlichungsdatum",
"Redirected": "Umleiten",
"AllSearchResultsHiddenByFilter": "Alle Ergebnisse werden durch den angewendeten Filter ausgeblendet"
"AllSearchResultsHiddenByFilter": "Alle Ergebnisse werden durch den angewendeten Filter ausgeblendet",
"DockerUpdater": "Aktualisieren Sie den Docker-Container, um das Update zu erhalten",
"Download": "Herunterladen",
"ErrorRestoringBackup": "Fehler beim Wiederherstellen der Sicherung",
"ExternalUpdater": "{appName} ist so konfiguriert, dass es einen externen Aktualisierungsmechanismus verwendet",
"NoEventsFound": "Keine Ereignisse gefunden",
"RestartReloadNote": "Hinweis: {appName} startet während des Wiederherstellungsvorgangs automatisch neu und lädt die Benutzeroberfläche neu.",
"TheLogLevelDefault": "Die Protokollebene ist standardmäßig auf „Info“ eingestellt und kann unter „Allgemeine Einstellungen“ (/settings/general) geändert werden.",
"UpdateAppDirectlyLoadError": "{appName} kann nicht direkt aktualisiert werden.",
"UpdaterLogFiles": "Updater-Protokolldateien",
"WouldYouLikeToRestoreBackup": "Willst du das Backup '{name}' wiederherstellen?",
"AptUpdater": "Verwenden Sie apt, um das Update zu installieren",
"InstallLatest": "Neueste Version installieren",
"CurrentlyInstalled": "Derzeit installiert",
"Mixed": "Gemischt",
"DownloadClientQbittorrentSettingsContentLayout": "Inhaltslayout",
"FailedToFetchSettings": "Einstellungen können nicht abgerufen werden",
"External": "Extern",
"FailedToFetchUpdates": "Updates konnten nicht abgerufen werden",
"IndexerSettingsSeedRatio": "Seed-Verhältnis",
"Install": "Installieren",
"ManualGrab": "Manuelles Greifen",
"OverrideGrabModalTitle": "Überschreiben und Abrufen - {title}",
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Ob das konfigurierte Inhaltslayout von qBittorrent, das ursprüngliche Layout des Torrents oder immer ein Unterordner erstellt werden soll (qBittorrent 4.3.2+)",
"HealthMessagesInfoBox": "Weitere Informationen zur Ursache dieser Gesundheitsprüfungsnachrichten findest du, indem du auf den Wiki-Link (Buch-Symbol) am Ende der Zeile klickst oder deine [Protokolle]({link}) überprüfst. Wenn du Schwierigkeiten hast, diese Nachrichten zu interpretieren, kannst du unseren Support kontaktieren, über die Links unten.",
"IndexerHDBitsSettingsMediumsHelpText": "Wenn nicht angegeben, werden alle Optionen verwendet.",
"InvalidUILanguage": "Die UI ist auf eine ungültige Sprache eingestellt, korrigiere sie und speichere die Einstellungen",
"LogFilesLocation": "Protokolldateien befinden sich unter: {location}",
"Logout": "Abmelden",
"NoHistoryFound": "Keine Historie gefunden",
"PasswordConfirmation": "Passwortbestätigung",
"InfoUrl": "Info-URL",
"LogSizeLimit": "Protokollgrößenlimit",
"LogSizeLimitHelpText": "Maximale Protokolldateigröße in MB, bevor archiviert wird. Standard ist 1MB.",
"NotificationsEmailSettingsUseEncryption": "Verschlüsselung verwenden",
"NotificationsTelegramSettingsIncludeAppName": "{appName} im Titel einfügen",
"NotificationsTelegramSettingsIncludeAppNameHelpText": "Optional den Nachrichtentitel mit {appName} voranstellen, um Benachrichtigungen von verschiedenen Anwendungen zu unterscheiden",
"LabelIsRequired": "Label ist erforderlich",
"Menu": "Menü",
"IndexerHDBitsSettingsCodecsHelpText": "Wenn nicht angegeben, werden alle Optionen verwendet.",
"IndexerSettingsCookie": "Cookie",
"IndexerSettingsSeedTime": "Seed-Zeit",
"IndexerSettingsAdditionalParameters": "Zusätzliche Parameter",
"IndexerSettingsApiPath": "API-Pfad",
"IndexerSettingsApiPathHelpText": "Pfad zur API, normalerweise {url}",
"DownloadClientTransmissionSettingsUrlBaseHelpText": "Fügt der {clientName}-rpc-URL ein Präfix hinzu, z. B. {url}, standardmäßig '{defaultUrl}'",
"IndexerSettingsSeedRatioHelpText": "Das Verhältnis, das ein Torrent erreichen muss, bevor er gestoppt wird. Leer verwendet das Standardverhältnis des Download-Clients. Das Verhältnis sollte mindestens 1,0 betragen und den Regeln des Indexers folgen.",
"IndexerSettingsSeedTimeHelpText": "Die Zeit, die ein Torrent gesät werden sollte, bevor er gestoppt wird. Leer verwendet die Standardzeit des Download-Clients",
"InstallMajorVersionUpdate": "Update installieren",
"InstallMajorVersionUpdateMessage": "Dieses Update wird eine neue Hauptversion installieren und ist möglicherweise nicht mit deinem System kompatibel. Bist du sicher, dass du dieses Update installieren möchtest?",
"InstallMajorVersionUpdateMessageLink": "Weitere Informationen findest du unter [{domain}]({url}).",
"NotificationsEmailSettingsUseEncryptionHelpText": "Ob bevorzugt Verschlüsselung verwendet werden soll, wenn auf dem Server konfiguriert, ob immer Verschlüsselung über SSL (nur Port 465) oder StartTLS (anderer Port) verwendet wird oder keine Verschlüsselung verwendet wird",
"PackageVersionInfo": "{packageVersion} von {packageAuthor}",
"PreviouslyInstalled": "Früher installiert",
"PrioritySettings": "Priorität: {priority}",
"SeedRatio": "Seed-Verhältnis",
"SeedTime": "Seed-Zeit",
"ApplicationSettingsSyncRejectBlocklistedTorrentHashesHelpText": "Wenn ein Torrent durch einen Hash blockiert wird, wird er möglicherweise nicht korrekt abgelehnt während RSS/Recherche für einige Indexer. Diese Option aktiviert die Ablehnung des Torrents nach dem Abrufen, aber bevor er an den Client gesendet wird.",
"IndexerHDBitsSettingsOriginsHelpText": "Wenn nicht angegeben, werden alle Optionen verwendet."
}

View File

@@ -196,7 +196,7 @@
"SSLCertPath": "Διαδρομή πιστοποίησης SSL",
"StartTypingOrSelectAPathBelow": "Ξεκινήστε να πληκτρολογείτε ή επιλέξτε μια διαδρομή παρακάτω",
"Style": "Στυλ",
"SystemTimeCheckMessage": "Ο χρόνος συστήματος είναι απενεργοποιημένος για περισσότερο από 1 ημέρα. Οι προγραμματισμένες εργασίες ενδέχεται να μην εκτελούνται σωστά έως ότου διορθωθεί η ώρα",
"SystemTimeHealthCheckMessage": "Ο χρόνος συστήματος είναι απενεργοποιημένος για περισσότερο από 1 ημέρα. Οι προγραμματισμένες εργασίες ενδέχεται να μην εκτελούνται σωστά έως ότου διορθωθεί η ώρα",
"TableOptions": "Επιλογές πίνακα",
"TableOptionsColumnsMessage": "Επιλέξτε ποιες στήλες είναι ορατές και με ποια σειρά εμφανίζονται",
"TagIsNotUsedAndCanBeDeleted": "Η ετικέτα δεν χρησιμοποιείται και μπορεί να διαγραφεί",
@@ -234,7 +234,7 @@
"IncludeHealthWarningsHelpText": "Συμπεριλάβετε προειδοποιήσεις για την υγεία",
"Security": "Ασφάλεια",
"Tasks": "Καθήκοντα",
"UnableToLoadBackups": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας",
"BackupsLoadError": "Δεν είναι δυνατή η φόρτωση αντιγράφων ασφαλείας",
"DownloadClientsLoadError": "Δεν είναι δυνατή η φόρτωση πελατών λήψης",
"UpdateMechanismHelpText": "Χρησιμοποιήστε το ενσωματωμένο πρόγραμμα ενημέρωσης του {appName} ή ένα script",
"AnalyticsEnabledHelpText": "Στείλτε ανώνυμες πληροφορίες χρήσης και σφάλματος στους διακομιστές του {appName}. Αυτό περιλαμβάνει πληροφορίες στο πρόγραμμα περιήγησής σας, ποιες σελίδες {appName} WebUI χρησιμοποιείτε, αναφορά σφαλμάτων καθώς και έκδοση λειτουργικού συστήματος και χρόνου εκτέλεσης. Θα χρησιμοποιήσουμε αυτές τις πληροφορίες για να δώσουμε προτεραιότητα σε λειτουργίες και διορθώσεις σφαλμάτων.",
@@ -431,7 +431,7 @@
"IndexerInfo": "Πληροφορίες ευρετηρίου",
"IndexerName": "Όνομα ευρετηρίου",
"IndexerProxies": "Proxer Indexer",
"IndexerNoDefinitionCheckHealthCheckMessage": "Τα ευρετήρια δεν έχουν ορισμό και δεν θα λειτουργήσουν: {0}. Αφαιρέστε και (ή) προσθέστε ξανά στο {appName}",
"IndexerNoDefinitionCheckHealthCheckMessage": "Τα ευρετήρια δεν έχουν ορισμό και δεν θα λειτουργήσουν: {indexerNames}. Αφαιρέστε και (ή) προσθέστε ξανά στο {appName}",
"SemiPrivate": "Ημι-ιδιωτικό",
"SettingsIndexerLoggingHelpText": "Καταγραφή πρόσθετων δεδομένων ευρετηρίου συμπεριλαμβανομένης της απόκρισης",
"SearchTypes": "Τύποι αναζήτησης",
@@ -458,7 +458,7 @@
"SyncLevelFull": "Πλήρης συγχρονισμός: Θα διατηρήσει πλήρως συγχρονισμένα τα ευρετήρια αυτής της εφαρμογής. Στη συνέχεια, οι αλλαγές που γίνονται στους indexers στο {appName} συγχρονίζονται με αυτήν την εφαρμογή. Οποιαδήποτε αλλαγή γίνει σε ευρετήρια απομακρυσμένα σε αυτήν την εφαρμογή θα παρακαμφθεί από τον {appName} στον επόμενο συγχρονισμό.",
"Remove": "Αφαιρώ",
"Replace": "Αντικαθιστώ",
"TheLatestVersionIsAlreadyInstalled": "Η τελευταία έκδοση του {appName} είναι ήδη εγκατεστημένη",
"OnLatestVersion": "Η τελευταία έκδοση του {appName} είναι ήδη εγκατεστημένη",
"ApiKeyValidationHealthCheckMessage": "Παρακαλούμε ενημερώστε το κλείδι API ώστε να έχει τουλάχιστον {length} χαρακτήρες. Μπορείτε να το κάνετε αυτό μέσα από τις ρυθμίσεις ή το αρχείο ρυθμίσεων",
"StopSelecting": "Διακοπή Επιλογής",
"OnHealthRestored": "Στην Αποκατάσταση Υγείας",
@@ -529,5 +529,16 @@
"BuiltIn": "Ενσωματωμένο",
"PublishedDate": "Ημερομηνία δημοσίευσης",
"Redirected": "Διευθύνω πάλιν",
"AllSearchResultsHiddenByFilter": "Όλα τα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο"
"AllSearchResultsHiddenByFilter": "Όλα τα αποτελέσματα αποκρύπτονται από το εφαρμοσμένο φίλτρο",
"Download": "Κατεβάστε",
"ErrorRestoringBackup": "Σφάλμα κατά την επαναφορά του αντιγράφου ασφαλείας",
"ExternalUpdater": "Το {appName} έχει ρυθμιστεί να χρησιμοποιεί έναν εξωτερικό μηχανισμό ενημέρωσης",
"NoEventsFound": "Δεν βρέθηκαν συμβάντα",
"RestartReloadNote": "Σημείωση: Το {appName} θα επανεκκινήσει αυτόματα και θα φορτώσει ξανά το περιβάλλον εργασίας χρήστη κατά τη διαδικασία επαναφοράς.",
"UpdateAppDirectlyLoadError": "Δεν είναι δυνατή η απευθείας ενημέρωση του {appName},",
"DockerUpdater": "ενημερώστε το κοντέινερ για να λάβετε την ενημέρωση",
"AptUpdater": "Χρησιμοποιήστε το apt για να εγκαταστήσετε την ενημέρωση",
"InstallLatest": "Εγκατάσταση πιο πρόσφατου",
"CurrentlyInstalled": "Εγκατεστημένο αυτήν τη στιγμή",
"Mixed": "Σταθερός"
}

View File

@@ -68,6 +68,7 @@
"Apps": "Apps",
"AppsMinimumSeeders": "Apps Minimum Seeders",
"AppsMinimumSeedersHelpText": "Minimum seeders required by the Applications for the indexer to grab, empty is Sync profile's default",
"AptUpdater": "Use apt to install the update",
"AreYouSureYouWantToDeleteCategory": "Are you sure you want to delete mapped category?",
"AreYouSureYouWantToDeleteIndexer": "Are you sure you want to delete '{name}' from {appName}?",
"Artist": "Artist",
@@ -98,6 +99,7 @@
"BackupNow": "Backup Now",
"BackupRetentionHelpText": "Automatic backups older than the retention period will be cleaned up automatically",
"Backups": "Backups",
"BackupsLoadError": "Unable to load backups",
"BasicSearch": "Basic Search",
"BeforeUpdate": "Before update",
"BindAddress": "Bind Address",
@@ -141,6 +143,7 @@
"CountDownloadClientsSelected": "{count} download client(s) selected",
"CountIndexersAvailable": "{count} indexer(s) available",
"CountIndexersSelected": "{count} indexer(s) selected",
"CurrentlyInstalled": "Currently Installed",
"Custom": "Custom",
"CustomFilter": "Custom Filter",
"CustomFilters": "Custom Filters",
@@ -184,8 +187,10 @@
"DisabledUntil": "Disabled Until",
"Discord": "Discord",
"Docker": "Docker",
"DockerUpdater": "Update the docker container to receive the update",
"Donate": "Donate",
"Donations": "Donations",
"Download": "Download",
"DownloadClient": "Download Client",
"DownloadClientAriaSettingsDirectoryHelpText": "Optional location to put downloads in, leave blank to use the default Aria2 location",
"DownloadClientCategory": "Download Client Category",
@@ -269,12 +274,16 @@
"Episode": "Episode",
"Error": "Error",
"ErrorLoadingContents": "Error loading contents",
"ErrorRestoringBackup": "Error restoring backup",
"EventType": "Event Type",
"Events": "Events",
"Exception": "Exception",
"ExistingTag": "Existing tag",
"External": "External",
"ExternalUpdater": "{appName} is configured to use an external update mechanism",
"Failed": "Failed",
"FailedToFetchSettings": "Failed to fetch settings",
"FailedToFetchUpdates": "Failed to fetch updates",
"FeatureRequests": "Feature Requests",
"Filename": "Filename",
"Files": "Files",
@@ -438,6 +447,11 @@
"Info": "Info",
"InfoUrl": "Info URL",
"InitialFailure": "Initial Failure",
"Install": "Install",
"InstallLatest": "Install Latest",
"InstallMajorVersionUpdate": "Install Update",
"InstallMajorVersionUpdateMessage": "This update will install a new major version and may not be compatible with your system. Are you sure you want to install this update?",
"InstallMajorVersionUpdateMessageLink": "Please check [{domain}]({url}) for more information.",
"InstanceName": "Instance Name",
"InstanceNameHelpText": "Instance name in tab and for Syslog app name",
"InteractiveSearch": "Interactive Search",
@@ -455,11 +469,13 @@
"Level": "Level",
"Link": "Link",
"LogFiles": "Log Files",
"LogFilesLocation": "Log files are located in: {location}",
"LogLevel": "Log Level",
"LogLevelTraceHelpTextWarning": "Trace logging should only be enabled temporarily",
"LogSizeLimit": "Log Size Limit",
"LogSizeLimitHelpText": "Maximum log file size in MB before archiving. Default is 1MB.",
"Logging": "Logging",
"Logout": "Logout",
"Logs": "Logs",
"MIA": "MIA",
"MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details",
@@ -496,6 +512,7 @@
"NoChange": "No Change",
"NoChanges": "No Changes",
"NoDownloadClientsFound": "No download clients found",
"NoEventsFound": "No events found",
"NoHistoryFound": "No history found",
"NoIndexerCategories": "No categories found for this indexer",
"NoIndexerHistory": "No history found for this indexer",
@@ -529,6 +546,7 @@
"OnHealthIssueHelpText": "On Health Issue",
"OnHealthRestored": "On Health Restored",
"OnHealthRestoredHelpText": "On Health Restored",
"OnLatestVersion": "The latest version of {appName} is already installed",
"Open": "Open",
"OpenBrowserOnStart": "Open browser on start",
"OpenThisModal": "Open This Modal",
@@ -553,6 +571,7 @@
"PreferMagnetUrl": "Prefer Magnet URL",
"PreferMagnetUrlHelpText": "When enabled, this indexer will prefer the use of magnet URLs for grabs with fallback to torrent links",
"Presets": "Presets",
"PreviouslyInstalled": "Previously Installed",
"Priority": "Priority",
"PrioritySettings": "Priority: {priority}",
"Privacy": "Privacy",
@@ -606,6 +625,7 @@
"Restart": "Restart",
"RestartNow": "Restart Now",
"RestartProwlarr": "Restart {appName}",
"RestartReloadNote": "Note: {appName} will automatically restart and reload the UI during the restore process.",
"RestartRequiredHelpTextWarning": "Requires restart to take effect",
"Restore": "Restore",
"RestoreBackup": "Restore Backup",
@@ -688,7 +708,7 @@
"SyncProfile": "Sync Profile",
"SyncProfiles": "Sync Profiles",
"System": "System",
"SystemTimeCheckMessage": "System time is off by more than 1 day. Scheduled tasks may not run correctly until the time is corrected",
"SystemTimeHealthCheckMessage": "System time is off by more than 1 day. Scheduled tasks may not run correctly until the time is corrected",
"TVSearchTypes": "TV Search Types",
"TableOptions": "Table Options",
"TableOptionsColumnsMessage": "Choose which columns are visible and which order they appear in",
@@ -703,7 +723,7 @@
"TestAllApps": "Test All Apps",
"TestAllClients": "Test All Clients",
"TestAllIndexers": "Test All Indexers",
"TheLatestVersionIsAlreadyInstalled": "The latest version of {appName} is already installed",
"TheLogLevelDefault": "The log level defaults to 'Info' and can be changed in [General Settings](/settings/general)",
"Theme": "Theme",
"ThemeHelpText": "Change Application UI Theme, 'Auto' Theme will use your OS Theme to set Light or Dark mode. Inspired by {inspiredBy}.",
"Time": "Time",
@@ -743,7 +763,6 @@
"UnableToAddANewIndexerProxyPleaseTryAgain": "Unable to add a new indexer proxy, please try again.",
"UnableToAddANewNotificationPleaseTryAgain": "Unable to add a new notification, please try again.",
"UnableToLoadAppProfiles": "Unable to load app profiles",
"UnableToLoadBackups": "Unable to load backups",
"UnableToLoadDevelopmentSettings": "Unable to load Development settings",
"UnableToLoadGeneralSettings": "Unable to load General settings",
"UnableToLoadHistory": "Unable to load history",
@@ -754,6 +773,7 @@
"UnableToLoadUISettings": "Unable to load UI settings",
"UnsavedChanges": "Unsaved Changes",
"UnselectAll": "Unselect All",
"UpdateAppDirectlyLoadError": "Unable to update {appName} directly,",
"UpdateAutomaticallyHelpText": "Automatically download and install updates. You will still be able to install from System: Updates",
"UpdateAvailableHealthCheckMessage": "New update is available: {version}",
"UpdateMechanismHelpText": "Use {appName}'s built-in updater or a script",
@@ -761,6 +781,7 @@
"UpdateStartupNotWritableHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is not writable by the user '{userName}'.",
"UpdateStartupTranslocationHealthCheckMessage": "Cannot install update because startup folder '{startupFolder}' is in an App Translocation folder.",
"UpdateUiNotWritableHealthCheckMessage": "Cannot install update because UI folder '{uiFolder}' is not writable by the user '{userName}'.",
"UpdaterLogFiles": "Updater Log Files",
"Updates": "Updates",
"Uptime": "Uptime",
"Url": "Url",
@@ -778,6 +799,7 @@
"Website": "Website",
"WhatsNew": "What's New?",
"Wiki": "Wiki",
"WouldYouLikeToRestoreBackup": "Would you like to restore the backup '{name}'?",
"XmlRpcPath": "XML RPC Path",
"Year": "Year",
"Yes": "Yes",

View File

@@ -48,7 +48,7 @@
"Scheduled": "Programado",
"SaveChanges": "Guardar cambios",
"RestoreBackup": "Restaurar copia de seguridad",
"ReleaseBranchCheckOfficialBranchMessage": "Las versión {0} no es una versión válida de {appName}, no recibirás actualizaciones",
"ReleaseBranchCheckOfficialBranchMessage": "La rama {0} no es una rama de lanzamiento válida de {appName}, no recibirás actualizaciones",
"Refresh": "Actualizar",
"Queue": "Cola",
"ProxyResolveIpHealthCheckMessage": "No se pudo resolver la dirección IP del Host Proxy configurado {proxyHostName}",
@@ -73,7 +73,7 @@
"LastWriteTime": "Última Fecha de Escritura",
"IndexerStatusUnavailableHealthCheckMessage": "Indexadores no disponibles debido a errores: {indexerNames}",
"Indexer": "Indexador",
"Grabbed": "Añadido",
"Grabbed": "Capturado",
"GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas, y actualizaciones",
"Filename": "Nombre de archivo",
"Failed": "Fallido",
@@ -99,7 +99,7 @@
"Peers": "Pares",
"PageSize": "Tamaño de Página",
"Ok": "Ok",
"OAuthPopupMessage": "Pop-ups bloqueados por su navegador",
"OAuthPopupMessage": "Los elementos emergentes están siendo bloqueados por tu navegador",
"Name": "Nombre",
"Message": "Mensaje",
"Level": "Nivel",
@@ -114,7 +114,7 @@
"Cancel": "Cancelar",
"Apply": "Aplicar",
"Age": "Antigüedad",
"SystemTimeCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido",
"SystemTimeHealthCheckMessage": "El reloj del sistema está retrasado más de un día. Las tareas de mantenimiento no se ejecutarán correctamente hasta que se haya corregido",
"UnsavedChanges": "Cambios sin guardar",
"ShowSearchHelpText": "Muestra el botón de búsqueda al pasar por encima",
"ShowSearch": "Mostrar búsqueda",
@@ -135,7 +135,7 @@
"DownloadClientSettings": "Opciones del cliente de descarga",
"Docker": "Docker",
"DeleteTag": "Eliminar Etiqueta",
"DeleteNotification": "Borrar Notificacion",
"DeleteNotification": "Eliminar Notificación",
"DeleteDownloadClient": "Borrar cliente de descarga",
"DeleteBackup": "Eliminar copia de seguridad",
"DatabaseMigration": "Migración de la base de datos",
@@ -143,7 +143,7 @@
"ClientPriority": "Prioridad del Cliente",
"ChangeHasNotBeenSavedYet": "El cambio aún no se ha guardado",
"CertificateValidationHelpText": "Cambiar la rigidez de la validación de la certificación HTTPS",
"CertificateValidation": "Validacion de certificado",
"CertificateValidation": "Validación de certificado",
"BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales",
"Branch": "Rama",
"BindAddressHelpText": "Dirección IP4 válida, localhost o '*' para todas las interfaces",
@@ -171,7 +171,7 @@
"UpdateAutomaticallyHelpText": "Descargar e instalar actualizaciones automáticamente. Todavía puedes instalar desde Sistema: Actualizaciones",
"UnableToLoadTags": "No se pueden cargar las Etiquetas",
"UnableToLoadNotifications": "No se pueden cargar las Notificaciones",
"DownloadClientsLoadError": "No se puden cargar los gestores de descargas",
"DownloadClientsLoadError": "No se pudieron cargar los clientes de descargas",
"UISettings": "Ajustes del UI",
"Torrents": "Torrents",
"TestAllClients": "Probar todos los clientes",
@@ -212,7 +212,7 @@
"Mechanism": "Mecanismo",
"Logs": "Registros",
"LogLevel": "Nivel de Registro",
"LaunchBrowserHelpText": " Abrir un navegador web e ir a la página de inicio de {appName} al arrancar la app.",
"LaunchBrowserHelpText": " Abre un navegador web y navega a la página de inicio de {appName} al iniciarse la aplicación.",
"Interval": "Intervalo",
"IndexerFlags": "Indicadores del indexador",
"IncludeHealthWarningsHelpText": "Incluir Alertas de Salud",
@@ -236,19 +236,19 @@
"ExistingTag": "Etiquetas existentes",
"EnableInteractiveSearchHelpText": "Se usará cuando se utilice la búsqueda interactiva",
"EnableAutomaticSearchHelpText": "Será usado cuando las búsquedas automáticas sean realizadas por la interfaz de usuario o por {appName}",
"DeleteTagMessageText": "¿Está seguro de querer eliminar la etiqueta '{label}'?",
"DeleteNotificationMessageText": "¿Seguro que quieres eliminar la notificación '{name}'?",
"DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{name}'?",
"DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{name}'?",
"CancelPendingTask": "Estas seguro de que deseas cancelar esta tarea pendiente?",
"BranchUpdateMechanism": "La rama se uso por un mecanisco de actualizacion externo",
"DeleteTagMessageText": "¿Estás seguro que quieres eliminar la etiqueta '{label}'?",
"DeleteNotificationMessageText": "¿Estás seguro que quieres eliminar la notificación '{name}'?",
"DeleteBackupMessageText": "¿Estás seguro que quieres eliminar la copia de seguridad '{name}'?",
"DeleteDownloadClientMessageText": "¿Estás seguro que quieres eliminar el cliente de descarga '{name}'?",
"CancelPendingTask": "¿Estás seguro que quieres cancelar esta tarea pendiente?",
"BranchUpdateMechanism": "Rama usada por un mecanismo de actualización externo",
"BranchUpdate": "Rama a usar para actualizar {appName}",
"BeforeUpdate": "Antes de actualizar",
"AddingTag": "Añadir etiqueta",
"UnableToLoadUISettings": "No se han podido cargar los ajustes de UI",
"UnableToLoadHistory": "No se ha podido cargar la historia",
"UnableToLoadGeneralSettings": "No se han podido cargar los ajustes Generales",
"UnableToLoadBackups": "No se pudo cargar las copias de seguridad",
"BackupsLoadError": "No se pudo cargar las copias de seguridad",
"UnableToAddANewNotificationPleaseTryAgain": "No se ha podido añadir una nueva notificación, prueba otra vez.",
"UnableToAddANewIndexerPleaseTryAgain": "No se pudo añadir un nuevo indexador, por favor inténtalo de nuevo.",
"UnableToAddANewDownloadClientPleaseTryAgain": "No se ha podido añadir un nuevo gestor de descargas, prueba otra vez.",
@@ -261,7 +261,7 @@
"NoTagsHaveBeenAddedYet": "Ninguna etiqueta ha sido añadida aún",
"NoLogFiles": "No hay archivos de registro",
"NoBackupsAreAvailable": "No hay copias de seguridad disponibles",
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver historial de commits de Github para mas detalle",
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver el historial de commits de Github para más detalles",
"ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.",
"FilterPlaceHolder": "Buscar Indexadores",
"Exception": "Excepción",
@@ -280,8 +280,8 @@
"FocusSearchBox": "Enfocar Campo de Búsqueda",
"SaveSettings": "Guardar ajustes",
"OpenThisModal": "Abrir esta Ventana Modal",
"MovieIndexScrollTop": "Indice de Películas: Desplazar hacia arriba",
"MovieIndexScrollBottom": "Indice de Películas: Desplazar hacia abajo",
"MovieIndexScrollTop": "Índice de Películas: Desplazar hacia arriba",
"MovieIndexScrollBottom": "Índice de Películas: Desplazar hacia abajo",
"CloseCurrentModal": "Cerrar esta Ventana Modal",
"AcceptConfirmationModal": "Aceptar Confirmación de esta Ventana Modal",
"IndexerLongTermStatusUnavailableHealthCheckMessage": "Indexadores no disponibles debido a errores durante más de 6 horas: {indexerNames}",
@@ -363,7 +363,7 @@
"Started": "Iniciado",
"Remove": "Eliminar",
"Replace": "Reemplazar",
"TheLatestVersionIsAlreadyInstalled": "La última versión de {appName} ya está instalada",
"OnLatestVersion": "La última versión de {appName} ya está instalada",
"Apps": "Aplicaciones",
"AddApplication": "Añadir aplicación",
"AddCustomFilter": "Añadir Filtro Personalizado",
@@ -398,7 +398,7 @@
"EditSelectedDownloadClients": "Editar Clientes de Descarga Seleccionados",
"EditSelectedIndexers": "Editar Indexadores Seleccionados",
"Implementation": "Implementación",
"ManageDownloadClients": "Gestionar Clientes de Descarga",
"ManageDownloadClients": "Administrar Clientes de Descarga",
"ApiKeyValidationHealthCheckMessage": "Actualice su clave de API para que tenga al menos {length} carácteres. Puede hacerlo en los ajustes o en el archivo de configuración",
"IndexerDownloadClientHealthCheckMessage": "Indexadores con clientes de descarga inválidos: {indexerNames}.",
"Episode": "Episodio",
@@ -425,7 +425,7 @@
"ResetAPIKeyMessageText": "¿Estás seguro que quieres restablecer tu clave API?",
"EditIndexerProxyImplementation": "Editar proxy de indexador - {implementationName}",
"AppUpdated": "{appName} Actualizado",
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes, necesitará recargar {appName}",
"AppUpdatedVersion": "{appName} ha sido actualizado a la versión `{version}`, para obtener los cambios más recientes tendrás que recargar {appName}",
"AddApplicationImplementation": "Agregar aplicación - {implementationName}",
"AddConnectionImplementation": "Añadir Conexión - {implementationName}",
"AddIndexerImplementation": "Agregar Indexador - {implementationName}",
@@ -493,9 +493,9 @@
"EditCategory": "Editar categoría",
"EditSyncProfile": "Editar perfil de sincronización",
"EnableIndexer": "Habilitar indexador",
"InvalidUILanguage": "Su interfaz de usuario está configurada en un idioma no válido, corríjalo y guarde la configuración",
"InvalidUILanguage": "Tu interfaz de usuario está configurada en un idioma inválido, corrígelo y guarda la configuración",
"DownloadClientQbittorrentSettingsContentLayout": "Diseño del contenido",
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Si usar el diseño de contenido configurado de qBittorrent, el diseño original del torrent o siempre crear una subcarpeta (qBittorrent 4.3.2+)",
"DownloadClientQbittorrentSettingsContentLayoutHelpText": "Si usa el diseño de contenido configurado de qBittorrent, el diseño original del torrent o siempre crea una subcarpeta (qBittorrent 4.3.2+)",
"EnableRssHelpText": "Habilitar canal RSS para el Indexador",
"days": "días",
"ElapsedTime": "Tiempo transcurrido",
@@ -517,7 +517,7 @@
"IndexerTagsHelpTextWarning": "Las etiquetas deben utilizarse con precaución, ya que pueden tener efectos no deseados. Un indexador con una etiqueta solo se sincronizará con aplicaciones que tengan la misma etiqueta.",
"TVSearchTypes": "Tipos de búsqueda de TV",
"DownloadClientAriaSettingsDirectoryHelpText": "Ubicación opcional en la que poner las descargas, dejar en blanco para usar la ubicación de Aria2 predeterminada",
"IndexerNoDefinitionCheckHealthCheckMessage": "Los indexadores no tienen definición y no funcionarán: {0}. Por favor elimínelos y (o) vuelva a añadirlos a {appName}.",
"IndexerNoDefinitionCheckHealthCheckMessage": "Los indexadores no tienen definición y no funcionarán: {indexerNames}. Por favor elimínalos y (o) vuelve a añadirlos a {appName}.",
"IndexerProxy": "Proxy del Indexador",
"IndexerObsoleteCheckMessage": "Los indexadores están obsoletos o se han actualizado: {0}. Por favor elimínelos y (o) vuelva a añadirlos a {appName}",
"IncludeManualGrabsHelpText": "Incluir las Capturas Manuales realizadas en {appName}",
@@ -537,7 +537,7 @@
"IndexerTagsHelpText": "Utilice etiquetas para especificar los Proxies del Indexador o las aplicaciones con las que se sincroniza el indexador.",
"MassEditor": "Editor Masivo",
"ApplicationsLoadError": "No se puede cargar la lista de aplicaciones",
"ManageClients": "Gestionar Clientes",
"ManageClients": "Administrar Clientes",
"ManageApplications": "Gestionar Aplicaciones",
"IndexerId": "ID del Indexador",
"IndexerInfo": "Información del Indexador",
@@ -609,10 +609,10 @@
"Url": "Url",
"VipExpiration": "Expiración VIP",
"TotalIndexerSuccessfulGrabs": "Capturas con Éxito Totales por Indexador",
"NotificationsEmailSettingsUseEncryptionHelpText": "Si prefiere utilizar el cifrado si está configurado en el servidor, utilizar siempre el cifrado mediante SSL (sólo puerto 465) o StartTLS (cualquier otro puerto) o no utilizar nunca el cifrado",
"NotificationsEmailSettingsUseEncryptionHelpText": "Si prefiere utilizar el cifrado si está configurado en el servidor, utilizar siempre el cifrado mediante SSL (sólo puerto 465) o StartTLS (cualquier otro puerto), o no utilizar nunca el cifrado",
"IndexerHDBitsSettingsPasskeyHelpText": "Clave de acceso desde los Detalles de Usuario",
"IndexerSettingsPasskey": "Clave de Acceso",
"BlackholeFolderHelpText": "La carpeta en donde {appName} se almacenaran los {extension} file",
"BlackholeFolderHelpText": "La carpeta donde {appName} almacenará los archivos {extension}",
"CustomFilter": "Filtro personalizado",
"LabelIsRequired": "Se requiere etiqueta",
"TorrentBlackholeSaveMagnetFiles": "Guardar archivos magnet",
@@ -771,7 +771,7 @@
"AverageGrabs": "Promedio de capturas",
"AllSearchResultsHiddenByFilter": "Todos los resultados están ocultos por el filtro aplicado.",
"PackageVersionInfo": "{packageVersion} por {packageAuthor}",
"HealthMessagesInfoBox": "Puede encontrar más información sobre la causa de estos mensajes de comprobación de salud haciendo clic en el enlace wiki (icono de libro) al final de la fila, o comprobando sus [logs]({link}). Si tienes dificultades para interpretar estos mensajes, puedes ponerte en contacto con nuestro servicio de asistencia en los enlaces que aparecen a continuación.",
"HealthMessagesInfoBox": "Puedes encontrar más información sobre la causa de estos mensajes de comprobación de salud haciendo clic en el enlace wiki (icono de libro) al final de la fila, o comprobando tus [registros]({link}). Si tienes dificultades para interpretar estos mensajes, puedes ponerte en contacto con nuestro soporte en los enlaces que aparecen abajo.",
"LogSizeLimit": "Límite de tamaño de registro",
"LogSizeLimitHelpText": "Máximo tamaño de archivo de registro en MB antes de archivarlo. Predeterminado es 1MB.",
"PreferMagnetUrl": "Preferir URL magnet",
@@ -784,5 +784,27 @@
"IndexerAvistazSettingsUsernameHelpText": "Nombre de usuario del sitio",
"IndexerAvistazSettingsUsernameHelpTextWarning": "Solo los miembros de rango y superiores pueden usar la API en este indexador.",
"IndexerAvistazSettingsPasswordHelpText": "Contraseña del sitio",
"IndexerAvistazSettingsPidHelpText": "PID de la página de Mi cuenta o Mi perfil"
"IndexerAvistazSettingsPidHelpText": "PID de la página de Mi cuenta o Mi perfil",
"LogFilesLocation": "Los archivos de registro se encuentran en: {location}",
"DockerUpdater": "Actualiza el contenedor docker para recibir la actualización",
"Download": "Descargar",
"ErrorRestoringBackup": "Error restaurando la copia de seguridad",
"ExternalUpdater": "{appName} está configurado para usar un mecanismo de actualización externo",
"FailedToFetchUpdates": "Fallo al buscar las actualizaciones",
"Logout": "Cerrar Sesión",
"NoEventsFound": "Ningún evento encontrado",
"RestartReloadNote": "Nota: {appName} se reiniciará automáticamente y recargará la interfaz durante el proceso de restauración.",
"TheLogLevelDefault": "El nivel de registro por defecto es 'Info' y puede ser cambiado en [Opciones generales](opciones/general)",
"UpdateAppDirectlyLoadError": "No se pudo actualizar {appName} directamente,",
"UpdaterLogFiles": "Actualizador de archivos de registro",
"WouldYouLikeToRestoreBackup": "Te gustaria restaurar la copia de seguridad '{name}'?",
"AptUpdater": "Usa apt para instalar la actualización",
"Install": "Instalar",
"InstallLatest": "Instala el último",
"InstallMajorVersionUpdateMessage": "Esta actualización instalará una nueva versión principal y podría no ser compatible con tu sistema. ¿Estás seguro que quieres instalar esta actualización?",
"InstallMajorVersionUpdate": "Instalar actualización",
"InstallMajorVersionUpdateMessageLink": "Por favor revisa [{domain}]({url}) para más información.",
"FailedToFetchSettings": "Error al recuperar la configuración",
"CurrentlyInstalled": "Actualmente instalado",
"PreviouslyInstalled": "Previamente instalado"
}

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