Compare commits

...

152 Commits

Author SHA1 Message Date
Bogdan
708c94bc56 Fixed PTP test 2025-05-15 00:47:46 +03:00
Bogdan
5ed82eaf09 Fixed: (PTP) Download torrent files with API credentials 2025-05-14 22:44:26 +03:00
Bogdan
7d77ad68fd Bump caniuse db 2025-05-14 21:25:20 +03:00
Bogdan
6725358db5 Bump babel, fontawesome icons, react-use-measure, react-virtualized and react-window 2025-05-14 21:25:20 +03:00
Bogdan
c410e23460 Bump core-js to 3.42 2025-05-14 21:25:20 +03:00
Bogdan
903b86b9a2 Bump version to 1.36.2 2025-05-11 14:48:48 +03:00
Weblate
52a49e6a34 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Discover999 <13189912235@163.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: ZijiYu <ziji.yu@stonybrook.edu>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/
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_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/
Translation: Servarr/Prowlarr
2025-05-11 00:07:11 +03:00
Bogdan
a7d99f351c Fixed: Parsing user agents without a version
Fixes #2392
2025-05-11 00:05:29 +03:00
Bogdan
b0212dd780 Add hourly limits as defaults for PTP 2025-05-10 11:55:11 +03:00
Bogdan
c8f5099423 Use the thrown exception in http timeout handling 2025-05-09 15:58:02 +03:00
Bogdan
5cc4c3f302 Bump version to 1.36.1 2025-05-04 21:06:28 +03:00
Bogdan
c0d2cb42e9 Fixed: (PTP) Sorting releases by time added 2025-05-01 17:06:17 +03:00
Bogdan
8081f13052 Clean logging messages in AppriseProxy 2025-05-01 12:12:47 +03:00
Bogdan
84b672e617 Fixed: Sync indexers to apps only if search is available 2025-05-01 01:34:09 +03:00
Bogdan
ed586c2d72 Update fixture file for PTP 2025-05-01 00:30:55 +03:00
Bogdan
233176e321 Improve error message when BHD's API responds with HTML 2025-04-30 22:12:30 +03:00
Bogdan
d1e3390bae Fixed: (PTP) Category mapping for search results 2025-04-30 22:12:30 +03:00
Bogdan
1cd60c7a40 Bump version to 1.36.0 2025-04-30 14:03:05 +03:00
Bogdan
c61cfcd312 Avoid logging the whole response in the exception when not finding JSON selectors in Cardigann 2025-04-30 12:36:34 +03:00
Weblate
5eb4d112ca Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nb_NO/
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/uk/
Translation: Servarr/Prowlarr
2025-04-29 11:05:21 +03:00
Mark McDowall
70f2361d69 Improve messaging when NZB contains invalid XML
(cherry picked from commit 728df146ada115a367bf1ce808482a4625e6098d)
2025-04-29 10:58:31 +03:00
Bogdan
1d6babaa15 Bump caniuse db 2025-04-29 10:23:51 +03:00
Bogdan
0427add8d0 Bump core-js to 3.41 2025-04-29 10:23:15 +03:00
Bogdan
010c2b836d Clean up formatted strings in log messages 2025-04-29 10:16:59 +03:00
Bogdan
22c4c1fc9a Pass messages with arguments to NLog in LoggerExtensions
(cherry picked from commit 9683b0af35220bb0af801779a06d73feaeba809a)
2025-04-29 10:14:32 +03:00
Bogdan
d5f6cc94b8 Fixed: (PTP) TV search capabilities removed 2025-04-29 10:04:40 +03:00
Bogdan
411e96ef2a New: Redirect enabled by default when adding new usenet indexers 2025-04-28 21:52:09 +03:00
Bogdan
2b0e52ebca Update default log level message 2025-04-27 21:22:37 +03:00
Bogdan
c6fa26ca7b Bump version to 1.35.1 2025-04-27 11:48:50 +03:00
blu3
c85f170d41 Bump license year 2025-04-23 11:34:19 +03:00
Bogdan
48a658571b Improve error messaging for not finding JSON selectors in Cardigann 2025-04-21 14:39:22 +03:00
Weblate
0b3a5c9bc4 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Hugoren Martinako <aumpfbahn@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translation: Servarr/Prowlarr
2025-04-20 22:30:45 +03:00
Bogdan
356d07ef34 Bump version to 1.35.0 2025-04-20 22:30:15 +03:00
Bogdan
0322d70d63 Fixed: Handle 307 and 308 redirects for indexer download requests 2025-04-20 11:09:08 +03:00
Bogdan
362f3fe223 Bump version to 1.34.1 2025-04-13 09:48:04 +03:00
Bogdan
075fd24f96 Downgrade Microsoft.AspNetCore.WebUtilities 2025-04-12 17:23:45 +03:00
Bogdan
4ba72ea7f3 Bump Swashbuckle to 7.3.2 2025-04-12 14:54:56 +03:00
Bogdan
46f73c51bb Bump IPAddressRange, Npgsql, System.Text.Json 2025-04-12 14:54:01 +03:00
Bogdan
3287d45661 Update timezone offset for AvistaZ trackers 2025-04-12 14:42:25 +03:00
Bogdan
71937fa44c Update timezone offset for FL 2025-04-12 14:33:30 +03:00
Bogdan
6aefd46cd4 Fixed: (SecretCinema) Edition not being decoded 2025-04-12 14:31:29 +03:00
Bogdan
c8370c9e00 Bump version to 1.34.0 2025-04-09 20:59:15 +03:00
Servarr
6be4203b41 Automated API Docs update 2025-04-09 10:29:44 +03:00
Bogdan
1339373e43 Bump Selenium.WebDriver.ChromeDriver 2025-04-08 13:30:56 +03:00
Bogdan
fc9dfb0cf7 Fixed: Disallow tags creation with empty label 2025-04-08 13:30:03 +03:00
Mark McDowall
48301055ea Fixed: Set output encoding to UTF-8 when running external processes
(cherry picked from commit f8e57b09856278a6d0c65f18704e96a33459687d)
2025-04-08 13:29:32 +03:00
Mark McDowall
8a9518c9c1 Update WikiUrl type in API docs
(cherry picked from commit 9bd619ccfe074abe396bbf043a36a5be18a7ba4b)
2025-04-08 13:29:09 +03:00
Bogdan
de099c6770 Log delete statements only once 2025-04-08 13:28:52 +03:00
Bogdan
07711da4e0 Bump version to 1.33.3 2025-04-06 15:44:25 +03:00
MrE12345
7cb70716d0 Fixed: (NorBits) Change encoding to UTF8 (#2367) 2025-04-06 12:43:24 +03:00
Weblate
548dedad5c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ste <stefanucciu@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
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/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/uk/
Translation: Servarr/Prowlarr
2025-04-06 12:23:27 +03:00
Bogdan
7008626358 Fixed: (PassThePopcorn) Parse volume factors for neutral leech releases 2025-04-04 21:34:10 +03:00
Bogdan
f6f2a3b00d Bump linux agent to ubuntu-22.04 2025-04-02 00:10:40 +03:00
Weblate
2b16d93095 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Alex Mills <alex@alexmills.uk>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
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/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fa/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
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/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2025-03-30 10:30:41 +03:00
Bogdan
e63ee13d23 Bump version to 1.33.2 2025-03-30 10:30:03 +03:00
Bogdan
5c5a163151 Fixed: (AnimeBytes) Allow season searching for ONA 2025-03-28 13:39:19 +02:00
Bogdan
023eec0ec0 Update timezone offset for PrivateHD and CinemaZ 2025-03-25 13:04:07 +02:00
Bogdan
5bc5f0e6b8 New: Categories, genres, indexer flags and publish dates for webhook releases 2025-03-25 13:00:53 +02:00
Bogdan
5cbacc01eb Fixed: Publish dates timezone in history details for grabbed releases 2025-03-25 13:00:53 +02:00
Bogdan
f4f1b38324 New: On Grab notifications for CustomScript 2025-03-25 13:00:53 +02:00
Bogdan
758dddd4ad Bump version to 1.33.1 2025-03-23 09:45:33 +02:00
Bogdan
73ee695633 New: (BeyondHD) Parsing audio and subtitles languages 2025-03-22 21:01:22 +02:00
Bogdan
27fbd7ef7e Fixed: (RuTracker.org) Improve subtitles removal 2025-03-22 12:45:10 +02:00
Bogdan
5125f256fb Fixed: Priority validation for indexers and download clients 2025-03-20 20:38:13 +02:00
Mark McDowall
b99e8d0d65 Improve logging when login fails due to CryptographicException
(cherry picked from commit 1449941471cbb8885e9298317b9a30f2576d7941)
2025-03-16 13:10:09 +02:00
Bogdan
d20b2cc9c0 Bump NLog and Polly 2025-03-16 12:06:32 +02:00
Bogdan
8a1787bdb6 Bump version to 1.33.0 2025-03-16 11:42:07 +02:00
Mark McDowall
a19b8ea997 New: Truncate button text
Fixes #2352

(cherry picked from commit 093ee5b88db0470426f6132e66a5893e5cf89bab)
2025-03-10 20:07:15 +02:00
Mark McDowall
10ea6cd753 Improve wrapping of text in sidebar
(cherry picked from commit f58dfc5605738ebccdd6adc6f1ca2a7843c086b2)
2025-03-10 20:07:15 +02:00
Bogdan
2c1b464715 New: Recommend against using uTorrent
(cherry picked from commit 6d8c3f15b343a24fc31a212463af8ed2b5792508)
2025-03-10 20:07:15 +02:00
Bogdan
3263454041 Bump version to 1.32.2 2025-03-09 11:50:31 +02:00
Servarr
015db4a916 Translations update from Servarr Weblate (#2351)
Multiple Translations updated by Weblate

ignore-downstream







Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_Hans/
Translation: Servarr/Prowlarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: wangdj1314 <wangdj@risenenergy.com>
Co-authored-by: 葛磊磊 <geleilei198117@163.com>
2025-03-07 10:38:29 +02:00
Bogdan
49268f3b8d Fix timezone offset tests for AvistaZ trackers 2025-03-04 13:15:44 +02:00
Bogdan
f02a6f3e2c Update timezone offset for AvistaZ trackers 2025-03-03 17:17:29 +02:00
Bogdan
46b6124b97 Bump version to 1.32.1 2025-03-02 12:17:40 +02:00
Bogdan
53bc97b3be Fixed: (BeyondHd) Search daily episodes using year-month-day format 2025-03-01 17:34:58 +02:00
Bogdan
b09d4927cc Check instance name must contain application name with culture-insensitive 2025-03-01 13:38:34 +02:00
Bogdan
328f3c0423 Bump version to 1.32.0 2025-02-22 12:55:30 +02:00
Mark McDowall
635e76526a Cleanse console log messages
(cherry picked from commit 609e964794e17343f63e1ecff3fef323e3d284ff)
2025-02-19 15:59:34 +02:00
Stevie Robinson
790feed5ab Fixed: Fallback to Instance Name for Discord notifications
(cherry picked from commit b99e06acc0a3ecae2857d9225b35424c82c67a2b)
2025-02-19 15:55:42 +02:00
Mark McDowall
59b5d2fc78 Fixed: Drop downs flickering in some cases
(cherry picked from commit 3b024443c5447b7638a69a99809bf44b2419261f)
2025-02-18 17:09:56 +02:00
Bogdan
d5b12cf51a Fixed release guid for SpeedApp 2025-02-18 04:00:24 +02:00
Bogdan
2d584f7eb6 New: Support for exclusive indexer flag
Co-authored-by: zakkarry <zak@ary.dev>
2025-02-18 02:11:57 +02:00
Bogdan
0f1d647cd7 Fixed: (FileList) Download links when passkey contains spaces 2025-02-16 12:22:44 +02:00
zodihax
d6e8d89be4 Fixed: (NorBits) Update release category parsing (#2342)
Co-authored-by: Bogdan <mynameisbogdan@users.noreply.github.com>
2025-02-12 19:27:09 +02:00
Bogdan
8672129d5a Fixed: (AnimeTorrents) Switched to cookies login 2025-02-12 15:52:22 +02:00
Bogdan
44bdff8b8f Minor cleanup for AnimeTorrents 2025-02-12 15:52:22 +02:00
Bogdan
4df8fc02f1 Bump version to 1.31.2 2025-02-09 17:51:35 +02:00
Weblate
e101129cff Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Marius Nechifor <flm.marius@gmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
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/fa/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2025-02-07 19:14:29 -06:00
Bogdan
147e732c9c Building docs on ARM
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2025-02-06 00:36:13 +02:00
Bogdan
a12381fb1d Cleanse "rsskey" from logs 2025-02-05 20:06:51 +02:00
Bogdan
3a4de9cca1 Fixed: (MAM) Continue downloading if attempting to buy personal FL for VIP release 2025-02-05 19:59:48 +02:00
Bogdan
43c988d951 Fixed: (MAM) Use the latest cookies on release download 2025-02-05 19:51:20 +02:00
Bogdan
a036e0fc37 Fixed: (MAM) Updated property name for user class 2025-02-05 19:42:32 +02:00
Bogdan
56b9da16cf Fix release category selector on all themes for NorBits
Co-authored-by: Garfield69 <garfield69@outlook.com>
2025-02-05 19:24:36 +02:00
zodihax
887c262589 Update release category selector for NorBits (#2338) 2025-02-05 12:55:53 +02:00
zodihax
12ff612775 Fixed: (NorBits) Added main categories to avoid invalid releases (#2337)
NorBits also has these main categories in addition to the already configured sub-categories. This PR adds these main categories.

Prowlarr often return 0 query results even when there are query results, this is probably caused by all the results only having a main category (for instance "TV") and no sub-categories.

`|Warn|NorBits|Invalid Release: '<redacted>' from indexer: NorBits. No categories provided.`
2025-02-03 18:03:40 +02:00
Bogdan
0d3d27e46f Fixed: (HDB) Use release name for full discs and XXX content 2025-02-02 18:51:12 +02:00
Bogdan
d1846fde61 New: (Myanonamouse) Prevent downloads without FL tokens
Co-authored-by: Kalon Shannon-Innes <mav@hotmail.com.au>
2025-02-02 17:46:28 +02:00
Bogdan
e6901506a0 Fixed: (IPTorrents) Cleanup languages between brackets when possible 2025-02-02 17:44:31 +02:00
Weblate
08b4eddbc5 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Mailme Dashite <mailmedashite@protonmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: marapavelka <mara.pavelka@gmail.com>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2025-02-02 16:13:56 +02:00
Bogdan
979db70e68 Bump version to 1.31.1 2025-02-02 12:47:52 +02:00
Bogdan
22834a852a Fixed: TV search with tmdbid for Newznab and Torznab 2025-01-29 18:39:22 +02:00
Bogdan
f0540a5f8b Bump version to 1.31.0 2025-01-24 17:33:38 +02:00
Weblate
1f7ac7d7d6 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: HanaO00 <lwin24452@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
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/pt_BR/
Translation: Servarr/Prowlarr
2025-01-24 13:19:05 +02:00
Bogdan
8ac68240ad Revert "Improve error message on non-JSON responses for Nebulance"
This reverts commit 2c3621d25e.
2025-01-23 16:42:41 +02:00
Bogdan
b463a3f54b Update categories for RuTracker
Co-authored-by: Garfield69 <garfield69@outlook.com>
2025-01-23 15:27:45 +02:00
Bogdan
e15e57329e Update categories for XSpeeds
Co-authored-by: Garfield69 <garfield69@outlook.com>
2025-01-23 15:27:45 +02:00
Bogdan
d8354408a4 Update categories for AnimeTorrents
Co-authored-by: ilike2burnthing <59480337+ilike2burnthing@users.noreply.github.com>
2025-01-23 15:27:45 +02:00
bakerboy448
6d2d49f7bd Fixed: (PTP) Filtering non-freeleech releases when using Freeleech Only
Co-authored-by: Bogdan <mynameisbogdan@users.noreply.github.com>
2025-01-23 02:36:03 +02:00
Bogdan
37610eec40 Fixed: (TorrentDay) Improved error message for expired cookies 2025-01-22 19:44:49 +02:00
Steel City Phantom
ed51208116 Auto-detect building on macOS ARM
(cherry picked from commit 64122b4cfb3bf53bdbf5c924baee5e1b0814501a)
2025-01-21 01:04:44 +02:00
Bogdan
26e4dcad65 Bump version to 1.30.2 2025-01-19 17:14:44 +02:00
Bogdan
6eb21a02a1 Bump NLog, Polly, System.Memory and AngleSharp 2025-01-15 23:23:30 +02:00
Bogdan
8c2d5a404d Fixed BR-DISK detection for AnimeBytes 2025-01-15 01:56:48 +02:00
Bogdan
3b83a00eaf Fixed: (AnimeBytes) Improve M2TS and ISO titles for BR-DISK detection 2025-01-12 19:01:14 +02:00
Weblate
a5a86a6f86 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fi/
Translation: Servarr/Prowlarr
2025-01-12 15:15:03 +02:00
Bogdan
e7ed09a43d Bump version to 1.30.1 2025-01-12 15:14:09 +02:00
Bogdan
547bc2e58c New: (MyAnonamouse) Search by languages option
Fixes #2326
2025-01-10 22:36:11 +02:00
Weblate
8eb674c8d7 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Ano10 <Ano10@users.noreply.translate.servarr.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Matti Meikäläinen <diefor-93@hotmail.com>
Co-authored-by: Mickaël O <mickael.ouillon@ac-bordeaux.fr>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply-mt-weblate@weblate.org>
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/da/
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/tr/
Translation: Servarr/Prowlarr
2025-01-08 13:07:07 +02:00
Bogdan
2c3621d25e Improve error message on non-JSON responses for Nebulance 2025-01-07 04:07:54 +02:00
Bogdan
2648f2c639 Fixed: (BTN) Improve M2TS and ISO titles for BR-DISK detection 2025-01-06 13:30:01 +02:00
Bogdan
f4d621063b Bump version to 1.30.0 2025-01-05 15:40:12 +02:00
Stevie Robinson
73494c462c Fixed: Listening on all IPv4 Addresses
(cherry picked from commit 035c474f10c257331a5f47e863d24af82537e335)
2025-01-05 14:27:33 +02:00
Bogdan
36f6896f30 Fixed: (PassThePopcorn) Increase rate limit 2025-01-02 23:20:39 +02:00
Bogdan
e01741a69e New: (AnimeBytes) Use error message from response 2024-12-31 16:33:19 +02:00
Bogdan
1dbff1235e Match single digits only in season number regex for AnimeBytes 2024-12-31 16:26:05 +02:00
Bogdan
1a9ad6b363 Suggest adding IP to RPC whitelist for on failed Transmission auth
(cherry picked from commit f05e552e8e6dc02cd26444073ab9a678dcb36492)
2024-12-31 12:23:32 +02:00
Bogdan
c88249300c Check if backup folder is writable on backup
(cherry picked from commit 8aad79fd3e14eb885724a5e5790803c289be2f25)
2024-12-31 12:23:09 +02:00
Qstick
7b8e352d87 Bump SonarCloud azure extension to 3.X 2024-12-30 22:49:24 -06:00
Bogdan
81f7a6cbab Word boundary in season number regex for AnimeBytes 2024-12-31 02:11:14 +02:00
Bogdan
523e46af2a Fixed: (AnimeBytes) Include year in release title for series with year in filenames 2024-12-31 01:55:55 +02:00
Bogdan
2b4a6def2a Fixed privacy level for Nebulance's API key 2024-12-30 00:59:48 +02:00
Bogdan
9097c0ef6d Bump version to 1.29.2 2024-12-30 00:59:35 +02:00
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
146 changed files with 3761 additions and 1974 deletions

View File

@@ -78,6 +78,6 @@ Thank you to [<img src="https://resources.jetbrains.com/storage/products/company
### License
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2024
- Copyright 2010-2025
Icon Credit - [Box vector created by freepik - www.freepik.com](https://www.freepik.com/vectors/box)

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '1.28.2'
majorVersion: '1.36.2'
minorVersion: $[counter('minorVersion', 1)]
prowlarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
@@ -19,7 +19,7 @@ variables:
nodeVersion: '20.X'
innoVersion: '6.2.2'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
linuxImage: 'ubuntu-22.04'
macImage: 'macOS-13'
trigger:
@@ -1169,12 +1169,12 @@ stages:
submodules: true
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
- task: SonarCloudPrepare@2
- task: SonarCloudPrepare@3
condition: eq(variables['System.PullRequest.IsFork'], 'False')
inputs:
SonarCloud: 'SonarCloud'
organization: 'prowlarr'
scannerMode: 'MSBuild'
scannerMode: 'dotnet'
projectKey: 'Prowlarr_Prowlarr'
projectName: 'Prowlarr'
projectVersion: '$(prowlarrVersion)'
@@ -1187,7 +1187,7 @@ stages:
./build.sh --backend -f net6.0 -r win-x64
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage
displayName: Coverage Unit Tests
- task: SonarCloudAnalyze@2
- task: SonarCloudAnalyze@3
condition: eq(variables['System.PullRequest.IsFork'], 'False')
displayName: Publish SonarCloud Results
- task: reportgenerator@5.3.11

11
docs.sh
View File

@@ -3,15 +3,16 @@ set -e
FRAMEWORK="net6.0"
PLATFORM=$1
ARCHITECTURE="${2:-x64}"
if [ "$PLATFORM" = "Windows" ]; then
RUNTIME="win-x64"
RUNTIME="win-$ARCHITECTURE"
elif [ "$PLATFORM" = "Linux" ]; then
RUNTIME="linux-x64"
RUNTIME="linux-$ARCHITECTURE"
elif [ "$PLATFORM" = "Mac" ]; then
RUNTIME="osx-x64"
RUNTIME="osx-$ARCHITECTURE"
else
echo "Platform must be provided as first arguement: Windows, Linux or Mac"
echo "Platform must be provided as first argument: Windows, Linux or Mac"
exit 1
fi
@@ -37,7 +38,7 @@ dotnet clean $slnFile -c Release
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
dotnet new tool-manifest
dotnet tool install --version 6.6.2 Swashbuckle.AspNetCore.Cli
dotnet tool install --version 7.3.2 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Prowlarr.Api.V1/openapi.json "$outputFolder/$FRAMEWORK/$RUNTIME/$application" v1 &

View File

@@ -170,7 +170,7 @@ module.exports = (env) => {
loose: true,
debug: false,
useBuiltIns: 'entry',
corejs: '3.39'
corejs: '3.42'
}
]
]

View File

@@ -20,6 +20,8 @@ import HintedSelectInputSelectedValue from './HintedSelectInputSelectedValue';
import TextInput from './TextInput';
import styles from './EnhancedSelectInput.css';
const MINIMUM_DISTANCE_FROM_EDGE = 10;
function isArrowKey(keyCode) {
return keyCode === keyCodes.UP_ARROW || keyCode === keyCodes.DOWN_ARROW;
}
@@ -137,18 +139,9 @@ class EnhancedSelectInput extends Component {
// Listeners
onComputeMaxHeight = (data) => {
const {
top,
bottom
} = data.offsets.reference;
const windowHeight = window.innerHeight;
if ((/^botton/).test(data.placement)) {
data.styles.maxHeight = windowHeight - bottom;
} else {
data.styles.maxHeight = top;
}
data.styles.maxHeight = windowHeight - MINIMUM_DISTANCE_FROM_EDGE;
return data;
};
@@ -460,6 +453,10 @@ class EnhancedSelectInput extends Component {
order: 851,
enabled: true,
fn: this.onComputeMaxHeight
},
preventOverflow: {
enabled: true,
boundariesElement: 'viewport'
}
}}
>

View File

@@ -24,6 +24,7 @@
composes: link;
padding: 10px 24px;
padding-left: 35px;
}
.isActiveLink {
@@ -41,10 +42,6 @@
text-align: center;
}
.noIcon {
margin-left: 25px;
}
.status {
float: right;
}

View File

@@ -8,7 +8,6 @@ interface CssExports {
'isActiveParentLink': string;
'item': string;
'link': string;
'noIcon': string;
'status': string;
}
export const cssExports: CssExports;

View File

@@ -63,9 +63,7 @@ class PageSidebarItem extends Component {
</span>
}
<span className={isChildItem ? styles.noIcon : null}>
{typeof title === 'function' ? title() : title}
</span>
{typeof title === 'function' ? title() : title}
{
!!StatusComponent &&

View File

@@ -22,11 +22,14 @@
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
height: 24px;
}
.label {
padding: 0 3px;
max-width: 100%;
max-height: 100%;
color: var(--toolbarLabelColor);
font-size: $extraSmallFontSize;
line-height: calc($extraSmallFontSize + 1px);

View File

@@ -23,6 +23,7 @@ function PageToolbarButton(props) {
isDisabled && styles.isDisabled
)}
isDisabled={isDisabled || isSpinning}
title={label}
{...otherProps}
>
<Icon

View File

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

View File

@@ -23,17 +23,17 @@
"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.2",
"@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-regular-svg-icons": "6.7.2",
"@fortawesome/free-solid-svg-icons": "6.7.2",
"@fortawesome/react-fontawesome": "0.2.2",
"@juggle/resize-observer": "3.4.0",
"@microsoft/signalr": "6.0.25",
"@sentry/browser": "7.119.1",
"@sentry/integrations": "7.119.1",
"@types/node": "20.16.11",
"@types/react": "18.2.79",
"@types/react": "18.3.21",
"@types/react-dom": "18.2.25",
"chart.js": "4.4.4",
"classnames": "2.5.1",
@@ -71,9 +71,9 @@
"react-router-dom": "5.2.0",
"react-tabs": "4.3.0",
"react-text-truncate": "0.19.0",
"react-use-measure": "2.1.1",
"react-virtualized": "9.21.1",
"react-window": "1.8.10",
"react-use-measure": "2.1.7",
"react-virtualized": "9.22.6",
"react-window": "1.8.11",
"redux": "4.2.1",
"redux-actions": "2.6.5",
"redux-batched-actions": "0.5.0",
@@ -84,27 +84,27 @@
"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.27.1",
"@babel/eslint-parser": "7.27.1",
"@babel/plugin-proposal-export-default-from": "7.27.1",
"@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.27.2",
"@babel/preset-react": "7.27.1",
"@babel/preset-typescript": "7.27.1",
"@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.39.0",
"core-js": "3.42.0",
"css-loader": "6.7.3",
"css-modules-typescript-loader": "4.0.1",
"eslint": "8.57.1",

View File

@@ -221,7 +221,7 @@
<PropertyGroup Condition="'$(IsOSX)' == 'true' and
'$(RuntimeIdentifier)' == ''">
<_UsingDefaultRuntimeIdentifier>true</_UsingDefaultRuntimeIdentifier>
<RuntimeIdentifier>osx-x64</RuntimeIdentifier>
<RuntimeIdentifier>osx-$(Architecture)</RuntimeIdentifier>
</PropertyGroup>
</Project>

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Selenium.Support" Version="4.1.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="99.0.4844.5100" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="134.0.6998.16500" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />

View File

@@ -16,6 +16,8 @@ namespace NzbDrone.Common.Test.Http
[TestCase("Readarr/1.0.0.2300 (ubuntu 20.04)", "Readarr")]
[TestCase("Sonarr/3.0.6.9999 (ubuntu 20.04)", "Sonarr")]
[TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36", "Other")]
[TestCase("appbrr", "appbrr")]
[TestCase(" appbrr ", "appbrr")]
public void should_parse_user_agent(string userAgent, string parsedAgent)
{
UserAgentParser.ParseSource(userAgent).Should().Be(parsedAgent);

View File

@@ -30,6 +30,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://anthelion.me/api.php?api_key=2b51db35e1910123321025a12b9933d2&o=json&t=movie&q=&tmdb=&imdb=&cat=&limit=100&offset=0")]
[TestCase(@"https://avistaz.to/api/v1/jackett/auth: username=mySecret&password=mySecret&pid=mySecret")]
[TestCase(@"https://www.sharewood.tv/api/2b51db35e1910123321025a12b9933d2/last-torrents")]
[TestCase(@"https://example.org/rss/torrents?rsskey=2b51db35e1910123321025a12b9933d2&search=")]
// Indexer and Download Client Responses

View File

@@ -42,17 +42,18 @@ namespace NzbDrone.Common
public void CreateZip(string path, IEnumerable<string> files)
{
using (var zipFile = ZipFile.Create(path))
_logger.Debug("Creating archive {0}", path);
using var zipFile = ZipFile.Create(path);
zipFile.BeginUpdate();
foreach (var file in files)
{
zipFile.BeginUpdate();
foreach (var file in files)
{
zipFile.Add(file, Path.GetFileName(file));
}
zipFile.CommitUpdate();
zipFile.Add(file, Path.GetFileName(file));
}
zipFile.CommitUpdate();
}
private void ExtractZip(string compressedFile, string destination)

View File

@@ -167,7 +167,7 @@ namespace NzbDrone.Common.Http.Dispatchers
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null);
throw new WebException("Http request timed out", ex, WebExceptionStatus.Timeout, null);
}
}

View File

@@ -1,15 +1,16 @@
using System;
using System.Text.RegularExpressions;
namespace NzbDrone.Common.Http
{
public static class UserAgentParser
{
private static readonly Regex AppSourceRegex = new Regex(@"(?<agent>[a-z0-9]*)\/.*(?:\(.*\))?",
private static readonly Regex AppSourceRegex = new (@"^(?<agent>[a-z0-9]+)(?:\/.+(?:\(.*\))?|$)",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static string SimplifyUserAgent(string userAgent)
{
if (userAgent == null || userAgent.StartsWith("Mozilla/5.0"))
if (userAgent == null || userAgent.StartsWith("Mozilla/5.0", StringComparison.Ordinal))
{
return null;
}
@@ -19,14 +20,9 @@ namespace NzbDrone.Common.Http
public static string ParseSource(string userAgent)
{
var match = AppSourceRegex.Match(SimplifyUserAgent(userAgent) ?? string.Empty);
var match = AppSourceRegex.Match(SimplifyUserAgent(userAgent?.Trim()) ?? string.Empty);
if (match.Groups["agent"].Success)
{
return match.Groups["agent"].Value;
}
return "Other";
return match.Groups["agent"].Success ? match.Groups["agent"].Value : "Other";
}
}
}

View File

@@ -10,7 +10,7 @@ namespace NzbDrone.Common.Instrumentation
private static readonly Regex[] CleansingRules =
{
// Url
new (@"(?<=[?&: ;])(apikey|api_key|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|user|u?id|api|[a-z_]*apikey|account|pid|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=[?&: ;])(apikey|api_key|(?:(?:access|api)[-_]?)?token|pass(?:key|wd)?|auth|authkey|rsskey|user|u?id|api|[a-z_]*apikey|account|pid|pwd)=(?<secret>[^&=""]+?)(?=[ ""&=]|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"rss(24h)?\.torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new (@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),

View File

@@ -0,0 +1,21 @@
using System.Text;
using NLog;
using NLog.Layouts.ClefJsonLayout;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation;
public class CleansingClefLogLayout : CompactJsonLayout
{
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
base.RenderFormattedMessage(logEvent, target);
if (RuntimeInfo.IsProduction)
{
var result = CleanseLogMessage.Cleanse(target.ToString());
target.Clear();
target.Append(result);
}
}
}

View File

@@ -0,0 +1,26 @@
using System.Text;
using NLog;
using NLog.Layouts;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Common.Instrumentation;
public class CleansingConsoleLogLayout : SimpleLayout
{
public CleansingConsoleLogLayout(string format)
: base(format)
{
}
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
base.RenderFormattedMessage(logEvent, target);
if (RuntimeInfo.IsProduction)
{
var result = CleanseLogMessage.Cleanse(target.ToString());
target.Clear();
target.Append(result);
}
}
}

View File

@@ -4,7 +4,7 @@ using NLog.Targets;
namespace NzbDrone.Common.Instrumentation
{
public class NzbDroneFileTarget : FileTarget
public class CleansingFileTarget : FileTarget
{
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{

View File

@@ -4,27 +4,27 @@ namespace NzbDrone.Common.Instrumentation.Extensions
{
public static class LoggerExtensions
{
[MessageTemplateFormatMethod("message")]
public static void ProgressInfo(this Logger logger, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
LogProgressMessage(logger, LogLevel.Info, formattedMessage);
LogProgressMessage(logger, LogLevel.Info, message, args);
}
[MessageTemplateFormatMethod("message")]
public static void ProgressDebug(this Logger logger, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
LogProgressMessage(logger, LogLevel.Debug, formattedMessage);
LogProgressMessage(logger, LogLevel.Debug, message, args);
}
[MessageTemplateFormatMethod("message")]
public static void ProgressTrace(this Logger logger, string message, params object[] args)
{
var formattedMessage = string.Format(message, args);
LogProgressMessage(logger, LogLevel.Trace, formattedMessage);
LogProgressMessage(logger, LogLevel.Trace, message, args);
}
private static void LogProgressMessage(Logger logger, LogLevel level, string message)
private static void LogProgressMessage(Logger logger, LogLevel level, string message, object[] parameters)
{
var logEvent = new LogEventInfo(level, logger.Name, message);
var logEvent = new LogEventInfo(level, logger.Name, null, message, parameters);
logEvent.Properties.Add("Status", "");
logger.Log(logEvent);

View File

@@ -3,7 +3,6 @@ using System.Diagnostics;
using System.IO;
using NLog;
using NLog.Config;
using NLog.Layouts.ClefJsonLayout;
using NLog.Targets;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -13,9 +12,11 @@ namespace NzbDrone.Common.Instrumentation
{
public static class NzbDroneLogger
{
private const string FILE_LOG_LAYOUT = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
public const string ConsoleLogLayout = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
public static CompactJsonLayout ClefLogLayout = new CompactJsonLayout();
private const string FileLogLayout = @"${date:format=yyyy-MM-dd HH\:mm\:ss.f}|${level}|${logger}|${message}${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private const string ConsoleFormat = "[${level}] ${logger}: ${message} ${onexception:inner=${newline}${newline}[v${assembly-version}] ${exception:format=ToString}${newline}${exception:format=Data}${newline}}";
private static readonly CleansingConsoleLogLayout CleansingConsoleLayout = new (ConsoleFormat);
private static readonly CleansingClefLogLayout ClefLogLayout = new ();
private static bool _isConfigured;
@@ -119,11 +120,7 @@ namespace NzbDrone.Common.Instrumentation
? formatEnumValue
: ConsoleLogFormat.Standard;
coloredConsoleTarget.Layout = logFormat switch
{
ConsoleLogFormat.Clef => ClefLogLayout,
_ => ConsoleLogLayout
};
ConfigureConsoleLayout(coloredConsoleTarget, logFormat);
var loggingRule = new LoggingRule("*", level, coloredConsoleTarget);
@@ -140,7 +137,7 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)
{
var fileTarget = new NzbDroneFileTarget();
var fileTarget = new CleansingFileTarget();
fileTarget.Name = name;
fileTarget.FileName = Path.Combine(appFolderInfo.GetLogFolder(), fileName);
@@ -153,7 +150,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.MaxArchiveFiles = maxArchiveFiles;
fileTarget.EnableFileDelete = true;
fileTarget.ArchiveNumbering = ArchiveNumberingMode.Rolling;
fileTarget.Layout = FILE_LOG_LAYOUT;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", minLogLevel, fileTarget);
@@ -172,7 +169,7 @@ namespace NzbDrone.Common.Instrumentation
fileTarget.ConcurrentWrites = false;
fileTarget.ConcurrentWriteAttemptDelay = 50;
fileTarget.ConcurrentWriteAttempts = 100;
fileTarget.Layout = FILE_LOG_LAYOUT;
fileTarget.Layout = FileLogLayout;
var loggingRule = new LoggingRule("*", LogLevel.Trace, fileTarget);
@@ -217,6 +214,15 @@ namespace NzbDrone.Common.Instrumentation
{
return GetLogger(obj.GetType());
}
public static void ConfigureConsoleLayout(ColoredConsoleTarget target, ConsoleLogFormat format)
{
target.Layout = format switch
{
ConsoleLogFormat.Clef => NzbDroneLogger.ClefLogLayout,
_ => NzbDroneLogger.CleansingConsoleLayout
};
}
}
public enum ConsoleLogFormat

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,6 +6,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Model;
@@ -117,7 +118,9 @@ namespace NzbDrone.Common.Processes
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true
RedirectStandardInput = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
if (environmentVariables != null)

View File

@@ -5,20 +5,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
<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="IPAddressRange" Version="6.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.2" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.3" />
<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.9" />
<PackageReference Include="NLog" Version="5.4.0" />
<PackageReference Include="NLog.Layouts.ClefJsonLayout" Version="1.0.3" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.4.0" />
<PackageReference Include="Npgsql" Version="7.0.10" />
<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.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Text.Json" Version="6.0.11" />
<PackageReference Include="System.ValueTuple" Version="4.6.1" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.2" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.1" />

File diff suppressed because one or more lines are too long

View File

@@ -122,7 +122,7 @@ namespace NzbDrone.Core.Test.IndexerTests.AnimeBytesTests
var fifthTorrentInfo = releases.ElementAt(28) as TorrentInfo;
fifthTorrentInfo.Title.Should().Be("[-ZR-] Dr. STONE: STONE WARS S02 [Web][MKV][h264][1080p][AAC 2.0][Dual Audio][Softsubs (-ZR-)]");
fifthTorrentInfo.Title.Should().Be("[-ZR-] Dr. STONE: STONE WARS 2021 S02 [Web][MKV][h264][1080p][AAC 2.0][Dual Audio][Softsubs (-ZR-)]");
fifthTorrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
fifthTorrentInfo.DownloadUrl.Should().Be("https://animebytes.tv/torrent/944509/download/somepass");
fifthTorrentInfo.InfoUrl.Should().Be("https://animebytes.tv/torrent/944509/group");

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 20:20:19"));
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2020-01-25 19:20:19"));
torrentInfo.Size.Should().Be(8300512414);
torrentInfo.InfoHash.Should().Be(null);
torrentInfo.MagnetUrl.Should().Be(null);

View File

@@ -26,15 +26,15 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
Subject.Definition = new IndexerDefinition
{
Name = "HdBits",
Settings = new HDBitsSettings() { ApiKey = "fakekey" }
Settings = new HDBitsSettings { ApiKey = "fakekey" }
};
_movieSearchCriteria = new MovieSearchCriteria
{
Categories = new int[] { 2000, 2010 },
Categories = new[] { 2000, 2010 },
ImdbId = "0076759"
};
}
@@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
var torrents = (await Subject.Fetch(_movieSearchCriteria)).Releases;
torrents.Should().HaveCount(2);
torrents.First().Should().BeOfType<HDBitsInfo>();
torrents.First().Should().BeOfType<TorrentInfo>();
var first = torrents.First() as TorrentInfo;

View File

@@ -50,7 +50,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
first.Guid.Should().Be("PassThePopcorn-452135");
first.Title.Should().Be("The.Night.Of.S01.BluRay.AAC2.0.x264-DEPTH");
first.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000");
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135");
first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135");
//first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones

View File

@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Lidarr
{
var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.MusicSearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing music search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
_logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return;
}
@@ -178,7 +185,7 @@ namespace NzbDrone.Core.Applications.Lidarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.MusicSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
lidarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => lidarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -204,7 +211,7 @@ namespace NzbDrone.Core.Applications.Lidarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.MusicSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Lidarr", indexer.Name, indexer.Id);
lidarrIndexer.Id = 0;

View File

@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Radarr
{
var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.MovieSearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing movie search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
_logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return;
}
@@ -176,7 +183,7 @@ namespace NzbDrone.Core.Applications.Radarr
if (!radarrIndexer.Equals(remoteIndexer) || forceSync)
{
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.MovieSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
radarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => radarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -202,7 +209,7 @@ namespace NzbDrone.Core.Applications.Radarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.MovieSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Radarr", indexer.Name, indexer.Id);
radarrIndexer.Id = 0;

View File

@@ -121,9 +121,16 @@ namespace NzbDrone.Core.Applications.Readarr
{
var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.BookSearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing book search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
_logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return;
}
@@ -178,7 +185,7 @@ namespace NzbDrone.Core.Applications.Readarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.BookSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
// Retain user fields not-affiliated with Prowlarr
readarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => readarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -204,7 +211,7 @@ namespace NzbDrone.Core.Applications.Readarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
if (indexerCapabilities.BookSearchAvailable && indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any())
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Readarr", indexer.Name, indexer.Id);
readarrIndexer.Id = 0;

View File

@@ -125,10 +125,17 @@ namespace NzbDrone.Core.Applications.Sonarr
{
var indexerCapabilities = GetIndexerCapabilities(indexer);
if (!indexerCapabilities.TvSearchAvailable)
{
_logger.Debug("Skipping add for indexer {0} [{1}] due to missing TV search support by the indexer", indexer.Name, indexer.Id);
return;
}
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Empty() &&
indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Empty())
{
_logger.Trace("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
_logger.Debug("Skipping add for indexer {0} [{1}] due to no app Sync Categories supported by the indexer", indexer.Name, indexer.Id);
return;
}
@@ -183,7 +190,7 @@ namespace NzbDrone.Core.Applications.Sonarr
{
_logger.Debug("Syncing remote indexer with current settings");
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
if (indexerCapabilities.TvSearchAvailable && (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()))
{
// Retain user fields not-affiliated with Prowlarr
sonarrIndexer.Fields.AddRange(remoteIndexer.Fields.Where(f => sonarrIndexer.Fields.All(s => s.Name != f.Name)));
@@ -210,7 +217,7 @@ namespace NzbDrone.Core.Applications.Sonarr
{
_appIndexerMapService.Delete(indexerMapping.Id);
if (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any())
if (indexerCapabilities.TvSearchAvailable && (indexerCapabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()).Any() || indexerCapabilities.Categories.SupportedCategories(Settings.AnimeSyncCategories.ToArray()).Any()))
{
_logger.Debug("Remote indexer not found, re-adding {0} [{1}] to Sonarr", indexer.Name, indexer.Id);
sonarrIndexer.Id = 0;

View File

@@ -66,12 +66,19 @@ namespace NzbDrone.Core.Backup
{
_logger.ProgressInfo("Starting Backup");
var backupFolder = GetBackupFolder(backupType);
_diskProvider.EnsureFolder(_backupTempFolder);
_diskProvider.EnsureFolder(GetBackupFolder(backupType));
_diskProvider.EnsureFolder(backupFolder);
if (!_diskProvider.FolderWritable(backupFolder))
{
throw new UnauthorizedAccessException($"Backup folder {backupFolder} is not writable");
}
var dateNow = DateTime.Now;
var backupFilename = $"prowlarr_backup_v{BuildInfo.Version}_{dateNow:yyyy.MM.dd_HH.mm.ss}.zip";
var backupPath = Path.Combine(GetBackupFolder(backupType), backupFilename);
var backupPath = Path.Combine(backupFolder, backupFilename);
Cleanup();

View File

@@ -274,7 +274,7 @@ namespace NzbDrone.Core.Configuration
{
var instanceName = _appOptions.InstanceName ?? GetValue("InstanceName", BuildInfo.AppName);
if (instanceName.ContainsIgnoreCase(BuildInfo.AppName))
if (instanceName.Contains(BuildInfo.AppName, StringComparison.OrdinalIgnoreCase))
{
return instanceName;
}

View File

@@ -254,7 +254,7 @@ namespace NzbDrone.Core.Datastore
protected void Delete(SqlBuilder builder)
{
var sql = builder.AddDeleteTemplate(typeof(TModel)).LogQuery();
var sql = builder.AddDeleteTemplate(typeof(TModel));
using (var conn = _database.OpenConnection())
{

View File

@@ -0,0 +1,60 @@
using System.Collections.Generic;
using System.Data;
using Dapper;
using FluentMigrator;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(042)]
public class myanonamouse_freeleech_wedge_options : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(MigrateIndexersToWedgeOptions);
}
private void MigrateIndexersToWedgeOptions(IDbConnection conn, IDbTransaction tran)
{
var updated = new List<object>();
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT \"Id\", \"Settings\" FROM \"Indexers\" WHERE \"Implementation\" = 'MyAnonamouse'";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var settings = Json.Deserialize<JObject>(reader.GetString(1));
if (settings.ContainsKey("freeleech") && settings.Value<JToken>("freeleech").Type == JTokenType.Boolean)
{
var optionValue = settings.Value<bool>("freeleech") switch
{
true => 2, // Required
_ => 0 // Never
};
settings.Remove("freeleech");
settings.Add("useFreeleechWedge", optionValue);
}
updated.Add(new
{
Id = id,
Settings = settings.ToJson()
});
}
}
}
var updateSql = "UPDATE \"Indexers\" SET \"Settings\" = @Settings WHERE \"Id\" = @Id";
conn.Execute(updateSql, updated, transaction: tran);
}
}
}

View File

@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -25,8 +26,9 @@ namespace NzbDrone.Core.Download.Clients.Aria2
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
}

View File

@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole
@@ -16,8 +17,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
public UsenetBlackhole(IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, configService, diskProvider, logger)
: base(httpClient, configService, diskProvider, localizationService, logger)
{
}

View File

@@ -9,6 +9,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -23,8 +24,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -33,8 +34,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector;

View File

@@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -31,8 +32,9 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, configService, diskProvider, logger)
: base(httpClient, configService, diskProvider, localizationService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxySelector = dsTaskProxySelector;

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Flood.Models;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
@@ -22,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.Flood
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.FreeboxDownload
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.Download.Clients.FreeboxDownload
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Hadouken
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -7,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, configService, diskProvider, logger)
: base(httpClient, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -10,6 +10,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -18,15 +19,14 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public class Nzbget : UsenetClientBase<NzbgetSettings>
{
private readonly INzbgetProxy _proxy;
private readonly string[] _successStatus = { "SUCCESS", "NONE" };
private readonly string[] _deleteFailedStatus = { "HEALTH", "DUPE", "SCAN", "COPY", "BAD" };
public Nzbget(INzbgetProxy proxy,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, configService, diskProvider, logger)
: base(httpClient, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -17,8 +18,9 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic
{
public Pneumatic(IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(configService, diskProvider, logger)
: base(configService, diskProvider, localizationService, logger)
{
}

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -30,8 +31,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
IConfigService configService,
IDiskProvider diskProvider,
ICacheManager cacheManager,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxySelector = proxySelector;

View File

@@ -9,6 +9,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -22,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(httpClient, configService, diskProvider, logger)
: base(httpClient, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -5,6 +5,7 @@ using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Download.Clients.Transmission
{
@@ -15,8 +16,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
}

View File

@@ -6,6 +6,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
@@ -20,8 +21,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}

View File

@@ -4,6 +4,7 @@ using System.Net;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
@@ -208,7 +209,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
private void AuthenticateClient(HttpRequestBuilder requestBuilder, TransmissionSettings settings, bool reauthenticate = false)
{
var authKey = string.Format("{0}:{1}", requestBuilder.BaseUrl, settings.Password);
var authKey = $"{requestBuilder.BaseUrl}:{settings.Password}";
var sessionId = _authSessionIDCache.Find(authKey);
@@ -220,24 +221,26 @@ namespace NzbDrone.Core.Download.Clients.Transmission
authLoginRequest.SuppressHttpError = true;
var response = _httpClient.Execute(authLoginRequest);
if (response.StatusCode == HttpStatusCode.MovedPermanently)
{
var url = response.Headers.GetSingleValue("Location");
throw new DownloadClientException("Remote site redirected to " + url);
}
else if (response.StatusCode == HttpStatusCode.Conflict)
switch (response.StatusCode)
{
sessionId = response.Headers.GetSingleValue("X-Transmission-Session-Id");
case HttpStatusCode.MovedPermanently:
var url = response.Headers.GetSingleValue("Location");
if (sessionId == null)
{
throw new DownloadClientException("Remote host did not return a Session Id.");
}
}
else
{
throw new DownloadClientAuthenticationException("Failed to authenticate with Transmission.");
throw new DownloadClientException("Remote site redirected to " + url);
case HttpStatusCode.Forbidden:
throw new DownloadClientException($"Failed to authenticate with Transmission. It may be necessary to add {BuildInfo.AppName}'s IP address to RPC whitelist.");
case HttpStatusCode.Conflict:
sessionId = response.Headers.GetSingleValue("X-Transmission-Session-Id");
if (sessionId == null)
{
throw new DownloadClientException("Remote host did not return a Session Id.");
}
break;
default:
throw new DownloadClientAuthenticationException("Failed to authenticate with Transmission.");
}
_logger.Debug("Transmission authentication succeeded.");

View File

@@ -4,6 +4,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Transmission;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
namespace NzbDrone.Core.Download.Clients.Vuze
{
@@ -16,8 +17,9 @@ namespace NzbDrone.Core.Download.Clients.Vuze
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(proxy, torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
}

View File

@@ -10,6 +10,7 @@ using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.rTorrent;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -27,8 +28,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
IConfigService configService,
IDiskProvider diskProvider,
IRTorrentDirectoryValidator rTorrentDirectoryValidator,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;

View File

@@ -7,7 +7,9 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Download.Clients.UTorrent
@@ -21,8 +23,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, logger)
: base(torrentFileInfoReader, seedConfigProvider, configService, diskProvider, localizationService, logger)
{
_proxy = proxy;
}
@@ -72,6 +75,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
}
public override string Name => "uTorrent";
public override ProviderMessage Message => new (_localizationService.GetLocalizedString("DownloadClientUTorrentProviderMessage"), ProviderMessageType.Warning);
public override bool SupportsCategories => true;
protected override void Test(List<ValidationFailure> failures)

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -19,6 +20,7 @@ namespace NzbDrone.Core.Download
{
protected readonly IConfigService _configService;
protected readonly IDiskProvider _diskProvider;
protected readonly ILocalizationService _localizationService;
protected readonly Logger _logger;
public abstract string Name { get; }
@@ -40,10 +42,12 @@ namespace NzbDrone.Core.Download
protected DownloadClientBase(IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
{
_configService = configService;
_diskProvider = diskProvider;
_localizationService = localizationService;
_logger = logger;
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Linq;
using System.Xml;
@@ -15,39 +16,53 @@ namespace NzbDrone.Core.Download
{
public void Validate(byte[] fileContent)
{
var reader = new StreamReader(new MemoryStream(fileContent));
using (var xmlTextReader = XmlReader.Create(reader, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
try
{
var xDoc = XDocument.Load(xmlTextReader);
var nzb = xDoc.Root;
var reader = new StreamReader(new MemoryStream(fileContent));
if (nzb == null)
using (var xmlTextReader = XmlReader.Create(reader,
new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
{
throw new InvalidNzbException("Invalid NZB: No Root element");
}
var xDoc = XDocument.Load(xmlTextReader);
var nzb = xDoc.Root;
// nZEDb has an bug in their error reporting code spitting out invalid http status codes
if (nzb.Name.LocalName.Equals("error") &&
nzb.TryGetAttributeValue("code", out var code) &&
nzb.TryGetAttributeValue("description", out var description))
{
throw new InvalidNzbException("Invalid NZB: Contains indexer error: {0} - {1}", code, description);
}
if (nzb == null)
{
throw new InvalidNzbException("Invalid NZB: No Root element");
}
if (!nzb.Name.LocalName.Equals("nzb"))
{
throw new InvalidNzbException("Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}'", nzb.Name.LocalName);
}
// nZEDb has a bug in their error reporting code spitting out invalid http status codes
if (nzb.Name.LocalName.Equals("error") &&
nzb.TryGetAttributeValue("code", out var code) &&
nzb.TryGetAttributeValue("description", out var description))
{
throw new InvalidNzbException("Invalid NZB: Contains indexer error: {0} - {1}", code, description);
}
var ns = nzb.Name.Namespace;
var files = nzb.Elements(ns + "file").ToList();
if (!nzb.Name.LocalName.Equals("nzb"))
{
throw new InvalidNzbException(
"Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}'", nzb.Name.LocalName);
}
if (files.Empty())
{
throw new InvalidNzbException("Invalid NZB: No files");
var ns = nzb.Name.Namespace;
var files = nzb.Elements(ns + "file").ToList();
if (files.Empty())
{
throw new InvalidNzbException("Invalid NZB: No files");
}
}
}
catch (InvalidNzbException)
{
// Throw the original exception
throw;
}
catch (Exception ex)
{
throw new InvalidNzbException("Invalid NZB: Unable to parse", ex);
}
}
}
}

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
@@ -24,8 +25,9 @@ namespace NzbDrone.Core.Download
ISeedConfigProvider seedConfigProvider,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(configService, diskProvider, logger)
: base(configService, diskProvider, localizationService, logger)
{
_torrentFileInfoReader = torrentFileInfoReader;
_seedConfigProvider = seedConfigProvider;

View File

@@ -5,6 +5,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.ThingiProvider;
@@ -19,8 +20,9 @@ namespace NzbDrone.Core.Download
protected UsenetClientBase(IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
ILocalizationService localizationService,
Logger logger)
: base(configService, diskProvider, logger)
: base(configService, diskProvider, localizationService, logger)
{
_httpClient = httpClient;
}

View File

@@ -224,7 +224,7 @@ namespace NzbDrone.Core.History
if (message.Release.PublishDate != DateTime.MinValue)
{
history.Data.Add("PublishedDate", message.Release.PublishDate.ToString("s") + "Z");
history.Data.Add("PublishedDate", message.Release.PublishDate.ToUniversalTime().ToString("s") + "Z");
}
_historyRepository.Insert(history);

View File

@@ -232,7 +232,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (queryCats.Any() && searchCriteria is TvSearchCriteria { Season: > 0 })
{
// Avoid searching for specials if it's a non-zero season search
queryCats.RemoveAll(cat => cat is "anime[tv_special]" or "anime[ova]" or "anime[ona]" or "anime[dvd_special]" or "anime[bd_special]");
queryCats.RemoveAll(cat => cat is "anime[tv_special]" or "anime[ova]" or "anime[dvd_special]" or "anime[bd_special]");
}
if (queryCats.Any())
@@ -301,6 +301,8 @@ namespace NzbDrone.Core.Indexers.Definitions
};
private static readonly HashSet<string> ExcludedFileExtensions = new (StringComparer.OrdinalIgnoreCase) { ".mka", ".mds", ".md5", ".nfo", ".sfv", ".ass", ".mks", ".srt", ".ssa", ".sup", ".jpeg", ".jpg", ".png", ".otf", ".ttf" };
private static readonly string[] PropertiesSeparator = { " | ", " / " };
private readonly AnimeBytesSettings _settings;
public AnimeBytesParser(AnimeBytesSettings settings)
@@ -324,6 +326,11 @@ namespace NzbDrone.Core.Indexers.Definitions
var response = STJson.Deserialize<AnimeBytesResponse>(indexerResponse.Content);
if (response.Error.IsNotNullOrWhiteSpace())
{
throw new IndexerException(indexerResponse, "Unexpected response from indexer request: {0}", response.Error);
}
if (response.Matches == 0)
{
return releaseInfos.ToArray();
@@ -393,38 +400,48 @@ namespace NzbDrone.Core.Indexers.Definitions
var minimumSeedTime = 259200 + (int)(size / (int)Math.Pow(1024, 3) * 18000);
var propertyList = WebUtility.HtmlDecode(torrent.Property)
.Split(new[] { " | ", " / " }, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Split(PropertiesSeparator, StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.ToList();
propertyList.RemoveAll(p => ExcludedProperties.Any(p.ContainsIgnoreCase));
var properties = propertyList.ToHashSet();
if (torrent.Files.Any(f => f.FileName.ContainsIgnoreCase("Remux")))
{
var resolutionProperty = properties.FirstOrDefault(RemuxResolutions.ContainsIgnoreCase);
if (resolutionProperty.IsNotNullOrWhiteSpace())
{
properties.Add($"{resolutionProperty} Remux");
}
}
if (properties.Any(p => p.StartsWithIgnoreCase("M2TS")))
if (properties.Any(p => p.StartsWith("M2TS", StringComparison.Ordinal)))
{
properties.Add("BR-DISK");
}
if (_settings.ExcludeRaw &&
properties.Any(p => p.StartsWithIgnoreCase("RAW") || p.Contains("BR-DISK")))
var isBluRayDisk = properties.Any(p => p.Equals("RAW", StringComparison.Ordinal) || p.StartsWith("M2TS", StringComparison.Ordinal) || p.StartsWith("ISO", StringComparison.Ordinal));
if (_settings.ExcludeRaw && isBluRayDisk)
{
continue;
}
properties = properties
.Select(property =>
{
if (isBluRayDisk)
{
property = Regex.Replace(property, @"\b(H\.?265)\b", "HEVC", RegexOptions.Compiled | RegexOptions.IgnoreCase);
property = Regex.Replace(property, @"\b(H\.?264)\b", "AVC", RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
if (torrent.Files.Any(f => f.FileName.ContainsIgnoreCase("Remux"))
&& RemuxResolutions.ContainsIgnoreCase(property))
{
property += " Remux";
}
return property;
})
.ToHashSet();
int? season = null;
int? episode = null;
var releaseInfo = _settings.EnableSonarrCompatibility && categoryName == "Anime" ? "S01" : "";
var editionTitle = torrent.EditionData.EditionTitle;
var editionTitle = torrent.EditionData?.EditionTitle;
if (editionTitle.IsNotNullOrWhiteSpace())
{
@@ -569,7 +586,7 @@ namespace NzbDrone.Core.Indexers.Definitions
if (_settings.UseFilenameForSingleEpisodes)
{
var files = torrent.Files;
var files = torrent.Files.ToList();
if (files.Count > 1)
{
@@ -607,11 +624,13 @@ namespace NzbDrone.Core.Indexers.Definitions
}
}
var useYearInTitle = year is > 0 && torrent.Files.Any(f => f.FileName.Contains(year.Value.ToString()));
foreach (var title in synonyms)
{
var releaseTitle = groupName is "Movie" or "Live Action Movie" ?
$"{releaseGroup}{title} {year} {infoString}" :
$"{releaseGroup}{title} {releaseInfo} {infoString}";
$"{releaseGroup}{title}{(useYearInTitle ? $" {year}" : string.Empty)} {releaseInfo} {infoString}";
var guid = new Uri(details + "?nh=" + HashUtil.CalculateMd5(title));
@@ -650,7 +669,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var advancedSeasonRegex = new Regex(@"\b(?:(?<season>\d+)(?:st|nd|rd|th) Season|Season (?<season>\d+))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var seasonCharactersRegex = new Regex(@"(I{2,})$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?<!Part[- ._])(?:S)?(?<season>[2-9])$", RegexOptions.Compiled);
var seasonNumberRegex = new Regex(@"\b(?<!Part[- ._])(?<!\d[/])(?:S)?(?<season>[2-9])$", RegexOptions.Compiled);
foreach (var title in titles)
{
@@ -755,7 +774,9 @@ namespace NzbDrone.Core.Indexers.Definitions
public int Matches { get; set; }
[JsonPropertyName("Groups")]
public AnimeBytesGroup[] Groups { get; set; }
public IReadOnlyCollection<AnimeBytesGroup> Groups { get; set; }
public string Error { get; set; }
}
public class AnimeBytesGroup
@@ -783,16 +804,16 @@ namespace NzbDrone.Core.Indexers.Definitions
public string Image { get; set; }
[JsonPropertyName("SynonymnsV2")]
public Dictionary<string, string> Synonymns { get; set; }
public IReadOnlyDictionary<string, string> Synonymns { get; set; }
[JsonPropertyName("Description")]
public string Description { get; set; }
[JsonPropertyName("Tags")]
public List<string> Tags { get; set; }
public IReadOnlyCollection<string> Tags { get; set; }
[JsonPropertyName("Torrents")]
public List<AnimeBytesTorrent> Torrents { get; set; }
public IReadOnlyCollection<AnimeBytesTorrent> Torrents { get; set; }
}
public class AnimeBytesTorrent
@@ -831,7 +852,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public int FileCount { get; set; }
[JsonPropertyName("FileList")]
public List<AnimeBytesFile> Files { get; set; }
public IReadOnlyCollection<AnimeBytesFile> Files { get; set; }
[JsonPropertyName("UploadTime")]
public string UploadTime { get; set; }

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AngleSharp.Html.Parser;
using NLog;
using NzbDrone.Common.Extensions;
@@ -44,46 +43,19 @@ namespace NzbDrone.Core.Indexers.Definitions
return new AnimeTorrentsParser(Settings, Capabilities.Categories);
}
protected override async Task DoLogin()
{
UpdateCookies(null, null);
var loginUrl = Settings.BaseUrl + "login.php";
var loginPage = await ExecuteAuth(new HttpRequest(loginUrl));
var requestBuilder = new HttpRequestBuilder(loginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true
};
var authLoginRequest = requestBuilder
.Post()
.SetCookies(loginPage.GetCookies())
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.AddFormParameter("form", "login")
.AddFormParameter("rememberme[]", "1")
.SetHeader("Content-Type", "application/x-www-form-urlencoded")
.SetHeader("Referer", loginUrl)
.Build();
var response = await ExecuteAuth(authLoginRequest);
if (response.Content == null || !response.Content.Contains("logout.php"))
{
throw new IndexerAuthException("AnimeTorrents authentication failed");
}
UpdateCookies(response.GetCookies(), DateTime.Now.AddDays(30));
_logger.Debug("AnimeTorrents authentication succeeded");
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return httpResponse.Content.Contains("Access Denied!") || httpResponse.Content.Contains("login.php");
if (httpResponse.Content.Contains("Access Denied!") || httpResponse.Content.Contains("login.php"))
{
throw new IndexerAuthException("AnimeTorrents authentication with cookies failed.");
}
return false;
}
protected override IDictionary<string, string> GetCookies()
{
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
}
private IndexerCapabilities SetCapabilities()
@@ -119,6 +91,7 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.BooksComics, "Doujinshi");
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.BooksComics, "Doujinshi 18+");
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.Audio, "OST");
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
return caps;
}
@@ -291,7 +264,7 @@ namespace NzbDrone.Core.Indexers.Definitions
var qTitleLink = row.QuerySelector("td:nth-of-type(2) a:nth-of-type(1)");
var title = qTitleLink?.TextContent.Trim();
// If we search an get no results, we still get a table just with no info.
// If we search and get no results, we still get a table just with no info.
if (title.IsNullOrWhiteSpace())
{
break;
@@ -306,6 +279,8 @@ namespace NzbDrone.Core.Indexers.Definitions
var connections = row.QuerySelector("td:nth-of-type(8)").TextContent.Trim().Split('/', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
var seeders = ParseUtil.CoerceInt(connections[0]);
var leechers = ParseUtil.CoerceInt(connections[1]);
var grabs = ParseUtil.CoerceInt(connections[2]);
var categoryLink = row.QuerySelector("td:nth-of-type(1) a")?.GetAttribute("href") ?? string.Empty;
var categoryId = ParseUtil.GetArgumentFromQueryString(categoryLink, "cat");
@@ -327,17 +302,17 @@ namespace NzbDrone.Core.Indexers.Definitions
PublishDate = publishedDate,
Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(6)").TextContent.Trim()),
Seeders = seeders,
Peers = ParseUtil.CoerceInt(connections[1]) + seeders,
Grabs = ParseUtil.CoerceInt(connections[2]),
Peers = leechers + seeders,
Grabs = grabs,
DownloadVolumeFactor = downloadVolumeFactor,
UploadVolumeFactor = 1,
Genres = row.QuerySelectorAll("td:nth-of-type(2) a.tortags").Select(t => t.TextContent.Trim()).ToList()
};
var uLFactorImg = row.QuerySelector("img[alt*=\"x Multiplier Torrent\"]");
if (uLFactorImg != null)
var uploadFactor = row.QuerySelector("img[alt*=\"x Multiplier Torrent\"]")?.GetAttribute("alt");
if (uploadFactor != null)
{
release.UploadVolumeFactor = ParseUtil.CoerceDouble(uLFactorImg.GetAttribute("alt").Split('x')[0]);
release.UploadVolumeFactor = ParseUtil.CoerceDouble(uploadFactor.Split('x')[0]);
}
releaseInfos.Add(release);
@@ -349,7 +324,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
public class AnimeTorrentsSettings : UserPassTorrentBaseSettings
public class AnimeTorrentsSettings : CookieTorrentBaseSettings
{
public AnimeTorrentsSettings()
{
@@ -360,7 +335,7 @@ namespace NzbDrone.Core.Indexers.Definitions
[FieldDefinition(4, Label = "Freeleech Only", Type = FieldType.Checkbox, HelpText = "Show freeleech torrents only")]
public bool FreeleechOnly { get; set; }
[FieldDefinition(5, Label = "Downloadable Only", Type = FieldType.Checkbox, HelpText = "Search downloadable torrents only (enable this only if your account class is Newbie)")]
[FieldDefinition(5, Label = "Downloadable Only", Type = FieldType.Checkbox, HelpText = "Search downloadable torrents only (enable this only if your account class is Newbie)", Advanced = true)]
public bool DownloadableOnly { get; set; }
}
}

View File

@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
private IndexerCapabilities SetCapabilities()
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
@@ -69,7 +69,8 @@ namespace NzbDrone.Core.Indexers.Definitions
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal
IndexerFlag.Internal,
IndexerFlag.Exclusive,
}
};
@@ -91,7 +92,7 @@ namespace NzbDrone.Core.Indexers.Definitions
_capabilities = capabilities;
}
private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria, string term, string imdbId = null, int tmdbId = 0)
private IEnumerable<IndexerRequest> GetPagedRequests(SearchCriteriaBase searchCriteria, string searchTerm, string imdbId = null, int tmdbId = 0)
{
var body = new Dictionary<string, object>
{
@@ -128,9 +129,9 @@ namespace NzbDrone.Core.Indexers.Definitions
body.Add("tmdb_id", tmdbId);
}
if (term.IsNotNullOrWhiteSpace())
if (searchTerm.IsNotNullOrWhiteSpace())
{
body.Add("search", term);
body.Add("search", searchTerm.Trim());
}
var cats = _capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
@@ -198,7 +199,16 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetPagedRequests(searchCriteria, searchCriteria.SanitizedTvSearchString, searchCriteria.FullImdbId));
var searchTerm = searchCriteria.SanitizedTvSearchString;
if (searchCriteria.Season is > 0 &&
searchCriteria.Episode.IsNotNullOrWhiteSpace() &&
DateTime.TryParseExact($"{searchCriteria.Season} {searchCriteria.Episode}", "yyyy MM/dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var showDate))
{
searchTerm = $"{searchCriteria.SanitizedSearchTerm} {showDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)}";
}
pageableRequests.Add(GetPagedRequests(searchCriteria, searchTerm, searchCriteria.FullImdbId));
return pageableRequests;
}
@@ -245,6 +255,11 @@ namespace NzbDrone.Core.Indexers.Definitions
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerHttpResponse.StatusCode} code from indexer request");
}
if (indexerHttpResponse.Headers.ContentType.Contains("text/html"))
{
throw new IndexerException(indexerResponse, $"Indexer responded with HTML content. {(indexerHttpResponse.Content.ContainsIgnoreCase("site maintenance") ? "Site is under maintenance." : "Site is likely blocked or unavailable.")}");
}
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}");
@@ -275,13 +290,6 @@ namespace NzbDrone.Core.Indexers.Definitions
var details = row.InfoUrl;
var link = row.DownloadLink;
var flags = new HashSet<IndexerFlag>();
if (row.Internal)
{
flags.Add(IndexerFlag.Internal);
}
var release = new TorrentInfo
{
Title = row.Name,
@@ -291,7 +299,7 @@ namespace NzbDrone.Core.Indexers.Definitions
Guid = details,
Categories = _categories.MapTrackerCatDescToNewznab(row.Category),
PublishDate = DateTime.Parse(row.CreatedAt, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal),
IndexerFlags = flags,
IndexerFlags = GetIndexerFlags(row),
Size = row.Size,
Grabs = row.Grabs,
Seeders = row.Seeders,
@@ -301,6 +309,8 @@ namespace NzbDrone.Core.Indexers.Definitions
UploadVolumeFactor = 1,
MinimumRatio = 1,
MinimumSeedTime = 172800, // 120 hours
Languages = row.Audios?.Split(",", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
Subs = row.Subtitles?.Split(",", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList() ?? new List<string>(),
};
// BHD can return crazy values for tmdb
@@ -319,6 +329,23 @@ namespace NzbDrone.Core.Indexers.Definitions
.ToArray();
}
private static HashSet<IndexerFlag> GetIndexerFlags(BeyondHDTorrent item)
{
var flags = new HashSet<IndexerFlag>();
if (item.Internal)
{
flags.Add(IndexerFlag.Internal);
}
if (item.Exclusive)
{
flags.Add(IndexerFlag.Exclusive);
}
return flags;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
@@ -450,9 +477,13 @@ namespace NzbDrone.Core.Indexers.Definitions
[JsonPropertyName("times_completed")]
public int Grabs { get; set; }
public int Seeders { get; set; }
public int Leechers { get; set; }
public string Audios { get; set; }
public string Subtitles { get; set; }
[JsonPropertyName("created_at")]
public string CreatedAt { get; set; }
@@ -478,6 +509,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public bool Limited { get; set; }
public bool Exclusive { get; set; }
public bool Internal { get; set; }
}
}

View File

@@ -88,7 +88,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
Guid = $"BTN-{torrent.TorrentID}",
InfoUrl = $"{protocol}//broadcasthe.net/torrents.php?id={torrent.GroupID}&torrentid={torrent.TorrentID}",
DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol),
Title = CleanReleaseName(torrent.ReleaseName),
Title = GetTitle(torrent),
Categories = _categories.MapTrackerCatToNewznab(torrent.Resolution),
InfoHash = torrent.InfoHash,
Size = torrent.Size,
@@ -136,9 +136,17 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
return releaseInfos;
}
private string CleanReleaseName(string releaseName)
private static string GetTitle(BroadcastheNetTorrent torrent)
{
return releaseName.Replace("\\", "");
var releaseName = torrent.ReleaseName.Replace("\\", "");
if (torrent.Container.ToUpperInvariant() is "M2TS" or "ISO")
{
releaseName = Regex.Replace(releaseName, @"\b(H\.?265)\b", "HEVC", RegexOptions.Compiled);
releaseName = Regex.Replace(releaseName, @"\b(H\.?264)\b", "AVC", RegexOptions.Compiled);
}
return releaseName;
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Text;
using System.Text.RegularExpressions;
using AngleSharp.Dom;
using Microsoft.AspNetCore.WebUtilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Extensions;
@@ -214,19 +215,21 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
if (selector.Selector != null)
{
var selectorSelector = ApplyGoTemplateText(selector.Selector.TrimStart('.'), variables);
selectorSelector = JsonParseFieldSelector(parentObj, selectorSelector);
var fieldSelector = JsonParseFieldSelector(parentObj, selectorSelector);
JToken selection = null;
if (selectorSelector != null)
if (fieldSelector != null)
{
selection = parentObj.SelectToken(selectorSelector);
selection = parentObj.SelectToken(fieldSelector);
}
if (selection == null)
{
if (required)
{
throw new Exception(string.Format("Selector \"{0}\" didn't match {1}", selectorSelector, parentObj.ToString()));
var jsonContent = parentObj.ToString(Formatting.None);
throw new Exception($"Selector \"{selectorSelector}\" didn't match JSON content").WithData("JsonContent", jsonContent[..Math.Min(jsonContent.Length, 5 * 1024)]);
}
return null;
@@ -234,7 +237,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
if (selection.Type is JTokenType.Array)
{
// turn this json array into a comma delimited string
// turn this json array into a comma-delimited string
var valueArray = selection.Value<JArray>();
value = string.Join(",", valueArray);
}
@@ -259,7 +262,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
{
if (required)
{
throw new Exception($"None of the case selectors \"{string.Join(",", selector.Case)}\" matched {parentObj}");
var jsonContent = parentObj.ToString(Formatting.None);
throw new Exception($"None of the case selectors \"{string.Join(",", selector.Case)}\" matched JSON content").WithData("JsonContent", jsonContent[..Math.Min(jsonContent.Length, 5 * 1024)]);
}
return null;
@@ -738,7 +743,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
case "hexdump":
// this is mainly for debugging invisible special char related issues
var hexData = string.Join("", data.Select(c => c + "(" + ((int)c).ToString("X2") + ")"));
_logger.Debug(string.Format("CardigannIndexer ({0}): strdump: {1}", _definition.Id, hexData));
_logger.Debug("CardigannIndexer ({0}): strdump: {1}", _definition.Id, hexData);
break;
case "strdump":
// for debugging
@@ -914,7 +919,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
break;
default:
_logger.Error(string.Format("CardigannIndexer ({0}): Unsupported selector: {1}", _definition.Id, rowSelector));
_logger.Error("CardigannIndexer ({0}): Unsupported selector: {1}", _definition.Id, rowSelector);
continue;
}
}

View File

@@ -105,7 +105,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
}
catch (Exception ex)
{
_logger.Trace(ex, "Failed to parse JSON rows count.");
_logger.Debug(ex, "Failed to parse JSON rows count.");
}
}
@@ -226,7 +226,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
{
results = ApplyFilters(results, search.Preprocessingfilters, variables);
searchResultDocument = searchResultParser.ParseDocument(results);
_logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results));
_logger.Trace("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results);
}
var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables);
@@ -241,7 +241,7 @@ namespace NzbDrone.Core.Indexers.Definitions.Cardigann
{
results = ApplyFilters(results, search.Preprocessingfilters, variables);
searchResultDocument = searchResultParser.ParseDocument(results);
_logger.Trace(string.Format("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results));
_logger.Trace("CardigannIndexer ({0}): result after preprocessingfilters: {1}", _definition.Id, results);
}
var rowsSelector = ApplyGoTemplateText(search.Rows.Selector, variables);

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 + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
PublishDate = DateTime.Parse(row.UploadDate + " +0300", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
Description = row.SmallDescription,
Genres = row.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
ImdbId = imdbId,
@@ -101,7 +101,7 @@ public class FileListParser : IParseIndexerResponse
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/download.php")
.AddQueryParam("id", torrentId.ToString())
.AddQueryParam("passkey", _settings.Passkey);
.AddQueryParam("passkey", _settings.Passkey.Trim());
return url.FullUri;
}

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

@@ -32,7 +32,7 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
return new HDBitsParser(Settings, Capabilities.Categories);
}
private IndexerCapabilities SetCapabilities()
private static IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
{
@@ -43,6 +43,11 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
Flags = new List<IndexerFlag>
{
IndexerFlag.Internal,
IndexerFlag.Exclusive,
}
};

View File

@@ -85,6 +85,9 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
[JsonProperty(PropertyName = "type_origin")]
public int TypeOrigin { get; set; }
[JsonProperty(PropertyName = "type_exclusive")]
public int TypeExclusive { get; set; }
[JsonProperty(PropertyName = "imdb")]
public ImdbInfo ImdbInfo { get; set; }

View File

@@ -1,9 +0,0 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.HDBits
{
public class HDBitsInfo : TorrentInfo
{
public bool? Internal { get; set; }
}
}

View File

@@ -62,16 +62,8 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
}
var id = result.Id;
var internalRelease = result.TypeOrigin == 1;
var flags = new HashSet<IndexerFlag>();
if (internalRelease)
{
flags.Add(IndexerFlag.Internal);
}
releaseInfos.Add(new HDBitsInfo
releaseInfos.Add(new TorrentInfo
{
Guid = $"HDBits-{id}",
Title = GetTitle(result),
@@ -85,28 +77,43 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
Files = (int)result.NumFiles,
Peers = result.Leechers + result.Seeders,
PublishDate = result.Added.ToUniversalTime(),
Internal = internalRelease,
Year = result.ImdbInfo?.Year ?? 0,
ImdbId = result.ImdbInfo?.Id ?? 0,
TvdbId = result.TvdbInfo?.Id ?? 0,
DownloadVolumeFactor = GetDownloadVolumeFactor(result),
UploadVolumeFactor = GetUploadVolumeFactor(result),
IndexerFlags = flags
IndexerFlags = GetIndexerFlags(result)
});
}
return releaseInfos.ToArray();
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private string GetTitle(TorrentQueryResponse item)
{
return _settings.UseFilenames && item.FileName.IsNotNullOrWhiteSpace()
// Use release name for XXX content and full discs
return item.TypeCategory != 7 && item.TypeMedium != 1 && _settings.UseFilenames && item.FileName.IsNotNullOrWhiteSpace()
? item.FileName.Replace(".torrent", "", StringComparison.InvariantCultureIgnoreCase)
: item.Name;
}
private static HashSet<IndexerFlag> GetIndexerFlags(TorrentQueryResponse item)
{
var flags = new HashSet<IndexerFlag>();
if (item.TypeOrigin == 1)
{
flags.Add(IndexerFlag.Internal);
}
if (item.TypeExclusive == 1)
{
flags.Add(IndexerFlag.Exclusive);
}
return flags;
}
private double GetDownloadVolumeFactor(TorrentQueryResponse item)
{
if (item.FreeLeech == "yes")
@@ -153,5 +160,7 @@ namespace NzbDrone.Core.Indexers.Definitions.HDBits
return url.FullUri;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
}
}

View File

@@ -403,10 +403,13 @@ namespace NzbDrone.Core.Indexers.Definitions
private static string CleanTitle(string title)
{
// drop invalid chars that seems to have cropped up in some titles. #6582
// Drop invalid chars that seems to have cropped up in some titles. #6582
title = Regex.Replace(title, @"[\u0000-\u0008\u000A-\u001F\u0100-\uFFFF]", string.Empty, RegexOptions.Compiled);
title = Regex.Replace(title, @"[\(\[\{]REQ(UEST(ED)?)?[\)\]\}]", string.Empty, RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Drop languages between brackets conflicting with anime release group parsing
title = Regex.Replace(title, @"^\[[a-z0-9 ._-]+\][-._ ](?<title>.*-[a-z0-9]+)$", "${title}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
return title.Trim(' ', '-', ':');
}
}

View File

@@ -23,7 +23,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public class Knaben : TorrentIndexerBase<NoAuthTorrentBaseSettings>
{
public override string Name => "Knaben";
public override string[] IndexerUrls => new[] { "https://knaben.eu/" };
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();
@@ -145,7 +146,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class KnabenRequestGenerator : IIndexerRequestGenerator
{
private const string API_SEARCH_ENDPOINT = "https://api.knaben.eu/v1";
private const string ApiSearchEndpoint = "https://api.knaben.org/v1";
private readonly IndexerCapabilities _capabilities;
@@ -226,7 +227,7 @@ namespace NzbDrone.Core.Indexers.Definitions
body.Add("categories", categories.Select(int.Parse).Distinct().ToArray());
}
var request = new HttpRequest(API_SEARCH_ENDPOINT, HttpAccept.Json)
var request = new HttpRequest(ApiSearchEndpoint, HttpAccept.Json)
{
Headers =
{

View File

@@ -16,6 +16,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
@@ -36,8 +37,8 @@ namespace NzbDrone.Core.Indexers.Definitions
public override bool SupportsPagination => true;
public override int PageSize => 100;
public override IndexerCapabilities Capabilities => SetCapabilities();
private readonly ICacheManager _cacheManager;
private static readonly Regex TorrentIdRegex = new Regex(@"tor/download.php\?tid=(?<id>\d+)$");
public MyAnonamouse(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger, ICacheManager cacheManager)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
@@ -59,39 +60,66 @@ namespace NzbDrone.Core.Indexers.Definitions
{
var downloadLink = link.RemoveQueryParam("canUseToken");
if (Settings.Freeleech && bool.TryParse(link.GetQueryParam("canUseToken"), out var canUseToken) && canUseToken)
if (Settings.UseFreeleechWedge is (int)MyAnonamouseFreeleechWedgeAction.Preferred or (int)MyAnonamouseFreeleechWedgeAction.Required &&
bool.TryParse(link.GetQueryParam("canUseToken"), out var canUseToken) && canUseToken)
{
_logger.Debug("Attempting to use freeleech token for {0}", downloadLink.AbsoluteUri);
_logger.Debug("Attempting to use freeleech wedge for {0}", downloadLink.AbsoluteUri);
var idMatch = TorrentIdRegex.Match(downloadLink.AbsoluteUri);
if (idMatch.Success)
if (int.TryParse(link.GetQueryParam("tid"), out var torrentId) && torrentId > 0)
{
var id = int.Parse(idMatch.Groups["id"].Value);
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
var freeleechUrl = Settings.BaseUrl + $"json/bonusBuy.php/{timestamp}";
var freeleechRequest = new HttpRequestBuilder(freeleechUrl)
var freeleechRequestBuilder = new HttpRequestBuilder(freeleechUrl)
.Accept(HttpAccept.Json)
.AddQueryParam("spendtype", "personalFL")
.AddQueryParam("torrentid", id)
.AddQueryParam("timestamp", timestamp.ToString())
.Build();
.AddQueryParam("torrentid", torrentId)
.AddQueryParam("timestamp", timestamp.ToString());
var indexerReq = new IndexerRequest(freeleechRequest);
var response = await FetchIndexerResponse(indexerReq).ConfigureAwait(false);
var resource = Json.Deserialize<MyAnonamouseBuyPersonalFreeleechResponse>(response.Content);
freeleechRequestBuilder.LogResponseContent = true;
var cookies = GetCookies();
if (cookies != null && cookies.Any())
{
freeleechRequestBuilder.SetCookies(cookies);
}
var freeleechRequest = freeleechRequestBuilder.Build();
var freeleechResponse = await _httpClient.ExecuteProxiedAsync(freeleechRequest, Definition).ConfigureAwait(false);
var resource = Json.Deserialize<MyAnonamouseBuyPersonalFreeleechResponse>(freeleechResponse.Content);
if (resource.Success)
{
_logger.Debug("Successfully to used freeleech token for torrentid {0}", id);
_logger.Debug("Successfully used freeleech wedge for torrentid {0}.", torrentId);
}
else if (resource.Error.IsNotNullOrWhiteSpace() && resource.Error.ContainsIgnoreCase("This Torrent is VIP"))
{
_logger.Debug("{0} is already VIP, continuing downloading: {1}", torrentId, resource.Error);
}
else if (resource.Error.IsNotNullOrWhiteSpace() && resource.Error.ContainsIgnoreCase("This is already a personal freeleech"))
{
_logger.Debug("{0} is already a personal freeleech, continuing downloading: {1}", torrentId, resource.Error);
}
else
{
_logger.Debug("Failed to use freeleech token: {0}", resource.Error);
_logger.Warn("Failed to purchase freeleech wedge for {0}: {1}", torrentId, resource.Error);
if (Settings.UseFreeleechWedge == (int)MyAnonamouseFreeleechWedgeAction.Preferred)
{
_logger.Debug("'Use Freeleech Wedge' option set to preferred, continuing downloading: '{0}'", downloadLink.AbsoluteUri);
}
else
{
throw new ReleaseUnavailableException($"Failed to buy freeleech wedge and 'Use Freeleech Wedge' is set to required, aborting download: '{downloadLink.AbsoluteUri}'");
}
}
}
else
{
_logger.Debug("Could not get torrent id from link {0}, skipping freeleech", downloadLink.AbsoluteUri);
_logger.Warn("Could not get torrent id from link {0}, skipping use of freeleech wedge.", downloadLink.AbsoluteUri);
}
}
@@ -294,14 +322,21 @@ namespace NzbDrone.Core.Indexers.Definitions
parameters.Set("tor[srchIn][filenames]", "true");
}
var catList = _capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
if (_settings.SearchLanguages.Any())
{
foreach (var (language, index) in _settings.SearchLanguages.Select((value, index) => (value, index)))
{
parameters.Set($"tor[browse_lang][{index}]", language.ToString());
}
}
var catList = _capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories).Distinct().ToList();
if (catList.Any())
{
var index = 0;
foreach (var cat in catList)
foreach (var (category, index) in catList.Select((value, index) => (value, index)))
{
parameters.Set("tor[cat][" + index + "]", cat);
index++;
parameters.Set($"tor[cat][{index}]", category);
}
}
else
@@ -441,6 +476,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)
@@ -523,7 +563,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.CombinePath("/tor/download.php")
.AddQueryParam("tid", torrentId);
if (_settings.Freeleech && canUseToken)
if (_settings.UseFreeleechWedge is (int)MyAnonamouseFreeleechWedgeAction.Preferred or (int)MyAnonamouseFreeleechWedgeAction.Required && canUseToken)
{
url = url.AddQueryParam("canUseToken", "true");
}
@@ -548,8 +588,11 @@ namespace NzbDrone.Core.Indexers.Definitions
_logger.Debug("Fetching user data: {0}", request.Url.FullUri);
var response = _httpClient.ExecuteProxied(request, _definition);
var jsonResponse = JsonConvert.DeserializeObject<MyAnonamouseUserDataResponse>(response.Content);
_logger.Trace("Current user class: '{0}'", jsonResponse.UserClass);
return jsonResponse.UserClass?.Trim();
},
TimeSpan.FromHours(1));
@@ -579,6 +622,8 @@ namespace NzbDrone.Core.Indexers.Definitions
SearchInDescription = false;
SearchInSeries = false;
SearchInFilenames = false;
SearchLanguages = Array.Empty<int>();
UseFreeleechWedge = (int)MyAnonamouseFreeleechWedgeAction.Never;
}
[FieldDefinition(2, Type = FieldType.Textbox, Label = "Mam Id", HelpText = "Mam Session Id (Created Under Preferences -> Security)")]
@@ -587,18 +632,21 @@ namespace NzbDrone.Core.Indexers.Definitions
[FieldDefinition(3, Type = FieldType.Select, Label = "Search Type", SelectOptions = typeof(MyAnonamouseSearchType), HelpText = "Specify the desired search type")]
public int SearchType { get; set; }
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "Use Freeleech Wedges", HelpText = "Use freeleech wedges to make grabbed torrents personal freeleech")]
public bool Freeleech { get; set; }
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "Search in description", HelpText = "Search text in the description")]
[FieldDefinition(4, Type = FieldType.Checkbox, Label = "Search in description", HelpText = "Search text in the description")]
public bool SearchInDescription { get; set; }
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "Search in series", HelpText = "Search text in the series")]
[FieldDefinition(5, Type = FieldType.Checkbox, Label = "Search in series", HelpText = "Search text in the series")]
public bool SearchInSeries { get; set; }
[FieldDefinition(7, Type = FieldType.Checkbox, Label = "Search in filenames", HelpText = "Search text in the filenames")]
[FieldDefinition(6, Type = FieldType.Checkbox, Label = "Search in filenames", HelpText = "Search text in the filenames")]
public bool SearchInFilenames { get; set; }
[FieldDefinition(7, Type = FieldType.Select, Label = "Search Languages", SelectOptions = typeof(MyAnonamouseSearchLanguages), HelpText = "Specify the desired languages. If unspecified, all options are used.")]
public IEnumerable<int> SearchLanguages { get; set; }
[FieldDefinition(8, Type = FieldType.Select, Label = "Use Freeleech Wedges", SelectOptions = typeof(MyAnonamouseFreeleechWedgeAction), HelpText = "Use freeleech wedges to make grabbed torrents personal freeleech")]
public int UseFreeleechWedge { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
@@ -626,6 +674,210 @@ namespace NzbDrone.Core.Indexers.Definitions
NotVip = 5,
}
public enum MyAnonamouseSearchLanguages
{
[FieldOption(Label="English")]
English = 1,
[FieldOption(Label="Afrikaans")]
Afrikaans = 17,
[FieldOption(Label="Arabic")]
Arabic = 32,
[FieldOption(Label="Bengali")]
Bengali = 35,
[FieldOption(Label="Bosnian")]
Bosnian = 51,
[FieldOption(Label="Bulgarian")]
Bulgarian = 18,
[FieldOption(Label="Burmese")]
Burmese = 6,
[FieldOption(Label="Cantonese")]
Cantonese = 44,
[FieldOption(Label="Catalan")]
Catalan = 19,
[FieldOption(Label="Chinese")]
Chinese = 2,
[FieldOption(Label="Croatian")]
Croatian = 49,
[FieldOption(Label="Czech")]
Czech = 20,
[FieldOption(Label="Danish")]
Danish = 21,
[FieldOption(Label="Dutch")]
Dutch = 22,
[FieldOption(Label="Estonian")]
Estonian = 61,
[FieldOption(Label="Farsi")]
Farsi = 39,
[FieldOption(Label="Finnish")]
Finnish = 23,
[FieldOption(Label="French")]
French = 36,
[FieldOption(Label="German")]
German = 37,
[FieldOption(Label="Greek")]
Greek = 26,
[FieldOption(Label="Greek, Ancient")]
GreekAncient = 59,
[FieldOption(Label="Gujarati")]
Gujarati = 3,
[FieldOption(Label="Hebrew")]
Hebrew = 27,
[FieldOption(Label="Hindi")]
Hindi = 8,
[FieldOption(Label="Hungarian")]
Hungarian = 28,
[FieldOption(Label="Icelandic")]
Icelandic = 63,
[FieldOption(Label="Indonesian")]
Indonesian = 53,
[FieldOption(Label="Irish")]
Irish = 56,
[FieldOption(Label="Italian")]
Italian = 43,
[FieldOption(Label="Japanese")]
Japanese = 38,
[FieldOption(Label="Javanese")]
Javanese = 12,
[FieldOption(Label="Kannada")]
Kannada = 5,
[FieldOption(Label="Korean")]
Korean = 41,
[FieldOption(Label="Lithuanian")]
Lithuanian = 50,
[FieldOption(Label="Latin")]
Latin = 46,
[FieldOption(Label="Latvian")]
Latvian = 62,
[FieldOption(Label="Malay")]
Malay = 33,
[FieldOption(Label="Malayalam")]
Malayalam = 58,
[FieldOption(Label="Manx")]
Manx = 57,
[FieldOption(Label="Marathi")]
Marathi = 9,
[FieldOption(Label="Norwegian")]
Norwegian = 48,
[FieldOption(Label="Polish")]
Polish = 45,
[FieldOption(Label="Portuguese")]
Portuguese = 34,
[FieldOption(Label="Brazilian Portuguese (BP)")]
BrazilianPortuguese = 52,
[FieldOption(Label="Punjabi")]
Punjabi = 14,
[FieldOption(Label="Romanian")]
Romanian = 30,
[FieldOption(Label="Russian")]
Russian = 16,
[FieldOption(Label="Scottish Gaelic")]
ScottishGaelic = 24,
[FieldOption(Label="Sanskrit")]
Sanskrit = 60,
[FieldOption(Label="Serbian")]
Serbian = 31,
[FieldOption(Label="Slovenian")]
Slovenian = 54,
[FieldOption(Label="Spanish")]
Spanish = 4,
[FieldOption(Label="Castilian Spanish")]
CastilianSpanish = 55,
[FieldOption(Label="Swedish")]
Swedish = 40,
[FieldOption(Label="Tagalog")]
Tagalog = 29,
[FieldOption(Label="Tamil")]
Tamil = 11,
[FieldOption(Label="Telugu")]
Telugu = 10,
[FieldOption(Label="Thai")]
Thai = 7,
[FieldOption(Label="Turkish")]
Turkish = 42,
[FieldOption(Label="Ukrainian")]
Ukrainian = 25,
[FieldOption(Label="Urdu")]
Urdu = 15,
[FieldOption(Label="Vietnamese")]
Vietnamese = 13,
[FieldOption(Label="Other")]
Other = 47,
}
public enum MyAnonamouseFreeleechWedgeAction
{
[FieldOption(Label = "Never", Hint = "Do not buy as freeleech")]
Never = 0,
[FieldOption(Label = "Preferred", Hint = "Buy and use wedge if possible")]
Preferred = 1,
[FieldOption(Label = "Required", Hint = "Abort download if unable to buy wedge")]
Required = 2,
}
public class MyAnonamouseTorrent
{
public int Id { get; set; }
@@ -655,7 +907,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
@@ -666,7 +919,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public class MyAnonamouseUserDataResponse
{
[JsonProperty(PropertyName = "class")]
[JsonProperty(PropertyName = "classname")]
public string UserClass { get; set; }
}
}

View File

@@ -322,7 +322,7 @@ namespace NzbDrone.Core.Indexers.Definitions
ApiKey = "";
}
[FieldDefinition(4, Label = "ApiKey", HelpText = "IndexerNebulanceSettingsApiKeyHelpText")]
[FieldDefinition(2, Label = "ApiKey", HelpText = "IndexerNebulanceSettingsApiKeyHelpText", Privacy = PrivacyLevel.ApiKey)]
public string ApiKey { get; set; }
}

View File

@@ -148,7 +148,8 @@ namespace NzbDrone.Core.Indexers.Newznab
SupportsSearch = SupportsSearch,
SupportsRedirect = SupportsRedirect,
SupportsPagination = SupportsPagination,
Capabilities = caps
Capabilities = caps,
Redirect = true
};
}

View File

@@ -128,7 +128,7 @@ namespace NzbDrone.Core.Indexers.Newznab
parameters.Set("tvdbid", searchCriteria.TvdbId.Value.ToString());
}
if (searchCriteria.TmdbId.HasValue && capabilities.TvSearchTvdbAvailable)
if (searchCriteria.TmdbId.HasValue && capabilities.TvSearchTmdbAvailable)
{
parameters.Set("tmdbid", searchCriteria.TmdbId.Value.ToString());
}

View File

@@ -27,7 +27,7 @@ public class NorBits : TorrentIndexerBase<NorBitsSettings>
public override string[] IndexerUrls => new[] { "https://norbits.net/" };
public override string Description => "NorBits is a Norwegian Private site for MOVIES / TV / GENERAL";
public override string Language => "nb-NO";
public override Encoding Encoding => Encoding.GetEncoding("iso-8859-1");
public override Encoding Encoding => Encoding.UTF8;
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
@@ -129,26 +129,14 @@ public class NorBits : TorrentIndexerBase<NorBitsSettings>
}
};
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=49", NewznabStandardCategory.MoviesUHD, "Filmer - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=19", NewznabStandardCategory.MoviesHD, "Filmer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=20", NewznabStandardCategory.MoviesHD, "Filmer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=1&sub2_cat[]=22", NewznabStandardCategory.MoviesSD, "Filmer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=49", NewznabStandardCategory.TVUHD, "TV - UHD-2160p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=19", NewznabStandardCategory.TVHD, "TV - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=20", NewznabStandardCategory.TVHD, "TV - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=2&sub2_cat[]=22", NewznabStandardCategory.TVSD, "TV - SD");
caps.Categories.AddCategoryMapping("main_cat[]=1", NewznabStandardCategory.Movies, "Filmer");
caps.Categories.AddCategoryMapping("main_cat[]=2", NewznabStandardCategory.TV, "TV");
caps.Categories.AddCategoryMapping("main_cat[]=3", NewznabStandardCategory.PC, "Programmer");
caps.Categories.AddCategoryMapping("main_cat[]=4", NewznabStandardCategory.Console, "Spill");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=42", NewznabStandardCategory.AudioMP3, "Musikk - 192");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=43", NewznabStandardCategory.AudioMP3, "Musikk - 256");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=44", NewznabStandardCategory.AudioMP3, "Musikk - 320");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=45", NewznabStandardCategory.AudioMP3, "Musikk - VBR");
caps.Categories.AddCategoryMapping("main_cat[]=5&sub2_cat[]=46", NewznabStandardCategory.AudioLossless, "Musikk - Lossless");
caps.Categories.AddCategoryMapping("main_cat[]=5", NewznabStandardCategory.Audio, "Musikk");
caps.Categories.AddCategoryMapping("main_cat[]=6", NewznabStandardCategory.Books, "Tidsskrift");
caps.Categories.AddCategoryMapping("main_cat[]=7", NewznabStandardCategory.AudioAudiobook, "Lydbøker");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=19", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-1080p/i");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=20", NewznabStandardCategory.AudioVideo, "Musikkvideoer - HD-720p");
caps.Categories.AddCategoryMapping("main_cat[]=8&sub2_cat[]=22", NewznabStandardCategory.AudioVideo, "Musikkvideoer - SD");
caps.Categories.AddCategoryMapping("main_cat[]=8", NewznabStandardCategory.AudioVideo, "Musikkvideoer");
caps.Categories.AddCategoryMapping("main_cat[]=40", NewznabStandardCategory.AudioOther, "Podcasts");
return caps;
@@ -190,7 +178,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();
@@ -277,20 +265,17 @@ public class NorBitsParser : IParseIndexerResponse
foreach (var row in rows)
{
var link = _settings.BaseUrl + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href").TrimStart('/');
var link = _settings.BaseUrl + row.QuerySelector("td:nth-of-type(2) > a[href*=\"download.php?id=\"]")?.GetAttribute("href")?.TrimStart('/');
var qDetails = row.QuerySelector("td:nth-of-type(2) > a[href*=\"details.php?id=\"]");
var title = qDetails?.GetAttribute("title").Trim();
var details = _settings.BaseUrl + qDetails?.GetAttribute("href").TrimStart('/');
var title = qDetails?.GetAttribute("title")?.Trim();
var details = _settings.BaseUrl + qDetails?.GetAttribute("href")?.TrimStart('/');
var mainCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
var secondCategory = row.QuerySelector("td:nth-of-type(1) > div > a[href*=\"sub2_cat[]\"]")?.GetAttribute("href")?.Split('?').Last();
var catQuery = row.QuerySelector("td:nth-of-type(1) a[href*=\"main_cat[]\"]")?.GetAttribute("href")?.Split('?').Last().Split('&', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var category = catQuery?.FirstOrDefault(x => x.StartsWith("main_cat[]=", StringComparison.OrdinalIgnoreCase));
var categoryList = new[] { mainCategory, secondCategory };
var cat = string.Join("&", categoryList.Where(c => !string.IsNullOrWhiteSpace(c)));
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)").TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)").TextContent);
var seeders = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(9)")?.TextContent);
var leechers = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(10)")?.TextContent);
var release = new TorrentInfo
{
@@ -298,7 +283,7 @@ public class NorBitsParser : IParseIndexerResponse
InfoUrl = details,
DownloadUrl = link,
Title = title,
Categories = _categories.MapTrackerCatToNewznab(cat),
Categories = _categories.MapTrackerCatToNewznab(category),
Size = ParseUtil.GetBytes(row.QuerySelector("td:nth-of-type(7)")?.TextContent),
Files = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(3) > a")?.TextContent.Trim()),
Grabs = ParseUtil.CoerceInt(row.QuerySelector("td:nth-of-type(8)")?.FirstChild?.TextContent.Trim()),

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

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Events;
@@ -15,6 +18,7 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
public override bool SupportsSearch => true;
public override bool SupportsPagination => true;
public override int PageSize => 50;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(4);
public override IndexerCapabilities Capabilities => SetCapabilities();
@@ -34,7 +38,19 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
public override IParseIndexerResponse GetParser()
{
return new PassThePopcornParser(Settings);
return new PassThePopcornParser(Settings, Capabilities.Categories);
}
protected override Task<HttpRequest> GetDownloadRequest(Uri link)
{
var requestBuilder = new HttpRequestBuilder(link.AbsoluteUri);
var request = requestBuilder
.SetHeader("ApiUser", Settings.APIUser)
.SetHeader("ApiKey", Settings.APIKey)
.Build();
return Task.FromResult(request);
}
private IndexerCapabilities SetCapabilities()
@@ -43,10 +59,6 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
LimitsDefault = PageSize,
LimitsMax = PageSize,
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId

View File

@@ -5,21 +5,20 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
public class PassThePopcornResponse
{
public string TotalResults { get; set; }
public List<PassThePopcornMovie> Movies { get; set; }
public IReadOnlyCollection<PassThePopcornMovie> Movies { get; set; }
public string Page { get; set; }
public string AuthKey { get; set; }
public string PassKey { get; set; }
}
public class PassThePopcornMovie
{
public string GroupId { get; set; }
public string CategoryId { get; set; }
public string Title { get; set; }
public string Year { get; set; }
public string Cover { get; set; }
public List<string> Tags { get; set; }
public IReadOnlyCollection<string> Tags { get; set; }
public string ImdbId { get; set; }
public List<PassThePopcornTorrent> Torrents { get; set; }
public IReadOnlyCollection<PassThePopcornTorrent> Torrents { get; set; }
}
public class PassThePopcornTorrent

View File

@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
@@ -14,12 +14,12 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
public class PassThePopcornParser : IParseIndexerResponse
{
private readonly PassThePopcornSettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
private static Regex SeasonRegex => new (@"\bS\d{2,3}(E\d{2,3})?\b", RegexOptions.Compiled);
public PassThePopcornParser(PassThePopcornSettings settings)
public PassThePopcornParser(PassThePopcornSettings settings, IndexerCapabilitiesCategories categories)
{
_settings = settings;
_categories = categories;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
@@ -56,6 +56,19 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
foreach (var torrent in result.Torrents)
{
// skip non-freeleech results when freeleech only is set
var downloadVolumeFactor = torrent.FreeleechType?.ToUpperInvariant() switch
{
"FREELEECH" or "NEUTRAL LEECH" => 0,
"HALF LEECH" => 0.5,
_ => 1
};
if (_settings.FreeleechOnly && downloadVolumeFactor != 0.0)
{
continue;
}
var id = torrent.Id;
var title = torrent.ReleaseName;
@@ -71,12 +84,11 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
flags.Add(PassThePopcornFlag.Approved);
}
var categories = new List<IndexerCategory> { NewznabStandardCategory.Movies };
if (title != null && SeasonRegex.Match(title).Success)
var uploadVolumeFactor = torrent.FreeleechType?.ToUpperInvariant() switch
{
categories.Add(NewznabStandardCategory.TV);
}
"NEUTRAL LEECH" => 0,
_ => 1
};
torrentInfos.Add(new TorrentInfo
{
@@ -84,8 +96,8 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
Title = title,
Year = int.Parse(result.Year),
InfoUrl = GetInfoUrl(result.GroupId, id),
DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey),
Categories = categories,
DownloadUrl = GetDownloadUrl(id),
Categories = _categories.MapTrackerCatToNewznab(result.CategoryId),
Size = long.Parse(torrent.Size),
Grabs = int.Parse(torrent.Snatched),
Seeders = int.Parse(torrent.Seeders),
@@ -94,16 +106,11 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
ImdbId = result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0,
Scene = torrent.Scene,
IndexerFlags = flags,
DownloadVolumeFactor = torrent.FreeleechType?.ToUpperInvariant() switch
{
"FREELEECH" => 0,
"HALF LEECH" => 0.5,
_ => 1
},
UploadVolumeFactor = 1,
DownloadVolumeFactor = downloadVolumeFactor,
UploadVolumeFactor = uploadVolumeFactor,
MinimumRatio = 1,
MinimumSeedTime = 345600,
Genres = result.Tags ?? new List<string>(),
Genres = result.Tags?.ToList() ?? new List<string>(),
PosterUrl = GetPosterUrl(result.Cover)
});
}
@@ -114,14 +121,12 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private string GetDownloadUrl(int torrentId, string authKey, string passKey)
private string GetDownloadUrl(int torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("action", "download")
.AddQueryParam("id", torrentId)
.AddQueryParam("authkey", authKey)
.AddQueryParam("torrent_pass", passKey);
.AddQueryParam("id", torrentId);
return url.FullUri;
}

View File

@@ -78,6 +78,8 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{ "action", "advanced" },
{ "json", "noredirect" },
{ "grouping", "0" },
{ "order_by", "time" },
{ "order_way", "desc" },
{ "searchstr", searchTerm }
};

View File

@@ -18,6 +18,12 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
{
private static readonly PassThePopcornSettingsValidator Validator = new ();
public PassThePopcornSettings()
{
BaseSettings.QueryLimit = 150;
BaseSettings.LimitsUnit = (int)IndexerLimitsUnit.Hour;
}
[FieldDefinition(2, Label = "IndexerSettingsApiUser", HelpText = "IndexerPassThePopcornSettingsApiUserHelpText", Privacy = PrivacyLevel.UserName)]
public string APIUser { get; set; }

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

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Indexers.Definitions
"https://rutracker.net/",
"https://rutracker.nl/"
};
public override string Description => "RuTracker.org is a Semi-Private Russian torrent site with a thriving file-sharing community";
public override string Description => "RuTracker.org is a RUSSIAN Semi-Private site with a thriving file-sharing community";
public override string Language => "ru-RU";
public override Encoding Encoding => Encoding.GetEncoding("windows-1251");
public override IndexerPrivacy Privacy => IndexerPrivacy.SemiPrivate;
@@ -144,6 +144,7 @@ namespace NzbDrone.Core.Indexers.Definitions
SupportsRawSearch = true
};
// Note: When refreshing the categories use the tracker.php page and NOT the search.php page!
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.Movies, "Наше кино");
caps.Categories.AddCategoryMapping(941, NewznabStandardCategory.Movies, "|- Кино СССР");
caps.Categories.AddCategoryMapping(1666, NewznabStandardCategory.Movies, "|- Детские отечественные фильмы");
@@ -933,6 +934,8 @@ namespace NzbDrone.Core.Indexers.Definitions
caps.Categories.AddCategoryMapping(1224, NewznabStandardCategory.AudioLossless, "|- Авторская песня (lossless)");
caps.Categories.AddCategoryMapping(1225, NewznabStandardCategory.AudioMP3, "|- Авторская песня (lossy)");
caps.Categories.AddCategoryMapping(1226, NewznabStandardCategory.Audio, "|- Менестрели и ролевики (lossy и lossless)");
caps.Categories.AddCategoryMapping(782, NewznabStandardCategory.Audio, "Лейбл- и сцен-паки. Неофициальные сборники и ремастеринги. AI-музыка");
caps.Categories.AddCategoryMapping(577, NewznabStandardCategory.Audio, "|- AI-Music - музыка ИИ, нейросетей (lossy и lossless)");
caps.Categories.AddCategoryMapping(1842, NewznabStandardCategory.AudioLossless, "Label Packs (lossless)");
caps.Categories.AddCategoryMapping(1648, NewznabStandardCategory.AudioMP3, "Label packs, Scene packs (lossy)");
caps.Categories.AddCategoryMapping(134, NewznabStandardCategory.AudioLossless, "|- Неофициальные сборники и ремастеринги (lossless)");
@@ -1292,7 +1295,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 +1310,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 +1351,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, "|- Графические редакторы");
@@ -1750,7 +1752,7 @@ namespace NzbDrone.Core.Indexers.Definitions
title = Regex.Replace(title, @"(\([\p{IsCyrillic}\W]+)\s/\s(.+?)\)", string.Empty, RegexOptions.Compiled | RegexOptions.IgnoreCase);
// Remove VO, MVO and DVO from titles
var vo = new Regex(@".VO\s\(.+?\)");
var vo = new Regex(@"((?:\dx\s)?(?:[A-Z])?VO\s\(.+?\))");
title = vo.Replace(title, string.Empty);
// Remove R5 and (R5) from release names
@@ -1758,7 +1760,7 @@ namespace NzbDrone.Core.Indexers.Definitions
title = r5.Replace(title, "$1");
// Remove Sub languages from release names
title = Regex.Replace(title, @"(\bSub\b.*$|\b[\+]*Sub[\+]*\b)", string.Empty);
title = Regex.Replace(title, @"(\bSub\b[^+]*\b|\b[\+]*Sub[\+]*\b)", string.Empty);
}
// language fix: all rutracker releases contains russian track

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;
@@ -19,7 +20,7 @@ public class SecretCinema : GazelleBase<GazelleSettings>
{
public override string Name => "Secret Cinema";
public override string[] IndexerUrls => new[] { "https://secret-cinema.pw/" };
public override string Description => "A tracker for rare movies.";
public override string Description => "Secret Cinema is a Private ratioless site for rare MOVIES.";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override IndexerCapabilities Capabilities => SetCapabilities();
@@ -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))
@@ -148,7 +151,7 @@ public class SecretCinemaParser : IParseIndexerResponse
if (torrent.RemasterTitle.IsNotNullOrWhiteSpace())
{
release.Title += $" [{torrent.RemasterTitle.Trim()}]";
release.Title += $" [{WebUtility.HtmlDecode(torrent.RemasterTitle).Trim()}]";
}
// Replace media formats with standards

View File

@@ -262,7 +262,7 @@ namespace NzbDrone.Core.Indexers.Definitions
return jsonResponse.Resource.Select(torrent => new TorrentInfo
{
Guid = torrent.Id.ToString(),
Guid = torrent.Url,
Title = CleanTitle(torrent.Name),
Description = torrent.ShortDescription,
Size = torrent.Size,

View File

@@ -7,6 +7,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Indexers.Settings;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
@@ -52,7 +53,7 @@ namespace NzbDrone.Core.Indexers.Definitions
public override IParseIndexerResponse GetParser()
{
return new TorrentDayParser(Settings, Capabilities.Categories);
return new TorrentDayParser(Settings, Capabilities.Categories, _logger);
}
protected override IDictionary<string, string> GetCookies()
@@ -228,15 +229,29 @@ namespace NzbDrone.Core.Indexers.Definitions
{
private readonly TorrentDaySettings _settings;
private readonly IndexerCapabilitiesCategories _categories;
private readonly Logger _logger;
public TorrentDayParser(TorrentDaySettings settings, IndexerCapabilitiesCategories categories)
public TorrentDayParser(TorrentDaySettings settings, IndexerCapabilitiesCategories categories, Logger logger)
{
_settings = settings;
_categories = categories;
_logger = logger;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
if (indexerResponse.HttpResponse.HasHttpRedirect)
{
_logger.Warn("Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
if (indexerResponse.HttpResponse.RedirectUrl.ContainsIgnoreCase("/login.php"))
{
throw new IndexerException(indexerResponse, "We are being redirected to the login page. Most likely your session expired or was killed. Recheck your cookie and try testing the indexer.");
}
throw new IndexerException(indexerResponse, "Redirected to {0} from indexer request", indexerResponse.HttpResponse.RedirectUrl);
}
var torrentInfos = new List<TorrentInfo>();
var rows = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content);

View File

@@ -121,8 +121,15 @@ public class XSpeeds : TorrentIndexerBase<XSpeedsSettings>
caps.Categories.AddCategoryMapping(112, NewznabStandardCategory.MoviesOther, "Anime Movies");
caps.Categories.AddCategoryMapping(111, NewznabStandardCategory.MoviesOther, "Anime TV");
caps.Categories.AddCategoryMapping(150, NewznabStandardCategory.PC, "Apps");
caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.Books, "Books Magazines");
caps.Categories.AddCategoryMapping(156, NewznabStandardCategory.TV, "AV1");
caps.Categories.AddCategoryMapping(156, NewznabStandardCategory.Movies, "AV1");
caps.Categories.AddCategoryMapping(159, NewznabStandardCategory.Movies, "Movie Boxsets AV1");
caps.Categories.AddCategoryMapping(158, NewznabStandardCategory.Movies, "Movies AV1");
caps.Categories.AddCategoryMapping(157, NewznabStandardCategory.TV, "TV AV1");
caps.Categories.AddCategoryMapping(160, NewznabStandardCategory.TV, "TV Boxsets AV1");
caps.Categories.AddCategoryMapping(153, NewznabStandardCategory.Books, "Books");
caps.Categories.AddCategoryMapping(154, NewznabStandardCategory.AudioAudiobook, "Audiobooks");
caps.Categories.AddCategoryMapping(155, NewznabStandardCategory.Books, "Books & Magazines");
caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.MoviesOther, "Cams/TS");
caps.Categories.AddCategoryMapping(140, NewznabStandardCategory.TVDocumentary, "Documentary");
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.MoviesDVD, "DVDR");
@@ -154,6 +161,7 @@ public class XSpeeds : TorrentIndexerBase<XSpeedsSettings>
caps.Categories.AddCategoryMapping(146, NewznabStandardCategory.MoviesSD, "Movies SD");
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Audio, "Music");
caps.Categories.AddCategoryMapping(135, NewznabStandardCategory.AudioLossless, "Music/FLAC");
caps.Categories.AddCategoryMapping(151, NewznabStandardCategory.Audio, "Karaoke");
caps.Categories.AddCategoryMapping(136, NewznabStandardCategory.Audio, "Music Boxset");
caps.Categories.AddCategoryMapping(148, NewznabStandardCategory.AudioVideo, "Music Videos");
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.Other, "Other");

View File

@@ -250,7 +250,11 @@ namespace NzbDrone.Core.Indexers
{
var response = await _httpClient.ExecuteProxiedAsync(request, Definition);
if (response.StatusCode is HttpStatusCode.MovedPermanently or HttpStatusCode.Found or HttpStatusCode.SeeOther)
if (response.StatusCode is HttpStatusCode.MovedPermanently
or HttpStatusCode.Found
or HttpStatusCode.SeeOther
or HttpStatusCode.TemporaryRedirect
or HttpStatusCode.PermanentRedirect)
{
var autoRedirectChain = new List<string> { request.Url.ToString() };

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