Compare commits

...

216 Commits

Author SHA1 Message Date
Qstick
e47c7e6a47 New: Add coverurl to Newznab response 2021-08-07 12:07:38 -04:00
Nyuels
d937e0324f Fixed: (Internet Archive) Follow redirects on grabs (#403) 2021-08-06 20:50:06 -04:00
Yukine
ff623d4c39 Fixed: (Indexer) AnimeBytes improve sonarr compatibility and make optional (#376)
* Fixed: (Indexer) AnimeBytes improve sonarr compatibility and make optional

* fix(AnimeBytes): correct numbering
2021-08-06 20:47:52 -04:00
Weblate
0b05f5ef24 Translated using Weblate (Arabic)
Currently translated at 1.1% (5 of 426 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (426 of 426 strings)

Translated using Weblate (Italian)

Currently translated at 84.2% (359 of 426 strings)

Translated using Weblate (Danish)

Currently translated at 13.6% (58 of 426 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Laubau <migdahs@gmail.com>
Co-authored-by: Simone <simoneungaro@hotmail.it>
Co-authored-by: bison529 <abshalsh@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr
2021-08-06 17:51:10 -04:00
Nyuels
e6c3292485 Fixed: (Tracker) Internet Archive: Add handling of missing result fields. (#402) 2021-08-06 13:53:58 -05:00
Nyuels
ba1c1baeb5 New: (Indexer) Internet Archive 2021-08-05 21:07:09 -04:00
Qstick
5e7f4f3fc1 Fixed: Add Test All for IndexerLongTermStatusCheck
Fixes #397
2021-08-05 13:47:30 -04:00
chryzsh
3dd11213fa Fixed: Gazelle search using full IMDb ID 2021-08-04 22:04:53 -04:00
bakerboy448
50cae0719f New: (Indexer) Alternative Links for TorrentDay
Fixes #386
2021-08-02 19:04:48 -05:00
crusher
2c6680e4fa New: (Indexer) Rutracker.org (#371)
* first attempt at sc definition

* add dologin. seems to return html instead of json

* barebones working setup

* added category but errors on override

* fixed and tested

* guid fix

* fixed bdmv and dvd releases to report in radarr accepted format

* New: (Indexer) RuTracker

* minor fixes

* somewhat working rutracker org defintion with some filtering

* filter russian letters option implemented

* deal with subtitle languages

* russian filtering pretty good now

* removed sc from branch

* rutracker handles series ok now

* final touches to rutracker

* tore out the captcha

Co-authored-by: Qstick <qstick@gmail.com>
2021-08-01 09:59:45 -04:00
Qstick
96afb7f327 Fixed: (BakaBT) Map AnimeMovie to Movie
Fixes #147
2021-08-01 09:59:44 -04:00
Qstick
0d1025d60a Fixed: (Cardigann) Input pairs in HandleRequest should be form data
Should fix some download links not working for Cardigann indexers
2021-08-01 09:59:44 -04:00
Qstick
0508dd2b66 Fixed: (Cardigann) Sites that use POST search not sending form params
Fixes #367
2021-08-01 09:59:44 -04:00
Weblate
026a503d5f Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.7% (425 of 426 strings)

Co-authored-by: Will Segatto <segatto.w@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr
2021-08-01 09:59:44 -04:00
Qstick
b3f8e648cd New: (Clients) Torrent and Usenet Blackhole
Fixes #238
2021-08-01 09:59:44 -04:00
Qstick
13b458090d New: RARBG tvdbId support and retry on failure
Fixes #333
2021-08-01 09:59:44 -04:00
Qstick
f97c3ff9bd Fixed: Application mapping regex fails 2021-08-01 09:59:43 -04:00
Qstick
841ff7b6ee Fixed: Don't fail sync on single app failure 2021-08-01 09:59:43 -04:00
bakerboy448
377db47daf git updates [skip ci] 2021-08-01 09:59:43 -04:00
crusher
2addcab765 New: (Indexer) - Secret Cinema (#372)
* first attempt at sc definition

* add dologin. seems to return html instead of json

* barebones working setup

* added category but errors on override

* fixed and tested

* guid fix

* fixed bdmv and dvd releases to report in radarr accepted format

* minor fixes

* fixed sc

* first attempt at SC categories

* category fixes for movies and music

* toggled back IsProduction
2021-08-01 09:59:31 -04:00
crusher
ddc676c608 Iptorrents tv episode search fix (#374)
* adjust search term for individual season in ipt
2021-08-01 09:59:01 -04:00
Qstick
924db7a394 New: (Indexer) TorrentParadiseMl 2021-07-29 21:23:23 -04:00
Qstick
580113d6ce New: (Indexer) TorrentSyndikat 2021-07-28 19:37:51 -04:00
Qstick
d532a69edc New: (Indexer) TorrentsCSV 2021-07-28 19:02:20 -04:00
Qstick
01f7e11d5a New: (Indexer) SceneTime 2021-07-27 22:28:07 -04:00
Qstick
de97ec95db Update YamlDotNet to 11.2.1 2021-07-26 21:55:46 -04:00
Qstick
6e66467ab3 Update Mailkit to 2.13.0 2021-07-26 21:52:59 -04:00
Qstick
4c5131708d Update RestSharp Packages 2021-07-26 21:48:47 -04:00
Qstick
bb2e1a6037 Update Sentry Packages 2021-07-26 21:46:04 -04:00
Qstick
5949bd97fd Update Lint Packages 2021-07-26 21:41:45 -04:00
Qstick
eaff071b16 Bump .Net5 to 5.0.8 2021-07-26 21:35:25 -04:00
Dmitry Chepurovskiy
a922586aba New: (Indexer) Anidub 2021-07-26 21:22:01 -04:00
Qstick
80beea9bdb Fixed: Don't return results with categories that were not searched 2021-07-25 22:58:31 -04:00
Qstick
8c326fc5c2 Fixed: (ExoticaZ) Update Categories 2021-07-25 21:38:21 -04:00
Dmitry Chepurovskiy
e26081acff New: (Indexer) Animedia (#360) 2021-07-24 11:37:28 -04:00
Ashino
b3b0467d22 New: (Indexer) Torrent Xthor (#342)
* New: (Indexer) Torrent Xthor

* New: (Indexer) Torrent Xthor

Fix multiple lines fieldDefinition and texts

* New: (Indexer) Torrent Xthor
Remove unwanted blankline

* New: (Indexer) Torrent Xthor
Fix BaseSettings after rebase

* New: (Indexer) Torrent Xthor

* New: (Indexer) Torrent Xthor

Fix multiple lines fieldDefinition and texts

* New: (Indexer) Torrent Xthor
Remove unwanted blankline

* New: (Indexer) Torrent Xthor
Fix BaseSettings after rebase

* New: (Indexer) Torrent Xthor
- Add "EnhancedFrenchAccent" field that will allow to find VF2 releases when searching VFF or VFQ
- Fix BaseSettings
- Decrease the RateLimit to 2.1 seconds
- Remove page argument when searching page 0

* Fix punctuation

* New: (Indexer) Torrent Xthor

* New: (Indexer) Torrent Xthor

Fix multiple lines fieldDefinition and texts

* New: (Indexer) Torrent Xthor
Remove unwanted blankline

* New: (Indexer) Torrent Xthor
Fix BaseSettings after rebase

* New: (Indexer) Torrent Xthor
- Add "EnhancedFrenchAccent" field that will allow to find VF2 releases when searching VFF or VFQ
- Fix BaseSettings
- Decrease the RateLimit to 2.1 seconds
- Remove page argument when searching page 0

* Fix punctuation

* New: (Indexer) Torrent Xthor
- Fix "unknown" categories when searching with Prowlarr (category conversion was missing)
- Now every class has its own file (like all others indexers)

* New: (Indexer) Torrent Xthor

- Fix fielddefinition to be on single line

Co-authored-by: TCLE <t.clemenceau@shinken-solutions.com>
2021-07-23 21:09:57 -04:00
Servarr
e1c98d2b38 Translated using Weblate (Portuguese (Brazil)) (#354)
Currently translated at 99.7% (425 of 426 strings)

Added translation using Weblate (Chinese (Min Nan))

Translated using Weblate (Chinese (Simplified) (zh_CN))

Currently translated at 65.7% (280 of 426 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (426 of 426 strings)

Translated using Weblate (French)

Currently translated at 100.0% (426 of 426 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (French)

Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (German)

Currently translated at 98.1% (417 of 425 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: doob187 <amderkum@gmail.com>
Co-authored-by: foXaCe <foxace66@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: doob187 <amderkum@gmail.com>
Co-authored-by: foXaCe <foxace66@gmail.com>
2021-07-21 10:49:00 -05:00
Qstick
e304461dfb New: Add PosterUrl to ReleaseInfo for parsing 2021-07-18 21:33:17 -04:00
Qstick
a127e5a30f Update and rename feature_request.md to feature_request.yml
[skip ci]
2021-07-17 11:51:03 -04:00
Qstick
e252cd4d3e Update bug_report.yml 2021-07-17 11:42:54 -04:00
Dmitry Chepurovskiy
9a1bd3db4c New: (Indexer) Shizaproject 2021-07-17 08:29:00 -04:00
Qstick
acce098e02 Update and rename bug_report.md to bug_report.yml 2021-07-17 08:14:36 -04:00
Yukine
afa87b7113 Fixed: (Anime Tosho) Only include Releases which have a NZB (#351) 2021-07-15 21:33:42 -04:00
bakerboy448
4cbd2cd8bc Fixed: Add Missing Search Translates 2021-07-15 21:23:39 -04:00
Yukine
e81d0f3e97 Fixed: (AnimeBytes) apply LinksUnionConverter to model (#353) 2021-07-15 21:22:54 -04:00
Hawks
34a6a0e0c9 Update indexer list text 2021-07-15 06:36:46 -05:00
Yukine
4254a05ea3 Fixed: (AnimeBytes) cleanup code, fix episode searching & improve Season matching (#329)
* refactor/fix(AnimeBytes): use data classes & fix season searching

* fix: only append epsisode when season was found

* feat: add Episode padding back for Sonarr compatibility

* fix: strip Epsiode number from request
2021-07-14 21:03:49 -04:00
Yukine
d32a94c14d Fixed: (SubsPlease) fix offset release time issues 2021-07-14 19:01:54 -04:00
ntldr0
6a9155bcf5 New: (Indexers) (Redacted) Add API support 2021-07-14 19:01:03 -04:00
Dmitry Chepurovskiy
de442cc659 New: (Indexer) Anilibria 2021-07-14 18:55:04 -04:00
bakerboy448
7f514c8f1e Fixed: Improved IPT's Cookie Help Text
ref https://www.reddit.com/r/prowlarr/comments/ojlamb/help_needed_with_ipt/h52nxnl/
2021-07-14 02:27:29 -05:00
bakerboy448
4c51f09acb Update bug report template [skip ci]
(cherry picked from commit 4659a8366d8a1565890d3b72442bd35c6eb8176e)
2021-07-13 20:55:43 +01:00
Qstick
a60388fcf9 Fixed: Indexer Info modal doesn't show correct Url 2021-07-12 23:26:17 -04:00
Qstick
11b656dabf Fixed: (TVVault) Advertise Indexer flags 2021-07-12 23:11:28 -04:00
Qstick
535f29bef4 Fixed: (DigitalCore) Release InfoUrls not being set 2021-07-12 23:11:28 -04:00
bakerboy448
0ddc530dd4 Fixed: Enhanced and Added Various C# Indexer Descriptions
Fixed: Consistency in C# Indexer Credential Fields
2021-07-12 21:57:27 -05:00
Servarr
b5321d33c9 Translated using Weblate (Catalan) (#336)
Currently translated at 1.1% (5 of 425 strings)

Added translation using Weblate (Catalan)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: dtalens <databio@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/ca/
Translation: Servarr/Prowlarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: dtalens <databio@gmail.com>
2021-07-12 21:57:14 -05:00
Qstick
4116c10caa New: (Indexers) Per indexer api and download limits 2021-07-12 22:53:33 -04:00
Qstick
0fe2cf5c2d New: (Indexer) TV Vault 2021-07-12 22:03:51 -04:00
PearsonFlyer
c94573e868 Fixed: Respect categories for ImmortalSeed in search 2021-07-12 21:34:02 -04:00
bakerboy448
1945af060d Fixed: Provider Wiki Links (supported-X => supported#X) 2021-07-12 21:33:27 -04:00
Qstick
cf399ffdcc Fixed: (DanishBytes) Convert to use API
Fixes #158
2021-07-11 21:28:57 -04:00
Qstick
5846188202 Fixed: (IPTorrents) Correctly map WebDL 2021-07-11 20:51:59 -04:00
Yukine
fc65a89fbc refactor: improve readability, use UTC in request instead New York 2021-07-11 18:21:16 -04:00
bakerboy448
b62ae41de8 update pr temp [skip ci] 2021-07-10 15:12:00 -05:00
bakerboy448
8107f309b4 Update PULL_REQUEST_TEMPLATE.md 2021-07-10 11:34:11 -04:00
Qstick
c2c12297bd Fixed: Persist columns for search page 2021-07-08 20:49:15 -04:00
bakerboy448
81cbdab5eb New: (Indexer) SubsPlease Alt Links 2021-07-07 23:04:14 -04:00
Servarr
9ee5a3e94b Translated using Weblate (Hungarian) (#300)
Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (Portuguese)

Currently translated at 85.4% (363 of 425 strings)

Translated using Weblate (French)

Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (German)

Currently translated at 92.4% (393 of 425 strings)

Translated using Weblate (Portuguese)

Currently translated at 84.4% (359 of 425 strings)

Translated using Weblate (Portuguese)

Currently translated at 84.4% (359 of 425 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: foXaCe <foxace66@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: foXaCe <foxace66@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
2021-07-07 00:55:40 -05:00
Qstick
a570fd2a8f New: Advanced settings toggle in indexer edit/add modal 2021-07-05 13:12:06 -04:00
Lagicrus
5cffb10e08 Fixed: If no categories are passed in, flag up a unknown error (#311)
* If no categories are passed in, flag up a unknown error

* Pass back in default props to deal with undefined issues
2021-07-05 08:42:51 -04:00
Qstick
b11bf284dc New: (IPTorrents) Add freeleech only option
Fixes #314
2021-07-05 08:41:29 -04:00
Robin Dadswell
5c4c042b2e Updated movieService reference for App Sync Profile Service dependency on Indexer Factory 2021-07-04 22:26:35 -04:00
Qstick
d1cb744efd Update azuresync.yml
[skip ci]
2021-07-01 21:59:49 -04:00
bakerboy448
79b910a80c Fixed: Cleanse BHD APIKey from logs 2021-07-01 16:22:57 -05:00
bakerboy448
01e08e0c31 fix radarr reference in contributing [skip ci] 2021-07-01 16:21:38 -05:00
Junkbite
dd3c9c268e allow empty catergories on indexer search 2021-06-30 21:57:53 -04:00
bakerboy448
725f738ee1 Fixed: Clarify redirect wording 2021-06-30 10:43:33 -05:00
Qstick
22c738f43e Prevent sync jobs from running in parallel
[skip ci]
2021-06-29 21:53:16 -04:00
Qstick
e45f88473c Fixed: (Anthelion) Null BaseUrl and better error message on auth fail
Fixes #295
2021-06-28 23:04:10 -04:00
Qstick
889591d0b1 Fixed: (HDSpace) Use query params 2021-06-28 22:43:30 -04:00
Qstick
fe8247df8a Fixed: (HDSpace) Auth failure and Name 2021-06-28 21:36:05 -04:00
bakerboy448
7a5721bcee typo fix 2021-06-28 20:26:34 -05:00
bakerboy448
eea5c3e9a4 Fixed: Cleanse Pwd from logs 2021-06-28 12:22:47 -05:00
Qstick
f55493c9a9 New: (Indexer) HD-Space 2021-06-27 21:40:43 -04:00
bakerboy448
79618adaf9 New: (Indexer) Add IPTorrents Alt Links
as of Jackett 4524c18d39251c677bec1d4d8f75f71c6c6ac010
2021-06-27 19:32:31 -04:00
Qstick
af13d6ed80 Fixed: Not using correct BaseUrl if changed between tests 2021-06-27 18:15:18 -04:00
Qstick
38c09277d9 New: Alternative Site Links 2021-06-27 01:58:37 -04:00
Qstick
1fb693d066 Update azuresync.yml
[skip ci]
2021-06-26 18:04:48 -04:00
Qstick
7414a2f690 Update azuresync.yml
[skip ci]
2021-06-26 17:59:12 -04:00
Qstick
000590bcf7 Update azuresync.yml
[skip ci]
2021-06-26 17:57:00 -04:00
Qstick
d5d6625a63 Update azuresync.yml
[skip ci]
2021-06-26 17:16:12 -04:00
Qstick
00f33cb48f Set area and sub-area on azure sync
[skip ci]
2021-06-26 17:09:23 -04:00
Qstick
fd265c5734 Update azure-pipelines.yml 2021-06-26 14:58:58 -04:00
Qstick
316543b9aa Change Azure to Agile Config
[skip ci]
2021-06-26 11:07:51 -04:00
Qstick
117ebcff2d Fix default azure board buckets
[skip ci]
2021-06-26 10:55:13 -04:00
Qstick
aab394b2c8 Update azuresync.yml
[skip ci]
2021-06-26 10:51:14 -04:00
Qstick
6ae520c061 Test Azure Boards sync 2021-06-26 10:47:23 -04:00
bakerboy448
dfb254d2dc Fixed: Default Branch is now Develop 2021-06-26 06:36:55 -05:00
Weblate
07c03b0a12 Translated using Weblate (Portuguese)
Currently translated at 83.7% (356 of 425 strings)

Translated using Weblate (German)

Currently translated at 92.7% (394 of 425 strings)

Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
Translation: Servarr/Prowlarr
2021-06-26 07:14:03 -04:00
bakerboy448
eb0cf2d5f6 bug update [skip ci] 2021-06-26 05:48:17 -05:00
Servarr
69c04ebe7a Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (Portuguese)

Currently translated at 83.7% (356 of 425 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 0.9% (4 of 425 strings)

Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: angelsky11 <angelsky11@gmail.com>
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/zh_Hans/
Translation: Servarr/Prowlarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: angelsky11 <angelsky11@gmail.com>
2021-06-25 20:02:41 -05:00
bakerboy448
135db6d2ff Fixed: Cleanse additional AuthKey instances in logs 2021-06-24 19:27:32 -05:00
bakerboy448
c3deace9e6 Fixed: Incorrectly cleansing usetoken param 2021-06-24 18:56:15 -05:00
Qstick
9042594b14 Update FUNDING.yml to include GitHub sponsors 2021-06-24 19:52:20 -04:00
bakerboy448
44df0f5c3d Fixed: NZBGet Settings hint mentions Sabnzbd 2021-06-24 11:02:23 -05:00
bakerboy448
7b9446eb35 fix template formatting [skip ci] 2021-06-23 23:55:10 -05:00
Qstick
c6b6daaf80 Fixed: (Cardigann) DoLogin if search returns HttpError
Fixes #271
2021-06-23 22:05:28 -04:00
bakerboy448
3b42b6a7e0 Fixed: (BHD) Treat Limited Freeleech as Freeleech 2021-06-23 19:05:48 -05:00
Qstick
b6238f469c Fixed: (Orpheus) Use default Gazelle download links 2021-06-23 12:13:29 -04:00
Qstick
ae00c3aa6b Fixed: Cardigann redirect message 2021-06-23 12:13:29 -04:00
bakerboy448
8bf9d1b016 fix port [skip ci] 2021-06-23 01:55:57 -05:00
Qstick
19ed7aa804 Fixed: QueryString parsing for Cardigann failing 2021-06-22 21:12:04 -04:00
Qstick
4d129ada95 Fixed: (Gazelle) Not using freeleech token correctly
Fixes #258
2021-06-22 21:04:23 -04:00
bakerboy448
4ec8ea0e4d fixup bug report to note hidden text [skip ci] 2021-06-22 17:25:52 -05:00
bakerboy448
bd79d3c828 Fixed: Cardigann Indexer Descriptions & Indexer InfoLinks 2021-06-21 23:47:31 -05:00
Qstick
7fb6c539d4 Fixed: Require PID for AvistaZ indexers 2021-06-21 23:18:53 -04:00
Qstick
7f6fa2efbe Fixed: Newznab trying to test caps when disabled
Fixes #226
2021-06-21 23:07:05 -04:00
Qstick
b1727d9d91 Fixed: Set Download/Upload factors for Rarbg
Fixes #234
2021-06-21 23:07:05 -04:00
Qstick
3435d9db6e New: Allow users to use custom ymls 2021-06-21 22:45:09 -04:00
Qstick
8e597c8179 Fixed: Allow redirect and set referer for Anthelion 2021-06-21 21:23:38 -04:00
Qstick
80ec66514e change wiki links from wikjs to wiki endpoint 2021-06-21 21:13:08 -04:00
Weblate
88e677d973 Translated using Weblate (German)
Currently translated at 92.4% (393 of 425 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN))

Currently translated at 65.6% (279 of 425 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN))

Currently translated at 65.6% (279 of 425 strings)

Translated using Weblate (French)

Currently translated at 100.0% (425 of 425 strings)

Added translation using Weblate (Chinese (Simplified))

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: foXaCe <foxace66@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: vinson512 <vinson512@hotmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2021-06-21 19:56:22 -04:00
bakerboy448
a00f32c508 read me updates [skip ci] 2021-06-21 19:55:46 -04:00
bakerboy448
538db52d16 Fixed: Correct Password and Username field Privacy
Fixed: Consistent help text and settings for Credential Fields
2021-06-21 11:57:55 -05:00
Qstick
1ce7b0e56e New: (Indexer) Newznab preset for NZBNDX api 2021-06-20 17:47:42 -04:00
Yukine
87d91a0f15 Fixed: Support both old and new UNIT3D Id params (#244) 2021-06-19 19:47:08 -04:00
Qstick
61c1e934a5 New: Handle Freeleech flag at IndexerBase
This sets freeleech flag automatically for torrent releases with DownloadVolumeFactor = 0
2021-06-19 17:21:24 -04:00
Qstick
97b09335df fixup Anthelion category parse 2021-06-19 16:42:07 -04:00
Qstick
5e34fd2a9f New: (Indexer) Anthelion 2021-06-19 16:10:20 -04:00
Qstick
7e620bd156 New: (Indexer) ShowRss 2021-06-19 15:56:31 -04:00
Qstick
a97b801b24 New: (Indexer) GazelleGames 2021-06-19 15:48:28 -04:00
bakerboy448
9e64acd407 fix supported wikijs link 2021-06-19 10:36:33 -05:00
Yukine
f72269f91b fix(SpeedApp): correct status code check 2021-06-18 20:00:28 -04:00
Yukine
94d7f768a1 feat(Indexer): add SpeedApp C# indexer 2021-06-18 20:00:28 -04:00
bakerboy448
78cdc78cf9 indexer request method changes [skip ci] 2021-06-18 08:31:15 -05:00
Weblate
2fc1257f42 Translated using Weblate (Chinese (Simplified) (zh_CN))
Currently translated at 51.5% (219 of 425 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.8% (416 of 425 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 97.8% (416 of 425 strings)

Translated using Weblate (Portuguese)

Currently translated at 82.3% (350 of 425 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (425 of 425 strings)

Translated using Weblate (French)

Currently translated at 98.3% (418 of 425 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: flowcool <a121313b@opayq.com>
Co-authored-by: vinson512 <vinson512@hotmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
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/zh_CN/
Translation: Servarr/Prowlarr
2021-06-17 22:09:01 -04:00
bakerboy448
210311cb38 last fixup... [skip ci] 2021-06-16 13:49:12 -05:00
bakerboy448
9d7ec89314 fixups... [skip ci] 2021-06-16 13:48:25 -05:00
bakerboy448
9c279701a6 update indexer template - no links [skip ci] 2021-06-16 13:46:41 -05:00
bakerboy448
743e2e9b21 Update indexer_request.md
add link to GHI
2021-06-16 12:55:14 -05:00
bakerboy448
4a8daea940 Update indexer_request.md
add link
2021-06-16 12:53:46 -05:00
Qstick
bd90b74c12 Attempt to fix ZonaQ Auth 2021-06-16 00:58:28 -04:00
Qstick
4dff0c075a Log cleanse for passwrd form param 2021-06-16 00:43:54 -04:00
Qstick
b8f57507dd Update README.md 2021-06-16 00:33:24 -04:00
Qstick
61bfa9e7ed New: Better Application Tests 2021-06-16 00:20:42 -04:00
Qstick
bbea256c85 Fixed: Dynamic page size for Cardigann search path paging
Fixes some indexers that have arbitrary paging paths in their search-paths definitions. Set page size based on first request, break out if a request down the line returns less results.
2021-06-15 23:53:52 -04:00
Qstick
5a1186639e Fixed: Cookie set for Cardigann cookie indexers 2021-06-15 23:51:33 -04:00
TheCatLady
a8f2700fe6 Sort average response times 2021-06-15 21:14:11 -04:00
Yukine
eeec505182 Fixed: Remove Camel Case DB Converter for Cookies (#223)
* fix(ProviderRepository): remove DictionaryKeyPolicy CamelCase Naming

* Revert "fix(ProviderRepository): remove DictionaryKeyPolicy CamelCase Naming"

This reverts commit 90c95b240f.

* fix(TableMapping): make own non Camel Case Converter for Cookies
2021-06-15 21:13:37 -04:00
bakerboy448
66dc53b92f Fixed: Remove Defunct Indexer - Usenet - NZBs2GO (#216)
Fixes #214
2021-06-14 15:12:57 -05:00
Qstick
334f3514df Cleanup conversion script issues 2021-06-13 18:26:32 -04:00
Qstick
6ce35f6a24 Fix Nebulance Settings copy paste issues 2021-06-13 17:49:15 -04:00
Qstick
f6a5f887ce New: Convert Shareisland to use API 2021-06-13 01:40:07 -04:00
Qstick
bc90415394 New: (Indexer) Nebulance 2021-06-13 01:10:46 -04:00
Qstick
a8fdd46cd3 Update NewznabController.cs 2021-06-12 19:41:40 -04:00
Qstick
b6a08bdd9e Fixed: Accept ImdbIds in string format on Newznab endpoint 2021-06-12 18:02:10 -04:00
Qstick
59df0351ac New: (Indexer) YTS 2021-06-12 17:11:36 -04:00
Qstick
0fd242cd62 Additional help text for Download Clients 2021-06-12 16:45:19 -04:00
Qstick
ed7c5a937f Fixed: Correctly handle 302 and 303 redirects in HttpClient
Fixes #204
2021-06-12 16:24:48 -04:00
ntldr0
f6906d0f18 Fixed: (Cardigann) fix checkbox configuration (#169)
In ApplyGoTemplateText(), boolean values are resolved by using IsNullOrWhiteSpace().  Since ".False" is neither null or whitespace, ".False" always resolves to true.
2021-06-12 16:23:53 -04:00
Qstick
561563b48c Fixed: (Avistaz) Empty query failing with error
Fixes #192
2021-06-12 15:17:43 -04:00
Servarr
e383036c84 Translations update from Weblate (#148)
* Translated using Weblate (French)

Currently translated at 100.0% (373 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (French)

Currently translated at 100.0% (373 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (German)

Currently translated at 98.9% (369 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (French)

Currently translated at 100.0% (373 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (Chinese (Simplified) (zh_CN))

Currently translated at 5.0% (19 of 373 strings)

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

* Translated using Weblate (German)

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (German)

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (German)

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (French)

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/

* Translated using Weblate (Portuguese)

Currently translated at 75.5% (290 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (384 of 384 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/

* Translated using Weblate (Hungarian)

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/

* Translated using Weblate (Italian)

Currently translated at 81.7% (341 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/it/

* Translated using Weblate (Dutch)

Currently translated at 84.1% (351 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/

* Translated using Weblate (French)

Currently translated at 94.0% (392 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/

* Translated using Weblate (Portuguese)

Currently translated at 76.2% (318 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/

* Translated using Weblate (Portuguese)

Currently translated at 76.2% (318 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/

* Translated using Weblate (Spanish)

Currently translated at 81.7% (341 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/

* Translated using Weblate (German)

Currently translated at 94.0% (392 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (German)

Currently translated at 94.0% (392 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/

* Translated using Weblate (French)

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/fr/

* Translated using Weblate (Portuguese)

Currently translated at 76.2% (318 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (417 of 417 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/

Co-authored-by: foXaCe <foxace66@gmail.com>
Co-authored-by: Hummingbirdy The Second <hummingbirdy@pm.me>
Co-authored-by: doob187 <amderkum@gmail.com>
Co-authored-by: muihiuwev <muihiuwev@outlook.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
2021-06-12 14:52:55 -04:00
Zippy79
202f439a60 Fixed: Newznab additional parameters (#189) 2021-06-12 14:50:34 -04:00
nitsua
449e60afc0 Fix broken health check level so it is not always "Type" for Notifiarr connect (#202) 2021-06-12 14:49:44 -04:00
Qstick
9675171aff Fixed: (Cardigann) Don't die if no categories can be mapped for a release
Fixes #105
2021-06-12 02:17:17 -04:00
Qstick
bcee5f1754 Fixed: (Torznab) Categories not parsed correctly
Fixes #181
2021-06-12 01:53:22 -04:00
Qstick
d1a3e61979 Fixed: Many torrent indexers use full ImdbId instead of int version
Fixes #192
2021-06-12 01:37:01 -04:00
Qstick
b4a0c272c9 New: (indexer) Newz69
Fixes #198
2021-06-11 23:50:56 -04:00
nitsua
75cbabf716 Add detailed help text for sync levels (#155)
Adjust donation buttons to fit on mobile
Other translation updates
2021-06-11 15:42:32 -04:00
bakerboy448
6612202384 Fixed: App not syncing correct if only Interactive Search enabled (#197)
Fixes #196
2021-06-11 15:42:00 -04:00
HDVinnie
6b52dd6e7a (Indexers) Add Support for Aither via UNIT3D API (#176)
* (Indexers) Add Support for Aither via UNIT3D API

- Added support for Aither via Unit3d API

- Updated IndexerDefinitionUpdateService.cs

* fix: aither definition

* fix: aither definition

* fix: line ending

* Tmp vinnie aithia (#1)

* (Indexers) Add Support for Aither via UNIT3D API

- Added support for Aither via Unit3d API

* fix: aither definition

Signed-off-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>

* !fixup fix: aither definition

Co-authored-by: HDVinnie <hdinnovations@protonmail.com>

* update: Aither.cs

- add language and description

Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2021-06-10 17:07:29 -05:00
Robin Dadswell
974ab6387f Fixed: Website Links going to api not site 2021-06-09 15:48:51 -05:00
ta264
9ac435bc41 Fixed: Cardigann redirections after login 2021-06-08 18:21:17 -04:00
ta264
b0f04bb9d7 Fixed: Bad login redirect using a reverse proxy 2021-06-08 14:03:57 +01:00
Lagicrus
52bff3d7bd Fixed: BarChart to have a stepSize multiplier of 1 instead of auto (#163)
* Fixes the BarChart to have a stepSize multiplier of 1 instead of auto

* Moves the size to props as per Discord

* Adds the same behavior to StackedBarChart's
2021-06-08 05:56:25 -04:00
Lagicrus
d965cb3c98 New: Sort 'Add Indexer' by Language (#130)
* New: Sort 'Add Indexer' by Language

* Adds language to propTypes

Updates propTypes to appease lint

* Call translate for labels
2021-06-08 05:20:26 -04:00
bakerboy448
b592a137cf Fixed: Cleanse Token from logs 2021-06-08 03:44:24 -04:00
Lagicrus
b0819c97ed Fixed: Adds a fix to support 3 digit issues (#157)
* Adds a fix to support 3 digit issues

* Fixes mistype with bug fix
2021-06-08 03:43:07 -04:00
Pfuenzle
5802d20b93 (Indexers) Add Newz-Complex 2021-06-07 19:11:16 -04:00
bakerboy448
58e30cc9a6 Update indexer_request.md 2021-06-07 17:36:35 -05:00
bakerboy448
513b9d2324 Fixed: Add missing Translate Keys (#152) 2021-06-07 15:15:11 -05:00
bakerboy448
3ebdc1c1ac Fixed: Develop branch out of date warning
Fixed: Develop branch invalid warning
2021-06-07 14:54:00 -04:00
bakerboy448
e9a5c5f7d2 Fixed: Missing Translate Keys for Redirect & Help Text (#143) 2021-06-07 10:42:01 -05:00
bakerboy448
23c01f7dbe fixup wiki link [skip ci] 2021-06-07 09:41:50 -05:00
bakerboy448
c35864cc7f update contributing [skip ci] 2021-06-07 09:41:28 -05:00
Pfuenzle
e545e0a129 (Indexers) Add Support for Unit3d API / Convert AnimeWorld (#132)
* (Indexers) Add Support for Unit3d API / Convert AnimeWorld

Added support for the Unit3d API for the tracker AnimeWorld.
Tested all the categories, they all returned the correct results

* Update IndexerDefinitionUpdateService.cs

* Added description and language
2021-06-07 09:33:07 -04:00
bakerboy448
1e72944998 Fixed: MaM Helptext clarified
#125
2021-06-06 23:23:31 -04:00
bakerboy448
d234cbda8a Fixed: Cleanse Username prefixed with ': ' from logs
- remove unused var in log cleansing code
2021-06-06 23:19:16 -04:00
Lizandra Candido da Silva
09a9731dae Translated using Weblate (Portuguese)
Currently translated at 88.2% (329 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt/
2021-06-06 22:58:14 -04:00
doob187
3b4df1706e Translated using Weblate (German)
Currently translated at 98.6% (368 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
2021-06-06 22:58:14 -04:00
Lizandra Candido da Silva
20038e4757 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (373 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
2021-06-06 22:58:14 -04:00
Csaba
c57c77d8e7 Translated using Weblate (Hungarian)
Currently translated at 100.0% (373 of 373 strings)

Translation: Servarr/Prowlarr
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/hu/
2021-06-06 22:58:14 -04:00
Qstick
c61c3a9c45 Fixed: (IPTorrent) Cookie not used on grabs 2021-06-06 22:46:38 -04:00
Qstick
d6d418f7b3 New: (IPTorrent) Books/Non-English Category 2021-06-06 22:43:16 -04:00
Qstick
ab5cf45d88 Fixed: Allow Blank Search
#118
2021-06-06 22:37:27 -04:00
Qstick
40d55b915e Fixed: History PropTypes warning 2021-06-06 22:35:15 -04:00
Qstick
4a851c37d5 New: AutoFocus search and Search on 'Enter'
Fixes #113
2021-06-06 22:16:39 -04:00
Qstick
63b6adf0e1 Fixed: Empty should redirect to Base 2021-06-06 21:20:04 -04:00
Qstick
d9e211472b Fixed: Cardigann redirect handling fails for relative location headers 2021-06-06 20:54:46 -04:00
Qstick
fa05dbc642 Fixed: (Rarbg) Tv search doesn't use Season and Ep 2021-06-06 17:54:57 -04:00
bakerboy448
709dc0ee5f fix template for length [skip ci] 2021-06-06 16:12:46 -05:00
bakerboy448
67f26fe185 Fixed: Updates to System > More Info (#67) 2021-06-06 16:11:06 -05:00
bakerboy448
5f4218ae91 add indexer request template [skip ci] (#116) 2021-06-06 16:10:51 -05:00
Qstick
30b54d8340 Fix Filelist unit tests 2021-06-06 13:33:51 -04:00
Qstick
ee6ae386ca Fixed: (Filelist) Unable to add
Fixes #109
2021-06-06 11:48:52 -04:00
Robin Dadswell
b3fb640969 New: App Profile help text on addition and edit of Indexers and other misc translations 2021-06-05 21:58:53 +01:00
Qstick
8b0a8e82b5 Wikijs Links 2021-06-05 16:37:49 -04:00
Robin Dadswell
f25998959e New: Added all Arr donation links 2021-06-05 21:15:06 +01:00
Qstick
f56ce129e6 Fixed: Push to client for Cardigann magnet links 2021-06-05 14:55:43 -04:00
Qstick
ae9930a03f Update ZonaQ.cs 2021-06-05 10:20:54 -04:00
Qstick
85be0be455 Fixed: Push Downloads to client fails for download overrides 2021-06-05 09:32:40 -04:00
Qstick
cf1c44ed75 Fixed: Normalize definitions when serving local and remote 2021-06-04 19:27:50 -04:00
Robin Dadswell
f062fafe82 Fixed: Error when trying to parse the value 'Unknown' as an IP Address 2021-06-05 00:18:12 +01:00
Qstick
1032d8b3ab Fixed: Slash on ProwlarrURL causes App failures 2021-06-04 19:13:01 -04:00
Qstick
99c4ed7dbc Fixed: Host not set for UI Search 2021-06-03 19:40:53 -04:00
300 changed files with 14492 additions and 1914 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: Prowlarr # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: prowlarr
ko_fi: # Replace with a single Ko-fi username

View File

@@ -1,36 +0,0 @@
---
name: Bug Report
about: Support Requests will be closed immediately, if you are not 100% certain this is a bug please go to our Reddit or Discord first. Exceptions do not mean you found a bug!
title: ''
labels: 'Type: Bug'
assignees: ''
---
<!-- Support Requests will be closed immediately, if you are unsure go to our Reddit or Discord first. Exceptions do not mean you found a bug! -->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
<!-- Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error -->
**Expected behavior**
<!-- A clear and concise description of what you expected to happen.-->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem.-->
**Platform Information (please complete the following information):**
- OS: <!-- [e.g. Windows 10 2004 / Ubuntu 20.04] -->
- Docker: <!-- [Yes/No] -->
- .NET Version (System -> Status): <!--[e.g. .NET 5.0.1] -->
- Browser and Version (Only needed for UI issues): <!--[e.g. chrome 86.0.4240.198] -->
- Prowlarr Version: <!--[e.g. 0.1.2.1854-->
- Prowlarr Branch: <!--[e.g. develop, nightly]-->
Turn on Trace logs under Settings -> General and wait for the bug to occur again.
**Upload the full log file here (or another site (e.g. pastebin) and link it). Issues will be closed, if they do not include this!**
<!-- Trace logs are named Prowlarr.trace.txt or Prowlarr.trace.#.txt and will contain "trace" in them-->

74
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
name: Bug Report
title: "[BUG]: "
description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Reddit or Discord first'
labels: ['Type: Bug', 'Status: Needs Triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this config...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: Environment
description: |
examples:
- **OS**: Ubuntu 20.04
- **Prowlarr**: Prowlarr 0.1.0.650
- **Docker Install**: Yes
- **Using Reverse Proxy**: No
- **Browser**: Firefox 90 (If UI related)
value: |
- OS:
- Prowlarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
render: markdown
validations:
required: true
- type: dropdown
attributes:
label: What branch are you running?
options:
- Master
- Develop
- Nightly
- Other (This issue will be closed)
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Trace Logs (https://wiki.servarr.com/prowlarr/troubleshooting#logging-and-log-files)
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: true

View File

@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Indexer Requests
url: https://requests.prowlarr.com/
about: Request new indexers to be added. Vote on existing requests.
- name: Support via Discord
url: https://prowlarr.com/discord
about: Chat with users and devs on support and setup related topics.

View File

@@ -1,20 +0,0 @@
---
name: Feature Request
about: Suggest an idea for Prowlarr
title: ''
labels: 'Type: Feature Request'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->

View File

@@ -0,0 +1,39 @@
name: Feature Request
title: "[FEAT]: "
description: 'Suggest an idea for Prowlarr'
labels: ['Type: Feature Request', 'Status: Needs Triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the feature you are requesting.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe
description: A clear and concise description of what the problem is.
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: true

View File

@@ -1,14 +1,15 @@
#### Database Migration
YES | NO
YES - XXXX | NO
#### Description
A few sentences describing the overall goals of the pull request's commits.
#### Screenshot (if UI related)
#### Todos
- [ ] Tests
- [ ] Translation Keys
- [ ] Wiki Updates
- [ ] Translation Keys (./src/NzbDrone.Core/Localization/Core/en.json)
- [ ] [Wiki Updates](https://wiki.servarr.com)
#### Issues Fixed or Closed by this PR

41
.github/workflows/azuresync.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Sync issue to Azure DevOps work item
on:
issues:
types:
[opened, edited, deleted, closed, reopened, labeled, unlabeled, assigned]
concurrency: azuresync-${{ github.event.issue.number }}
jobs:
alert:
runs-on: ubuntu-latest
steps:
- uses: danhellem/github-actions-issue-to-work-item@master
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == true }}"
env:
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
github_token: "${{ github.token }}"
ado_organization: "Servarr"
ado_project: "Servarr"
ado_area_path: "Servarr\\Prowlarr"
ado_wit: "Bug"
ado_new_state: "New"
ado_active_state: "Active"
ado_close_state: "Closed"
ado_bypassrules: true
log_level: 100
- uses: danhellem/github-actions-issue-to-work-item@master
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == false }}"
env:
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
github_token: "${{ github.token }}"
ado_organization: "Servarr"
ado_project: "Servarr"
ado_area_path: "Servarr\\Prowlarr"
ado_wit: "User Story"
ado_new_state: "New"
ado_active_state: "Active"
ado_close_state: "Closed"
ado_bypassrules: true
log_level: 100

View File

@@ -2,12 +2,30 @@
We're always looking for people to help make Prowlarr even better, there are a number of ways to contribute.
This file is updated on an ad-hoc basis, for the latest details please see the [contributing wiki page](https://wiki.servarr.com/prowlarr/contributing).
## Documentation ##
Setup guides, FAQ, the more information we have on the wiki the better.
Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/prowlarr) the better.
## Development ##
See the readme for information on setting up your development environment.
### Tools required ###
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
- [Git](https://git-scm.com/downloads)
- [NodeJS](https://nodejs.org/en/download/) (Node 12.X.X or higher)
- [Yarn](https://yarnpkg.com/)
- .NET Core 5.0.
### Getting started ###
1. Fork Prowlarr
2. Clone the repository into your development machine. [*info*](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository-from-github)
3. Install the required Node Packages `yarn install`
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
5. Build the project in Visual Studio, Setting startup project to `Prowlarr.Console` and framework to `net5.0`
6. Debug the project in Visual Studio
7. Open http://localhost:9696
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Prowlarr/Prowlarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
@@ -20,6 +38,10 @@ See the readme for information on setting up your development environment.
- One feature/bug fix per pull request to keep things clean and easy to understand
- Use 4 spaces instead of tabs, this is the default for VS 2019 and WebStorm (to my knowledge)
### Contributing Indexers ###
- If you're contributing an indexer please phrase your commit as something like: `New: (Indexer) {Indexer Name}`, `New: (Indexer) {Usenet|Torrent} {Indexer Name}`, `New: (Indexer) {Torznab|Newznab} {Indexer Name}`
- If you're updating an indexer please phrase your commit as something like: `Fixed: (Indexer) {Indexer Name} {changes}` e.g. `Fixed: (Indexer) Changed BHD to use API`
### Pull Requesting ###
- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it
- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability

View File

@@ -2,7 +2,7 @@
[![Build Status](https://dev.azure.com/Prowlarr/Prowlarr/_apis/build/status/Prowlarr.Prowlarr?branchName=develop)](https://dev.azure.com/Prowlarr/Prowlarr/_build/latest?definitionId=1&branchName=develop)
[![Translated](https://translate.servarr.com/widgets/servarr/-/prowlarr/svg-badge.svg)](https://translate.servarr.com/engage/prowlarr/?utm_source=widget)
[![Docker Pulls](https://img.shields.io/docker/pulls/hotio/prowlarr.svg)](https://wiki.servarr.com/Prowlarr_Installation#Docker)
[![Docker Pulls](https://img.shields.io/docker/pulls/hotio/prowlarr.svg)](https://wiki.servarr.com/prowlarr/installation#docker)
![Github Downloads](https://img.shields.io/github/downloads/Prowlarr/Prowlarr/total.svg)
[![Backers on Open Collective](https://opencollective.com/Prowlarr/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/Prowlarr/sponsors/badge.svg)](#sponsors)
@@ -10,12 +10,14 @@
Prowlarr is a indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports both Torrent Trackers and Usenet Indexers. It integrates seamlessly with Sonarr, Radarr, Lidarr, and Readarr offering complete management of your indexers with no per app Indexer setup required (we do it all).
## Major Features Include:
- Usenet support for any Newznab compatible indexer, including Headphones VIP
- Torrent support 400+ trackers & more coming soon
- Usenet support for 24 indexers natively, including Headphones VIP, and support for any Newznab compatible indexer via "Generic Newznab"
- Torrent support for over 500 trackers with more added all the time
- Torrent support for any Torznab compatible tracker via "Generic Torznab"
- Indexer Sync to Sonarr/Radarr/Readarr/Lidarr, so no manual configuration of the other applications are required
- Indexer History and Statistics
- Manual Searching of Trackers & Indexers at a category level
- Support for pushing releases directly to your download clients from Prowlarr
- Indexer health and status notifications
## Support
Note: Prowlarr is currently early in life, thus bugs should be expected
@@ -23,11 +25,14 @@ Note: Prowlarr is currently early in life, thus bugs should be expected
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60)](https://prowlarr.com/discord)
[![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60)](https://www.reddit.com/r/Prowlarr)
[![GitHub - Bugs and Feature Requests Only](https://img.shields.io/badge/github-issues-red.svg?maxAge=60)](https://github.com/Prowlarr/Prowlarr/issues)
[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/Prowlarr)
[![Wiki](https://img.shields.io/badge/servarr-wiki-181717.svg?maxAge=60)](https://wiki.servarr.com/prowlarr)
## Feature Requests
## Indexers/Trackers
[Feature Requests](https://github.com/Prowlarr/Prowlarr/issues/new?assignees=&template=feature_request.md&Type%3A%20Feature%20Request&title=)
[Supported Indexers](https://wiki.servarr.com/en/prowlarr/supported-indexers)
[Indexer Requests](https://requests.prowlarr.com)
- Request or vote on an existing request for a new tracker/indexer
## Contributors & Developers
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).

View File

@@ -13,7 +13,7 @@ variables:
buildName: '$(Build.SourceBranchName).$(prowlarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '5.0.203'
dotnetVersion: '5.0.302'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
trigger:
@@ -879,7 +879,7 @@ stages:
artifactName: 'WindowsAutomationScreenshots'
targetPath: $(Build.SourcesDirectory)
- checkout: none
- powershell: |
- pwsh: |
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Servarr/AzureDiscordNotify/master/DiscordNotify.ps1'))
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)

View File

@@ -23,6 +23,16 @@ class BarChart extends Component {
this.myChart = new Chart(this.canvasRef.current, {
type: 'bar',
options: {
x: {
ticks: {
stepSize: this.props.stepSize
}
},
y: {
ticks: {
stepSize: this.props.stepSize
}
},
indexAxis: this.props.horizontal ? 'y' : 'x',
maintainAspectRatio: false,
plugins: {
@@ -64,7 +74,8 @@ BarChart.propTypes = {
horizontal: PropTypes.bool,
legend: PropTypes.bool,
title: PropTypes.string.isRequired,
kind: PropTypes.oneOf(kinds.all).isRequired
kind: PropTypes.oneOf(kinds.all).isRequired,
stepSize: PropTypes.number
};
BarChart.defaultProps = {
@@ -72,7 +83,8 @@ BarChart.defaultProps = {
horizontal: false,
legend: false,
title: '',
kind: kinds.INFO
kind: kinds.INFO,
stepSize: 1
};
export default BarChart;

View File

@@ -16,10 +16,16 @@ class StackedBarChart extends Component {
maintainAspectRatio: false,
scales: {
x: {
stacked: true
stacked: true,
ticks: {
stepSize: this.props.stepSize
}
},
y: {
stacked: true
stacked: true,
ticks: {
stepSize: this.props.stepSize
}
}
},
plugins: {
@@ -63,11 +69,13 @@ class StackedBarChart extends Component {
StackedBarChart.propTypes = {
data: PropTypes.object.isRequired,
title: PropTypes.string.isRequired
title: PropTypes.string.isRequired,
stepSize: PropTypes.number
};
StackedBarChart.defaultProps = {
title: ''
title: '',
stepSize: 1
};
export default StackedBarChart;

View File

@@ -129,7 +129,7 @@ class FileBrowserModalContent extends Component {
className={styles.mappedDrivesWarning}
kind={kinds.WARNING}
>
<Link to="https://wiki.servarr.com/Prowlarr_FAQ#Why_cant_Prowlarr_see_my_files_on_a_remote_server">
<Link to="https://wiki.servarr.com/prowlarr/faq#why-cant-prowlarr-see-my-files-on-a-remote-server">
{translate('MappedDrivesRunningAsService')}
</Link>
</Alert>

View File

@@ -25,7 +25,7 @@ function FormInputHelpText(props) {
isCheckInput && styles.isCheckInput
)}
>
{text}
<div dangerouslySetInnerHTML={{ __html: text }} />
{
link ?

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -73,7 +73,7 @@ class HistoryOptions extends Component {
}
HistoryOptions.propTypes = {
historyCleanupDays: PropTypes.bool.isRequired,
historyCleanupDays: PropTypes.number.isRequired,
dispatchSaveGeneralSettings: PropTypes.func.isRequired
};

View File

@@ -20,19 +20,25 @@ import styles from './AddIndexerModalContent.css';
const columns = [
{
name: 'protocol',
label: 'Protocol',
label: translate('Protocol'),
isSortable: true,
isVisible: true
},
{
name: 'name',
label: 'Name',
label: translate('Name'),
isSortable: true,
isVisible: true
},
{
name: 'language',
label: translate('Language'),
isSortable: true,
isVisible: true
},
{
name: 'privacy',
label: 'Privacy',
label: translate('Privacy'),
isSortable: true,
isVisible: true
}

View File

@@ -26,7 +26,8 @@ class SelectIndexerRow extends Component {
const {
protocol,
privacy,
name
name,
language
} = this.props;
return (
@@ -41,6 +42,10 @@ class SelectIndexerRow extends Component {
{name}
</TableRowCell>
<TableRowCell>
{language}
</TableRowCell>
<TableRowCell>
{privacy}
</TableRowCell>
@@ -53,6 +58,7 @@ SelectIndexerRow.propTypes = {
name: PropTypes.string.isRequired,
protocol: PropTypes.string.isRequired,
privacy: PropTypes.string.isRequired,
language: PropTypes.string.isRequired,
implementation: PropTypes.string.isRequired,
onIndexerSelect: PropTypes.func.isRequired
};

View File

@@ -13,6 +13,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import AdvancedSettingsButton from 'Settings/AdvancedSettingsButton';
import translate from 'Utilities/String/translate';
import styles from './EditIndexerModalContent.css';
@@ -31,6 +32,7 @@ function EditIndexerModalContent(props) {
onSavePress,
onTestPress,
onDeleteIndexerPress,
onAdvancedSettingsPress,
...otherProps
} = props;
@@ -99,7 +101,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="redirect"
helpText={'Redirect incoming download requests for indexer instead of Proxying using Prowlarr'}
helpText={translate('RedirectHelpText')}
isDisabled={!supportsRedirect.value}
{...redirect}
onChange={onInputChange}
@@ -113,6 +115,7 @@ function EditIndexerModalContent(props) {
type={inputTypes.APP_PROFILE_SELECT}
name="appProfileId"
{...appProfileId}
helpText={translate('AppProfileSelectHelpText')}
onChange={onInputChange}
/>
</FormGroup>
@@ -164,6 +167,12 @@ function EditIndexerModalContent(props) {
</Button>
}
<AdvancedSettingsButton
advancedSettings={advancedSettings}
onAdvancedSettingsPress={onAdvancedSettingsPress}
showLabel={false}
/>
<SpinnerErrorButton
isSpinning={isTesting}
error={saveError}
@@ -203,6 +212,7 @@ EditIndexerModalContent.propTypes = {
onModalClose: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onTestPress: PropTypes.func.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired,
onDeleteIndexerPress: PropTypes.func
};

View File

@@ -3,6 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveIndexer, setIndexerFieldValue, setIndexerValue, testIndexer } from 'Store/Actions/indexerActions';
import { toggleAdvancedSettings } from 'Store/Actions/settingsActions';
import createIndexerSchemaSelector from 'Store/Selectors/createIndexerSchemaSelector';
import EditIndexerModalContent from './EditIndexerModalContent';
@@ -23,7 +24,8 @@ const mapDispatchToProps = {
setIndexerValue,
setIndexerFieldValue,
saveIndexer,
testIndexer
testIndexer,
toggleAdvancedSettings
};
class EditIndexerModalContentConnector extends Component {
@@ -56,6 +58,11 @@ class EditIndexerModalContentConnector extends Component {
this.props.testIndexer({ id: this.props.id });
}
onAdvancedSettingsPress = () => {
console.log('settings');
this.props.toggleAdvancedSettings();
}
//
// Render
@@ -65,6 +72,7 @@ class EditIndexerModalContentConnector extends Component {
{...this.props}
onSavePress={this.onSavePress}
onTestPress={this.onTestPress}
onAdvancedSettingsPress={this.onAdvancedSettingsPress}
onInputChange={this.onInputChange}
onFieldChange={this.onFieldChange}
/>
@@ -80,6 +88,7 @@ EditIndexerModalContentConnector.propTypes = {
item: PropTypes.object.isRequired,
setIndexerValue: PropTypes.func.isRequired,
setIndexerFieldValue: PropTypes.func.isRequired,
toggleAdvancedSettings: PropTypes.func.isRequired,
saveIndexer: PropTypes.func.isRequired,
testIndexer: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired

View File

@@ -50,7 +50,7 @@ class TagsModalContent extends Component {
render() {
const {
movieTags,
indexerTags,
tagList,
onModalClose
} = this.props;
@@ -108,7 +108,7 @@ class TagsModalContent extends Component {
<div className={styles.result}>
{
movieTags.map((t) => {
indexerTags.map((t) => {
const tag = _.find(tagList, { id: t });
if (!tag) {
@@ -140,7 +140,7 @@ class TagsModalContent extends Component {
return null;
}
if (movieTags.indexOf(t) > -1) {
if (indexerTags.indexOf(t) > -1) {
return null;
}
@@ -179,7 +179,7 @@ class TagsModalContent extends Component {
}
TagsModalContent.propTypes = {
movieTags: PropTypes.arrayOf(PropTypes.number).isRequired,
indexerTags: PropTypes.arrayOf(PropTypes.number).isRequired,
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
onModalClose: PropTypes.func.isRequired,
onApplyTagsPress: PropTypes.func.isRequired

View File

@@ -10,15 +10,15 @@ function createMapStateToProps() {
(state, { indexerIds }) => indexerIds,
createAllIndexersSelector(),
createTagsSelector(),
(indexerIds, allMovies, tagList) => {
const movies = _.intersectionWith(allMovies, indexerIds, (s, id) => {
(indexerIds, allIndexers, tagList) => {
const indexers = _.intersectionWith(allIndexers, indexerIds, (s, id) => {
return s.id === id;
});
const movieTags = _.uniq(_.concat(..._.map(movies, 'tags')));
const indexerTags = _.uniq(_.concat(..._.map(indexers, 'tags')));
return {
movieTags,
indexerTags,
tagList
};
}

View File

@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import withScrollPosition from 'Components/withScrollPosition';
import { testAllIndexers } from 'Store/Actions/indexerActions';
import { saveMovieEditor, setMovieFilter, setMovieSort, setMovieTableOption } from 'Store/Actions/indexerIndexActions';
import { saveIndexerEditor, setMovieFilter, setMovieSort, setMovieTableOption } from 'Store/Actions/indexerIndexActions';
import scrollPositions from 'Store/scrollPositions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createIndexerClientSideCollectionItemsSelector from 'Store/Selectors/createIndexerClientSideCollectionItemsSelector';
@@ -40,8 +40,8 @@ function createMapDispatchToProps(dispatch, props) {
dispatch(setMovieFilter({ selectedFilterKey }));
},
dispatchSaveMovieEditor(payload) {
dispatch(saveMovieEditor(payload));
dispatchSaveIndexerEditor(payload) {
dispatch(saveIndexerEditor(payload));
},
onTestAllPress() {
@@ -56,7 +56,7 @@ class IndexerIndexConnector extends Component {
// Listeners
onSaveSelected = (payload) => {
this.props.dispatchSaveMovieEditor(payload);
this.props.dispatchSaveIndexerEditor(payload);
}
onScroll = ({ scrollTop }) => {
@@ -79,7 +79,7 @@ class IndexerIndexConnector extends Component {
IndexerIndexConnector.propTypes = {
isSmallScreen: PropTypes.bool.isRequired,
dispatchSaveMovieEditor: PropTypes.func.isRequired,
dispatchSaveIndexerEditor: PropTypes.func.isRequired,
items: PropTypes.arrayOf(PropTypes.object)
};

View File

@@ -71,7 +71,7 @@ class IndexerIndexRow extends Component {
const {
id,
name,
baseUrl,
indexerUrls,
enable,
redirect,
tags,
@@ -248,7 +248,7 @@ class IndexerIndexRow extends Component {
className={styles.externalLink}
name={icons.EXTERNAL_LINK}
title={'Website'}
to={baseUrl}
to={indexerUrls[0].replace('api.', '')}
/>
<IconButton
@@ -289,7 +289,7 @@ class IndexerIndexRow extends Component {
IndexerIndexRow.propTypes = {
id: PropTypes.number.isRequired,
baseUrl: PropTypes.string.isRequired,
indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
protocol: PropTypes.string.isRequired,
privacy: PropTypes.string.isRequired,
priority: PropTypes.number.isRequired,

View File

@@ -18,7 +18,7 @@ function IndexerInfoModalContent(props) {
description,
encoding,
language,
baseUrl,
indexerUrls,
protocol,
onModalClose
} = props;
@@ -54,10 +54,10 @@ function IndexerInfoModalContent(props) {
<DescriptionListItemTitle>Indexer Site</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to={baseUrl}>{baseUrl}</Link>
<Link to={indexerUrls[0]}>{indexerUrls[0]}</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>{protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url</DescriptionListItemTitle>
<DescriptionListItemTitle>{`${protocol === 'usenet' ? 'Newznab' : 'Torznab'} Url`}</DescriptionListItemTitle>
<DescriptionListItemDescription>
{`${window.location.origin}${window.Prowlarr.urlBase}/${id}/api`}
</DescriptionListItemDescription>
@@ -74,7 +74,7 @@ IndexerInfoModalContent.propTypes = {
description: PropTypes.string.isRequired,
encoding: PropTypes.string.isRequired,
language: PropTypes.string.isRequired,
baseUrl: PropTypes.string.isRequired,
indexerUrls: PropTypes.arrayOf(PropTypes.string).isRequired,
protocol: PropTypes.string.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -10,7 +10,6 @@ function createMapStateToProps() {
(state) => state.settings.advancedSettings,
createIndexerSelector(),
(advancedSettings, indexer) => {
console.log(indexer);
return {
advancedSettings,
...indexer

View File

@@ -19,6 +19,10 @@ function getAverageResponseTimeData(indexerStats) {
};
});
data.sort((a, b) => {
return b.value - a.value;
});
return data;
}

View File

@@ -26,7 +26,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Protocol
{translate('Protocol')}
</SortMenuItem>
<SortMenuItem
@@ -35,7 +35,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Age
{translate('Age')}
</SortMenuItem>
<SortMenuItem
@@ -53,7 +53,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Indexer
{translate('Indexer')}
</SortMenuItem>
<SortMenuItem
@@ -62,7 +62,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Size
{translate('Size')}
</SortMenuItem>
<SortMenuItem
@@ -71,7 +71,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Files
{translate('Files')}
</SortMenuItem>
<SortMenuItem
@@ -80,7 +80,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Grabs
{translate('Grabs')}
</SortMenuItem>
<SortMenuItem
@@ -89,7 +89,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Peers
{translate('Peers')}
</SortMenuItem>
<SortMenuItem
@@ -98,7 +98,7 @@ function SearchIndexSortMenu(props) {
sortDirection={sortDirection}
onPress={onSortSelect}
>
Category
{translate('Category')}
</SortMenuItem>
</MenuContent>
</SortMenu>

View File

@@ -19,7 +19,7 @@ function NoSearchResults(props) {
return (
<div>
<div className={styles.message}>
No search results found, try performing a new search below.
{translate('NoSearchResultsFound')}
</div>
</div>
);

View File

@@ -4,8 +4,10 @@ import React, { Component } from 'react';
import IndexersSelectInputConnector from 'Components/Form/IndexersSelectInputConnector';
import NewznabCategorySelectInputConnector from 'Components/Form/NewznabCategorySelectInputConnector';
import TextInput from 'Components/Form/TextInput';
import keyboardShortcuts from 'Components/keyboardShortcuts';
import SpinnerButton from 'Components/Link/SpinnerButton';
import PageContentFooter from 'Components/Page/PageContentFooter';
import translate from 'Utilities/String/translate';
import SearchFooterLabel from './SearchFooterLabel';
import styles from './SearchFooter.css';
@@ -38,9 +40,11 @@ class SearchFooter extends Component {
searchQuery
} = this.state;
if (searchQuery !== '' || searchCategories !== [] || searchIndexerIds !== []) {
if (searchQuery !== '' || searchCategories.length > 0 || searchIndexerIds.length > 0) {
this.onSearchPress();
}
this.props.bindShortcut('enter', this.onSearchPress, { isGlobal: true });
}
componentDidUpdate(prevProps) {
@@ -114,6 +118,7 @@ class SearchFooter extends Component {
<TextInput
name='searchQuery'
autoFocus={true}
value={searchQuery}
isDisabled={isFetching}
onChange={onInputChange}
@@ -163,7 +168,7 @@ class SearchFooter extends Component {
isDisabled={isFetching || !hasIndexers}
onPress={this.onSearchPress}
>
Search
{translate('Search')}
</SpinnerButton>
</div>
</div>
@@ -181,7 +186,8 @@ SearchFooter.propTypes = {
onSearchPress: PropTypes.func.isRequired,
hasIndexers: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired,
searchError: PropTypes.object
searchError: PropTypes.object,
bindShortcut: PropTypes.func.isRequired
};
export default SearchFooter;
export default keyboardShortcuts(SearchFooter);

View File

@@ -1,10 +1,22 @@
import PropTypes from 'prop-types';
import React from 'react';
import Label from 'Components/Label';
import { kinds, tooltipPositions } from 'Helpers/Props';
import Tooltip from '../../Components/Tooltip/Tooltip';
function CategoryLabel({ categories }) {
const sortedCategories = categories.filter((cat) => cat.name !== undefined).sort((c) => c.id);
if (categories?.length === 0) {
return (
<Tooltip
anchor={<Label kind={kinds.DANGER}>Unknown</Label>}
tooltip="Please report this issue to the GitHub as this shouldn't be happening"
position={tooltipPositions.LEFT}
/>
);
}
return (
<span>
{
@@ -20,6 +32,10 @@ function CategoryLabel({ categories }) {
);
}
CategoryLabel.defaultProps = {
categories: []
};
CategoryLabel.propTypes = {
categories: PropTypes.arrayOf(PropTypes.object).isRequired
};

View File

@@ -10,7 +10,8 @@ import styles from './AdvancedSettingsButton.css';
function AdvancedSettingsButton(props) {
const {
advancedSettings,
onAdvancedSettingsPress
onAdvancedSettingsPress,
showLabel
} = props;
return (
@@ -43,18 +44,27 @@ function AdvancedSettingsButton(props) {
/>
</span>
<div className={styles.labelContainer}>
<div className={styles.label}>
{advancedSettings ? translate('HideAdvanced') : translate('ShowAdvanced')}
</div>
</div>
{
showLabel &&
<div className={styles.labelContainer}>
<div className={styles.label}>
{advancedSettings ? translate('HideAdvanced') : translate('ShowAdvanced')}
</div>
</div>
}
</Link>
);
}
AdvancedSettingsButton.propTypes = {
advancedSettings: PropTypes.bool.isRequired,
onAdvancedSettingsPress: PropTypes.func.isRequired
onAdvancedSettingsPress: PropTypes.func.isRequired,
showLabel: PropTypes.bool.isRequired
};
AdvancedSettingsButton.defaultProps = {
showLabel: true
};
export default AdvancedSettingsButton;

View File

@@ -18,9 +18,9 @@ import translate from 'Utilities/String/translate';
import styles from './EditApplicationModalContent.css';
const syncLevelOptions = [
{ key: 'disabled', value: 'Disabled' },
{ key: 'addOnly', value: 'Add and Remove Only' },
{ key: 'fullSync', value: 'Full Sync' }
{ key: 'disabled', value: translate('Disabled') },
{ key: 'addOnly', value: translate('AddRemoveOnly') },
{ key: 'fullSync', value: translate('FullSync') }
];
function EditApplicationModalContent(props) {
@@ -53,7 +53,7 @@ function EditApplicationModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{`${id ? 'Edit' : 'Add'} Application`}
{`${id ? translate('Edit') : translate('Add')} ${translate('Application')}`}
</ModalHeader>
<ModalBody>
@@ -94,13 +94,13 @@ function EditApplicationModalContent(props) {
</FormGroup>
<FormGroup>
<FormLabel>{'Sync Level'}</FormLabel>
<FormLabel>{translate('SyncLevel')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
values={syncLevelOptions}
name="syncLevel"
helpText={'Sync Level'}
helpText={`${translate('SyncLevelAddRemove')}<br>${translate('SyncLevelFull')}`}
{...syncLevel}
onChange={onInputChange}
/>

View File

@@ -53,6 +53,9 @@ class AddDownloadClientModalContent extends Component {
<div>
<Alert kind={kinds.INFO}>
<div>
{translate('AddDownloadClientToProwlarr')}
</div>
<div>
{translate('ProwlarrSupportsAnyDownloadClient')}
</div>

View File

@@ -55,7 +55,7 @@ function UpdateSettings(props) {
type={inputTypes.TEXT}
name="branch"
helpText={usingExternalUpdateMechanism ? translate('BranchUpdateMechanism') : translate('BranchUpdate')}
helpLink="https://wiki.servarr.com/Prowlarr_Settings#Updates"
helpLink="https://wiki.servarr.com/prowlarr/settings#updates"
{...branch}
onChange={onInputChange}
readOnly={usingExternalUpdateMechanism}
@@ -92,7 +92,7 @@ function UpdateSettings(props) {
name="updateMechanism"
values={updateOptions}
helpText={translate('UpdateMechanismHelpText')}
helpLink="https://wiki.servarr.com/Prowlarr_Settings#Updates"
helpLink="https://wiki.servarr.com/prowlarr/settings#updates"
onChange={onInputChange}
{...updateMechanism}
/>

View File

@@ -25,8 +25,8 @@ function NotificationEventItems(props) {
<FormLabel>{translate('NotificationTriggers')}</FormLabel>
<div>
<FormInputHelpText
text={translate('NotifcationTriggersHelpText')}
link="https://wiki.servarr.com/Prowlarr_Settings#Connections"
text={translate('NotificationTriggersHelpText')}
link="https://wiki.servarr.com/prowlarr/settings#connections"
/>
<div className={styles.events}>
<div>

View File

@@ -176,7 +176,7 @@ export const SET_MOVIE_SORT = 'indexerIndex/setMovieSort';
export const SET_MOVIE_FILTER = 'indexerIndex/setMovieFilter';
export const SET_MOVIE_VIEW = 'indexerIndex/setMovieView';
export const SET_MOVIE_TABLE_OPTION = 'indexerIndex/setMovieTableOption';
export const SAVE_MOVIE_EDITOR = 'indexerIndex/saveMovieEditor';
export const SAVE_INDEXER_EDITOR = 'indexerIndex/saveIndexerEditor';
export const BULK_DELETE_INDEXERS = 'indexerIndex/bulkDeleteIndexers';
//
@@ -186,14 +186,14 @@ export const setMovieSort = createAction(SET_MOVIE_SORT);
export const setMovieFilter = createAction(SET_MOVIE_FILTER);
export const setMovieView = createAction(SET_MOVIE_VIEW);
export const setMovieTableOption = createAction(SET_MOVIE_TABLE_OPTION);
export const saveMovieEditor = createThunk(SAVE_MOVIE_EDITOR);
export const saveIndexerEditor = createThunk(SAVE_INDEXER_EDITOR);
export const bulkDeleteIndexers = createThunk(BULK_DELETE_INDEXERS);
//
// Action Handlers
export const actionHandlers = handleThunks({
[SAVE_MOVIE_EDITOR]: function(getState, payload, dispatch) {
[SAVE_INDEXER_EDITOR]: function(getState, payload, dispatch) {
dispatch(set({
section,
isSaving: true

View File

@@ -202,7 +202,8 @@ export const defaultState = {
export const persistState = [
'releases.customFilters',
'releases.selectedFilterKey'
'releases.selectedFilterKey',
'releases.columns'
];
//

View File

@@ -13,7 +13,7 @@ function createHealthCheckSelector() {
source: 'UI',
type: 'warning',
message: translate('CouldNotConnectSignalR'),
wikiUrl: 'https://wiki.servarr.com/Prowlarr_System#Could_not_connect_to_signalR'
wikiUrl: 'https://wiki.servarr.com/prowlarr/system#could-not-connect-to-signalr'
});
}

View File

@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import FieldSet from 'Components/FieldSet';
import Link from 'Components/Link/Link';
import translate from 'Utilities/String/translate';
import styles from '../styles.css';
class Donations extends Component {
//
// Render
render() {
return (
<FieldSet legend={translate('Donations')}>
<div className={styles.logoContainer} title="Radarr">
<Link to="https://opencollective.com/radarr">
<img
className={styles.logo}
src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-radarr.png`}
/>
</Link>
</div>
<div className={styles.logoContainer} title="Lidarr">
<Link to="https://opencollective.com/lidarr">
<img
className={styles.logo}
src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-lidarr.png`}
/>
</Link>
</div>
<div className={styles.logoContainer} title="Readarr">
<Link to="https://opencollective.com/readarr">
<img
className={styles.logo}
src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-readarr.png`}
/>
</Link>
</div>
<div className={styles.logoContainer} title="Prowlarr">
<Link to="https://opencollective.com/prowlarr">
<img
className={styles.logo}
src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-prowlarr.png`}
/>
</Link>
</div>
<div className={styles.logoContainer} title="Sonarr">
<Link to="https://opencollective.com/sonarr">
<img
className={styles.logo}
src={`${window.Prowlarr.urlBase}/Content/Images/Icons/logo-sonarr.png`}
/>
</Link>
</div>
</FieldSet>
);
}
}
Donations.propTypes = {
};
export default Donations;

View File

@@ -43,6 +43,7 @@ function getInternalLink(source) {
function getTestLink(source, props) {
switch (source) {
case 'IndexerStatusCheck':
case 'IndexerLongTermStatusCheck':
return (
<SpinnerIconButton
name={icons.TEST}

View File

@@ -15,32 +15,32 @@ class MoreInfo extends Component {
return (
<FieldSet legend={translate('MoreInfo')}>
<DescriptionList>
<DescriptionListItemTitle>Home page</DescriptionListItemTitle>
<DescriptionListItemTitle>{translate('HomePage')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://prowlarr.com/">prowlarr.com</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>Discord</DescriptionListItemTitle>
<DescriptionListItemTitle>{translate('Wiki')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://wiki.servarr.com/prowlarr">wiki.servarr.com/prowlarr</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>{translate('Reddit')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://reddit.com/r/prowlarr">r/prowlarr</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>{translate('Discord')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://prowlarr.com/discord">prowlarr.com/discord</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>Wiki</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://wiki.servarr.com/Prowlarr">wiki.servarr.com/Prowlarr</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>Donations</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://opencollective.com/prowlarr">opencollective.com/prowlarr</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>Source</DescriptionListItemTitle>
<DescriptionListItemTitle>{translate('Source')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://github.com/Prowlarr/Prowlarr/">github.com/Prowlarr/Prowlarr</Link>
</DescriptionListItemDescription>
<DescriptionListItemTitle>Feature Requests</DescriptionListItemTitle>
<DescriptionListItemTitle>{translate('FeatureRequests')}</DescriptionListItemTitle>
<DescriptionListItemDescription>
<Link to="https://github.com/Prowlarr/Prowlarr/issues">github.com/Prowlarr/Prowlarr/issues</Link>
</DescriptionListItemDescription>

View File

@@ -3,6 +3,7 @@ import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import translate from 'Utilities/String/translate';
import AboutConnector from './About/AboutConnector';
import Donations from './Donations/Donations';
import HealthConnector from './Health/HealthConnector';
import MoreInfo from './MoreInfo/MoreInfo';
@@ -18,6 +19,7 @@ class Status extends Component {
<HealthConnector />
<AboutConnector />
<MoreInfo />
<Donations />
</PageContentBody>
</PageContent>
);

View File

@@ -0,0 +1,17 @@
.logo {
margin: auto;
padding: 9px;
}
.logoContainer {
display: inline-block;
margin: 0.5em;
width: 50px;
height: 50px;
outline: none;
border: solid 1px #e6e6e6;
border-radius: 0.5em;
background: #f8f8ff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
cursor: pointer;
}

View File

@@ -24,7 +24,7 @@ class UpdateChanges extends Component {
<ul>
{
changes.map((change, index) => {
const checkChange = change.replace(/#\d{4,5}\b/g, (match, contents) => {
const checkChange = change.replace(/#\d{3,5}\b/g, (match, contents) => {
return `[${match}](https://github.com/Prowlarr/Prowlarr/issues/${match.substring(1)})`;
});

View File

@@ -252,7 +252,7 @@
</span>
<a
href="https://wiki.servarr.com/Prowlarr_FAQ#Help_I_have_locked_my_self_out_of_Prowlarr_and_do_not_know_the_password"
href="https://wiki.servarr.com/prowlarr/faq#help-i-have-locked-myself-out"
class="forgot-password"
>Forgot your password?</a
>

View File

@@ -30,9 +30,9 @@
"@fortawesome/free-regular-svg-icons": "5.15.3",
"@fortawesome/free-solid-svg-icons": "5.15.3",
"@fortawesome/react-fontawesome": "0.1.14",
"@microsoft/signalr": "5.0.6",
"@sentry/browser": "6.3.1",
"@sentry/integrations": "6.3.1",
"@microsoft/signalr": "5.0.8",
"@sentry/browser": "6.10.0",
"@sentry/integrations": "6.10.0",
"chart.js": "3.2.0",
"classnames": "2.3.1",
"clipboard": "2.0.8",
@@ -98,12 +98,12 @@
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
"core-js": "3.11.0",
"css-loader": "5.2.4",
"eslint": "7.25.0",
"eslint": "7.31.0",
"eslint-plugin-filenames": "1.3.2",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-react": "7.23.2",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-react": "7.24.0",
"eslint-plugin-simple-import-sort": "7.0.0",
"esprint": "2.0.0",
"esprint": "3.1.0",
"file-loader": "6.2.0",
"filemanager-webpack-plugin": "5.0.0",
"html-webpack-plugin": "5.3.1",
@@ -125,7 +125,7 @@
"webpack": "5.35.1",
"webpack-cli": "4.6.0",
"webpack-livereload-plugin": "3.0.1",
"stylelint": "13.13.0",
"stylelint": "13.13.1",
"stylelint-order": "4.1.0"
}
}

View File

@@ -94,7 +94,7 @@
<!-- Standard testing packages -->
<ItemGroup Condition="'$(TestProject)'=='true'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="NUnit" Version="3.13.1" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.97" />

View File

@@ -17,6 +17,11 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"http://127.0.0.1:9117/dl/indexername?jackett_apikey=flwjiefewklfjacketmySecretsdfldskjfsdlk&path=we0re9f0sdfbase64sfdkfjsdlfjk&file=The+Torrent+File+Name.torrent")]
[TestCase(@"http://nzb.su/getnzb/2b51db35e1912ffc138825a12b9933d2.nzb&i=37292&r=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"https://horrorcharnel.org/takeloginhorror.php: username=mySecret&password=mySecret&use_sslvalue==&perm_ssl=1&submitme=X&use_ssl=1&returnto=%2F&captchaSelection=1230456")]
[TestCase(@"https://torrentdb.net/login: _token=2b51db35e1912ffc138825a12b9933d2&username=mySecret&password=mySecret&remember=on")]
[TestCase(@" var authkey = ""2b51db35e1910123321025a12b9933d2"";")]
[TestCase(@"https://hd-space.org/index.php?page=login: uid=mySecret&pwd=mySecret")]
[TestCase(@"https://beyond-hd.me/api/torrents/2b51db35e1912ffc138825a12b9933d2")]
// NzbGet
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
@@ -88,5 +93,14 @@ namespace NzbDrone.Common.Test.InstrumentationTests
cleansedMessage.Should().Be(message);
}
[TestCase(@"&useToken=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"&useToken=2b51db35e1910123321025a12b9933d2")]
public void should_not_clean_usetoken(string message)
{
var cleansedMessage = CleanseLogMessage.Cleanse(message);
cleansedMessage.Should().Be(message);
}
}
}

View File

@@ -53,6 +53,16 @@ namespace NzbDrone.Common.Extensions
return dateTime >= afterDateTime && dateTime <= beforeDateTime;
}
public static DateTime EndOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 999);
}
public static DateTime StartOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
}
public static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
}
}

View File

@@ -194,5 +194,21 @@ namespace NzbDrone.Common.Extensions
var inputBytes = encoding.GetBytes(searchString);
return encoding.GetString(WebUtility.UrlDecodeToBytes(inputBytes, 0, inputBytes.Length));
}
public static string CleanFileName(this string name)
{
string result = name;
string[] badCharacters = { "\\", "/", "<", ">", "?", "*", ":", "|", "\"" };
string[] goodCharacters = { "+", "+", "", "", "!", "-", "-", "", "" };
result = result.Replace(": ", " - ");
for (int i = 0; i < badCharacters.Length; i++)
{
result = result.Replace(badCharacters[i], goodCharacters[i]);
}
return result.TrimStart(' ', '.').TrimEnd(' ');
}
}
}

View File

@@ -84,6 +84,13 @@ namespace NzbDrone.Common.Http
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
}
// 302 or 303 should default to GET on redirect even if POST on original
if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.RedirectMethod)
{
request.Method = HttpMethod.GET;
request.ContentData = null;
}
response = await ExecuteRequestAsync(request, cookieContainer);
}
while (response.HasHttpRedirect);

View File

@@ -30,6 +30,7 @@ namespace NzbDrone.Common.Http
public HttpUri Url { get; set; }
public HttpMethod Method { get; set; }
public HttpHeader Headers { get; set; }
public Encoding Encoding { get; set; }
public byte[] ContentData { get; set; }
public string ContentSummary { get; set; }
public bool SuppressHttpError { get; set; }
@@ -75,8 +76,15 @@ namespace NzbDrone.Common.Http
public void SetContent(string data)
{
var encoding = HttpHeader.GetEncodingFromContentType(Headers.ContentType);
ContentData = encoding.GetBytes(data);
if (Encoding != null)
{
ContentData = Encoding.GetBytes(data);
}
else
{
var encoding = HttpHeader.GetEncodingFromContentType(Headers.ContentType);
ContentData = encoding.GetBytes(data);
}
}
public void AddBasicAuthentication(string username, string password)

View File

@@ -47,7 +47,14 @@ namespace NzbDrone.Common.Http
{
if (_content == null)
{
_content = Headers.GetEncodingFromContentType().GetString(ResponseData);
if (Request.Encoding != null)
{
_content = Request.Encoding.GetString(ResponseData);
}
else
{
_content = Headers.GetEncodingFromContentType().GetString(ResponseData);
}
}
return _content;
@@ -62,6 +69,20 @@ namespace NzbDrone.Common.Http
StatusCode == HttpStatusCode.TemporaryRedirect ||
StatusCode == HttpStatusCode.Found;
public string RedirectUrl
{
get
{
var newUrl = Headers["Location"];
if (newUrl == null)
{
return string.Empty;
}
return (Request.Url += new HttpUri(newUrl)).FullUri;
}
}
public string[] GetCookieHeaders()
{
return Headers.GetValues("Set-Cookie") ?? Array.Empty<string>();

View File

@@ -11,13 +11,15 @@ namespace NzbDrone.Common.Instrumentation
private static readonly Regex[] CleansingRules = new[]
{
// Url
new Regex(@"(?<=\?|&|: |;)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&|: |;)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey|account|passwd|pwd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&| )[^=]*?(_?(?<!use)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=authkey = "")(?<secret>[^&=]+?)(?="")", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=beyond-hd\.[a-z]+/api/torrents/)(?<secret>[^&=][a-z0-9]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Path
new Regex(@"""C:\\Users\\(?<secret>[^\""]+?)(\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
@@ -77,7 +79,6 @@ namespace NzbDrone.Common.Instrumentation
private static string CleanseRemoteIP(Match match)
{
var group = match.Groups[1];
var valueAll = match.Value;
var valueIP = group.Value;
if (IPAddress.TryParse(valueIP, out var address) && !address.IsLocalAddress())

View File

@@ -6,11 +6,11 @@
<ItemGroup>
<PackageReference Include="DotNet4.SocksProxy" Version="1.4.0.1" />
<PackageReference Include="DryIoc.dll" Version="4.7.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.7.9" />
<PackageReference Include="Sentry" Version="3.3.3" />
<PackageReference Include="Sentry" Version="3.8.3" />
<PackageReference Include="SharpZipLib" Version="1.3.1" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" />

View File

@@ -0,0 +1,227 @@
using System;
using System.Collections.Generic;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Download
{
[TestFixture]
public class DownloadClientProviderFixture : CoreTest<DownloadClientProvider>
{
private List<IDownloadClient> _downloadClients;
private List<DownloadClientStatus> _blockedProviders;
private int _nextId;
[SetUp]
public void SetUp()
{
_downloadClients = new List<IDownloadClient>();
_blockedProviders = new List<DownloadClientStatus>();
_nextId = 1;
Mocker.GetMock<IDownloadClientFactory>()
.Setup(v => v.GetAvailableProviders())
.Returns(_downloadClients);
Mocker.GetMock<IDownloadClientStatusService>()
.Setup(v => v.GetBlockedProviders())
.Returns(_blockedProviders);
}
private Mock<IDownloadClient> WithUsenetClient(int priority = 0)
{
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
mock.SetupGet(s => s.Definition)
.Returns(Builder<DownloadClientDefinition>
.CreateNew()
.With(v => v.Id = _nextId++)
.With(v => v.Priority = priority)
.Build());
_downloadClients.Add(mock.Object);
mock.SetupGet(v => v.Protocol).Returns(DownloadProtocol.Usenet);
return mock;
}
private Mock<IDownloadClient> WithTorrentClient(int priority = 0)
{
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
mock.SetupGet(s => s.Definition)
.Returns(Builder<DownloadClientDefinition>
.CreateNew()
.With(v => v.Id = _nextId++)
.With(v => v.Priority = priority)
.Build());
_downloadClients.Add(mock.Object);
mock.SetupGet(v => v.Protocol).Returns(DownloadProtocol.Torrent);
return mock;
}
private void GivenBlockedClient(int id)
{
_blockedProviders.Add(new DownloadClientStatus
{
ProviderId = id,
DisabledTill = DateTime.UtcNow.AddHours(3)
});
}
[Test]
public void should_roundrobin_over_usenet_client()
{
WithUsenetClient();
WithUsenetClient();
WithUsenetClient();
WithTorrentClient();
var client1 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
client1.Definition.Id.Should().Be(1);
client2.Definition.Id.Should().Be(2);
client3.Definition.Id.Should().Be(3);
client4.Definition.Id.Should().Be(1);
client5.Definition.Id.Should().Be(2);
}
[Test]
public void should_roundrobin_over_torrent_client()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentClient();
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(2);
client2.Definition.Id.Should().Be(3);
client3.Definition.Id.Should().Be(4);
client4.Definition.Id.Should().Be(2);
client5.Definition.Id.Should().Be(3);
}
[Test]
public void should_roundrobin_over_protocol_separately()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
var client1 = Subject.GetDownloadClient(DownloadProtocol.Usenet);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(1);
client2.Definition.Id.Should().Be(2);
client3.Definition.Id.Should().Be(3);
client4.Definition.Id.Should().Be(2);
}
[Test]
public void should_skip_blocked_torrent_client()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentClient();
GivenBlockedClient(3);
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(2);
client2.Definition.Id.Should().Be(4);
client3.Definition.Id.Should().Be(2);
client4.Definition.Id.Should().Be(4);
}
[Test]
public void should_not_skip_blocked_torrent_client_if_all_blocked()
{
WithUsenetClient();
WithTorrentClient();
WithTorrentClient();
WithTorrentClient();
GivenBlockedClient(2);
GivenBlockedClient(3);
GivenBlockedClient(4);
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(2);
client2.Definition.Id.Should().Be(3);
client3.Definition.Id.Should().Be(4);
client4.Definition.Id.Should().Be(2);
}
[Test]
public void should_skip_secondary_prio_torrent_client()
{
WithUsenetClient();
WithTorrentClient(2);
WithTorrentClient();
WithTorrentClient();
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(3);
client2.Definition.Id.Should().Be(4);
client3.Definition.Id.Should().Be(3);
client4.Definition.Id.Should().Be(4);
}
[Test]
public void should_not_skip_secondary_prio_torrent_client_if_primary_blocked()
{
WithUsenetClient();
WithTorrentClient(2);
WithTorrentClient(2);
WithTorrentClient();
GivenBlockedClient(4);
var client1 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client2 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client3 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client4 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
var client5 = Subject.GetDownloadClient(DownloadProtocol.Torrent);
client1.Definition.Id.Should().Be(2);
client2.Definition.Id.Should().Be(3);
client3.Definition.Id.Should().Be(2);
client4.Definition.Id.Should().Be(3);
}
}
}

View File

@@ -0,0 +1,161 @@
using System;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Download;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Download
{
public class DownloadClientStatusServiceFixture : CoreTest<DownloadClientStatusService>
{
private DateTime _epoch;
[SetUp]
public void SetUp()
{
_epoch = DateTime.UtcNow;
Mocker.GetMock<IRuntimeInfo>()
.SetupGet(v => v.StartTime)
.Returns(_epoch - TimeSpan.FromHours(1));
}
private DownloadClientStatus WithStatus(DownloadClientStatus status)
{
Mocker.GetMock<IDownloadClientStatusRepository>()
.Setup(v => v.FindByProviderId(1))
.Returns(status);
Mocker.GetMock<IDownloadClientStatusRepository>()
.Setup(v => v.All())
.Returns(new[] { status });
return status;
}
private void VerifyUpdate()
{
Mocker.GetMock<IDownloadClientStatusRepository>()
.Verify(v => v.Upsert(It.IsAny<DownloadClientStatus>()), Times.Once());
}
private void VerifyNoUpdate()
{
Mocker.GetMock<IDownloadClientStatusRepository>()
.Verify(v => v.Upsert(It.IsAny<DownloadClientStatus>()), Times.Never());
}
[Test]
public void should_not_consider_blocked_within_5_minutes_since_initial_failure()
{
WithStatus(new DownloadClientStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(4),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(4),
EscalationLevel = 3
});
Subject.RecordFailure(1);
VerifyUpdate();
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().BeNull();
}
[Test]
public void should_consider_blocked_after_5_minutes_since_initial_failure()
{
WithStatus(new DownloadClientStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
VerifyUpdate();
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
}
[Test]
public void should_not_escalate_further_till_after_5_minutes_since_initial_failure()
{
var origStatus = WithStatus(new DownloadClientStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(4),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(4),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().BeNull();
origStatus.EscalationLevel.Should().Be(3);
}
[Test]
public void should_escalate_further_after_5_minutes_since_initial_failure()
{
WithStatus(new DownloadClientStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.EscalationLevel.Should().BeGreaterThan(3);
}
[Test]
public void should_not_escalate_beyond_3_hours()
{
WithStatus(new DownloadClientStatus
{
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
EscalationLevel = 3
});
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
Subject.RecordFailure(1);
var status = Subject.GetBlockedProviders().FirstOrDefault();
status.Should().NotBeNull();
status.DisabledTill.Should().HaveValue();
status.DisabledTill.Should().NotBeAfter(_epoch + TimeSpan.FromHours(3.1));
}
}
}

View File

@@ -33,14 +33,8 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
Subject.Check().ShouldBeWarning();
}
[TestCase("Develop")]
[TestCase("develop")]
public void should_return_error_when_branch_is_v1(string branch)
{
GivenValidBranch(branch);
Subject.Check().ShouldBeError();
}
[TestCase("nightly")]
[TestCase("Nightly")]
public void should_return_no_warning_when_branch_valid(string branch)

View File

@@ -1,4 +1,4 @@
using FluentAssertions;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.HealthCheck;
using NzbDrone.Core.Test.Framework;
@@ -10,9 +10,9 @@ namespace NzbDrone.Core.Test.HealthCheck
{
private const string WikiRoot = "https://wiki.servarr.com/";
[TestCase("I blew up because of some weird user mistake", null, WikiRoot + "Prowlarr_System#i_blew_up_because_of_some_weird_user_mistake")]
[TestCase("I blew up because of some weird user mistake", "#my_health_check", WikiRoot + "Prowlarr_System#my_health_check")]
[TestCase("I blew up because of some weird user mistake", "Custom-Page#my_health_check", WikiRoot + "Custom-Page#my_health_check")]
[TestCase("I blew up because of some weird user mistake", null, WikiRoot + "prowlarr/system#i-blew-up-because-of-some-weird-user-mistake")]
[TestCase("I blew up because of some weird user mistake", "#my-health-check", WikiRoot + "prowlarr/system#my-health-check")]
[TestCase("I blew up because of some weird user mistake", "custom-page#my-health-check", WikiRoot + "prowlarr/custom-page#my-health-check")]
public void should_format_wiki_url(string message, string wikiFragment, string expectedUrl)
{
var subject = new NzbDrone.Core.HealthCheck.HealthCheck(typeof(HealthCheckBase), HealthCheckResult.Warning, message, wikiFragment);

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.FileList;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Test.Framework;
@@ -18,16 +19,42 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
Subject.Settings = new FileListSettings()
{
Passkey = "abcd",
Username = "somename"
Username = "somename",
BaseUrl = "https://filelist.io"
};
Subject.Capabilities = new IndexerCapabilities
{
TvSearchParams = new List<TvSearchParam>
{
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
},
MovieSearchParams = new List<MovieSearchParam>
{
MovieSearchParam.Q, MovieSearchParam.ImdbId
},
MusicSearchParams = new List<MusicSearchParam>
{
MusicSearchParam.Q
},
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
},
Flags = new List<IndexerFlag>
{
IndexerFlag.FreeLeech
}
};
Subject.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD");
Subject.Capabilities.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Filme DVD");
_movieSearchCriteria = new MovieSearchCriteria
{
SearchTerm = "Star Wars",
Categories = new int[] { 2000 }
};
Subject.BaseUrl = "https://filelist.io";
}
private void MovieWithoutIMDB()
@@ -38,7 +65,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
[Test]
public void should_use_categories_for_feed()
{
var results = Subject.GetSearchRequests(new MovieSearchCriteria { Categories = new int[] { 1, 2 } });
var results = Subject.GetSearchRequests(new MovieSearchCriteria { Categories = new int[] { NewznabStandardCategory.MoviesSD.Id, NewznabStandardCategory.MoviesDVD.Id } });
results.GetAllTiers().Should().HaveCount(1);
@@ -50,7 +77,7 @@ namespace NzbDrone.Core.Test.IndexerTests.FileListTests
[Test]
public void should_not_search_by_imdbid_if_not_supported()
{
_movieSearchCriteria.ImdbId = "tt0076759";
_movieSearchCriteria.ImdbId = "0076759";
var results = Subject.GetSearchRequests(_movieSearchCriteria);
results.GetAllTiers().Should().HaveCount(1);

View File

@@ -34,7 +34,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
_movieSearchCriteria = new MovieSearchCriteria
{
Categories = new int[] { 2000, 2010 },
ImdbId = "tt0076759"
ImdbId = "0076759"
};
}

View File

@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
_movieSearchCriteria = new MovieSearchCriteria
{
Categories = new int[] { 2000, 2010 },
ImdbId = "tt0076759"
ImdbId = "0076759"
};
}
@@ -56,7 +56,7 @@ namespace NzbDrone.Core.Test.IndexerTests.HDBitsTests
public void should_search_by_imdbid_if_supported()
{
var results = Subject.GetSearchRequests(_movieSearchCriteria);
var imdbQuery = int.Parse(_movieSearchCriteria.ImdbId.Substring(2));
var imdbQuery = int.Parse(_movieSearchCriteria.ImdbId);
results.GetAllTiers().Should().HaveCount(1);

View File

@@ -1,15 +1,17 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Test.IndexerTests
{
public class TestIndexer : HttpIndexerBase<TestIndexerSettings>
public class TestIndexer : UsenetIndexerBase<TestIndexerSettings>
{
public override string Name => "Test Indexer";
public override string BaseUrl => "http://testindexer.com";
public override string[] IndexerUrls => new string[] { "http://testindexer.com" };
public override string Description => "";
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
@@ -18,8 +20,8 @@ namespace NzbDrone.Core.Test.IndexerTests
public int _supportedPageSize;
public override int PageSize => _supportedPageSize;
public TestIndexer(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
public TestIndexer(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, IValidateNzbs nzbValidationService, Logger logger)
: base(httpClient, eventAggregator, indexerStatusService, configService, nzbValidationService, logger)
{
}

View File

@@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Test.IndexerTests
{
public class TestIndexerSettings : IProviderConfig
public class TestIndexerSettings : IIndexerSettings
{
public NzbDroneValidationResult Validate()
{
@@ -14,5 +12,6 @@ namespace NzbDrone.Core.Test.IndexerTests
}
public string BaseUrl { get; set; }
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
}
}

View File

@@ -6,7 +6,7 @@
<PackageReference Include="Dapper" Version="2.0.78" />
<PackageReference Include="NBuilder" Version="6.1.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.113.0-0" />
<PackageReference Include="YamlDotNet" Version="11.1.1" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Applications
protected readonly IAppIndexerMapService _appIndexerMapService;
protected readonly Logger _logger;
protected static readonly Regex AppIndexerRegex = new Regex(@"(?<indexer>\d*)/api",
protected static readonly Regex AppIndexerRegex = new Regex(@"\/(?<indexer>\d.)\/",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
public abstract string Name { get; }

View File

@@ -114,7 +114,12 @@ namespace NzbDrone.Core.Applications
var prowlarrMappings = indexerMappings.ToDictionary(i => i.RemoteIndexerId, i => i.IndexerId);
//Get Dictionary of Remote Indexers point to Prowlarr and what they are mapped to
var remoteMappings = app.GetIndexerMappings();
var remoteMappings = ExecuteAction(a => a.GetIndexerMappings(), app);
if (remoteMappings == null)
{
continue;
}
//Add mappings if not already in db, these were setup manually in the app or orphaned by a table wipe
foreach (var mapping in remoteMappings)
@@ -214,5 +219,64 @@ namespace NzbDrone.Core.Applications
_logger.Error(ex, "An error occurred while talking to remote application.");
}
}
private TResult ExecuteAction<TResult>(Func<IApplication, TResult> applicationAction, IApplication application)
{
TResult result;
try
{
result = applicationAction(application);
_applicationStatusService.RecordSuccess(application.Definition.Id);
return result;
}
catch (WebException webException)
{
if (webException.Status == WebExceptionStatus.NameResolutionFailure ||
webException.Status == WebExceptionStatus.ConnectFailure)
{
_applicationStatusService.RecordConnectionFailure(application.Definition.Id);
}
else
{
_applicationStatusService.RecordFailure(application.Definition.Id);
}
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
webException.Message.Contains("timed out"))
{
_logger.Warn("{0} server is currently unavailable. {1}", this, webException.Message);
}
else
{
_logger.Warn("{0} {1}", this, webException.Message);
}
}
catch (TooManyRequestsException ex)
{
if (ex.RetryAfter != TimeSpan.Zero)
{
_applicationStatusService.RecordFailure(application.Definition.Id, ex.RetryAfter);
}
else
{
_applicationStatusService.RecordFailure(application.Definition.Id, TimeSpan.FromHours(1));
}
_logger.Warn("API Request Limit reached for {0}", this);
}
catch (HttpException ex)
{
_applicationStatusService.RecordFailure(application.Definition.Id);
_logger.Warn("{0} {1}", this, ex.Message);
}
catch (Exception ex)
{
_applicationStatusService.RecordFailure(application.Definition.Id);
_logger.Error(ex, "An error occurred while talking to remote application.");
}
return default(TResult);
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json.Linq;
using NLog;
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Lidarr
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_lidarrV1Proxy.Test(Settings));
var testIndexer = new IndexerDefinition
{
Id = 0,
Name = "Test",
Protocol = DownloadProtocol.Usenet,
Capabilities = new IndexerCapabilities()
};
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Audio);
try
{
failures.AddIfNotNull(_lidarrV1Proxy.TestConnection(BuildLidarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Lidarr"));
}
return new ValidationResult(failures);
}
@@ -146,7 +165,7 @@ namespace NzbDrone.Core.Applications.Lidarr
Fields = schema.Fields,
};
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/{indexer.Id}/";
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
lidarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Lidarr
return other.EnableRss == EnableRss &&
other.EnableAutomaticSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableInteractiveSearch &&
other.Name == Name &&
other.Implementation == Implementation &&
other.Priority == Priority &&

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Lidarr
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s):// and port if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Lidarr sees it, including http(s)://, port, and urlbase if needed")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Lidarr Server", HelpText = "Lidarr server URL, including http(s):// and port if needed")]

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Lidarr
List<LidarrIndexer> GetIndexerSchema(LidarrSettings settings);
void RemoveIndexer(int indexerId, LidarrSettings settings);
LidarrIndexer UpdateIndexer(LidarrIndexer indexer, LidarrSettings settings);
ValidationFailure Test(LidarrSettings settings);
ValidationFailure TestConnection(LidarrIndexer indexer, LidarrSettings settings);
}
public class LidarrV1Proxy : ILidarrV1Proxy
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Lidarr
return Execute<LidarrIndexer>(request);
}
public ValidationFailure Test(LidarrSettings settings)
public ValidationFailure TestConnection(LidarrIndexer indexer, LidarrSettings settings)
{
var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST);
request.SetContent(indexer.ToJson());
try
{
GetStatus(settings);
Execute<LidarrIndexer>(request);
}
catch (HttpException ex)
{
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Lidarr
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Lidarr cannot connect to Prowlarr");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json.Linq;
using NLog;
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Radarr
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_radarrV3Proxy.Test(Settings));
var testIndexer = new IndexerDefinition
{
Id = 0,
Name = "Test",
Protocol = DownloadProtocol.Usenet,
Capabilities = new IndexerCapabilities()
};
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies);
try
{
failures.AddIfNotNull(_radarrV3Proxy.TestConnection(BuildRadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Radarr"));
}
return new ValidationResult(failures);
}
@@ -146,7 +165,7 @@ namespace NzbDrone.Core.Applications.Radarr
Fields = schema.Fields,
};
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/{indexer.Id}/";
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
radarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Radarr
return other.EnableRss == EnableRss &&
other.EnableAutomaticSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableInteractiveSearch &&
other.Name == Name &&
other.Implementation == Implementation &&
other.Priority == Priority &&

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Radarr
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s):// and port if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Radarr sees it, including http(s)://, port, and urlbase if needed")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Radarr Server", HelpText = "Radarr server URL, including http(s):// and port if needed")]

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Radarr
List<RadarrIndexer> GetIndexerSchema(RadarrSettings settings);
void RemoveIndexer(int indexerId, RadarrSettings settings);
RadarrIndexer UpdateIndexer(RadarrIndexer indexer, RadarrSettings settings);
ValidationFailure Test(RadarrSettings settings);
ValidationFailure TestConnection(RadarrIndexer indexer, RadarrSettings settings);
}
public class RadarrV3Proxy : IRadarrV3Proxy
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Radarr
return Execute<RadarrIndexer>(request);
}
public ValidationFailure Test(RadarrSettings settings)
public ValidationFailure TestConnection(RadarrIndexer indexer, RadarrSettings settings)
{
var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST);
request.SetContent(indexer.ToJson());
try
{
GetStatus(settings);
Execute<RadarrIndexer>(request);
}
catch (HttpException ex)
{
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Radarr
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Radarr cannot connect to Prowlarr");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json.Linq;
using NLog;
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Readarr
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_readarrV1Proxy.Test(Settings));
var testIndexer = new IndexerDefinition
{
Id = 0,
Name = "Test",
Protocol = DownloadProtocol.Usenet,
Capabilities = new IndexerCapabilities()
};
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.Books);
try
{
failures.AddIfNotNull(_readarrV1Proxy.TestConnection(BuildReadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Readarr"));
}
return new ValidationResult(failures);
}
@@ -146,7 +165,7 @@ namespace NzbDrone.Core.Applications.Readarr
Fields = schema.Fields,
};
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/{indexer.Id}/";
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
readarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Readarr
return other.EnableRss == EnableRss &&
other.EnableAutomaticSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableInteractiveSearch &&
other.Name == Name &&
other.Implementation == Implementation &&
other.Priority == Priority &&

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Readarr
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s):// and port if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Readarr sees it, including http(s)://, port, and urlbase if needed")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Readarr Server", HelpText = "Readarr server URL, including http(s):// and port if needed")]

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Readarr
List<ReadarrIndexer> GetIndexerSchema(ReadarrSettings settings);
void RemoveIndexer(int indexerId, ReadarrSettings settings);
ReadarrIndexer UpdateIndexer(ReadarrIndexer indexer, ReadarrSettings settings);
ValidationFailure Test(ReadarrSettings settings);
ValidationFailure TestConnection(ReadarrIndexer indexer, ReadarrSettings settings);
}
public class ReadarrV1Proxy : IReadarrV1Proxy
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Readarr
return Execute<ReadarrIndexer>(request);
}
public ValidationFailure Test(ReadarrSettings settings)
public ValidationFailure TestConnection(ReadarrIndexer indexer, ReadarrSettings settings)
{
var request = BuildRequest(settings, $"/api/v1/indexer/test", HttpMethod.POST);
request.SetContent(indexer.ToJson());
try
{
GetStatus(settings);
Execute<ReadarrIndexer>(request);
}
catch (HttpException ex)
{
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Readarr
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Readarr cannot connect to Prowlarr");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json.Linq;
using NLog;
@@ -31,7 +32,25 @@ namespace NzbDrone.Core.Applications.Sonarr
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_sonarrV3Proxy.Test(Settings));
var testIndexer = new IndexerDefinition
{
Id = 0,
Name = "Test",
Protocol = DownloadProtocol.Usenet,
Capabilities = new IndexerCapabilities()
};
testIndexer.Capabilities.Categories.AddCategoryMapping(1, NewznabStandardCategory.TV);
try
{
failures.AddIfNotNull(_sonarrV3Proxy.TestConnection(BuildSonarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Sonarr"));
}
return new ValidationResult(failures);
}
@@ -146,7 +165,7 @@ namespace NzbDrone.Core.Applications.Sonarr
Fields = schema.Fields,
};
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl}/{indexer.Id}/";
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "baseUrl").Value = $"{Settings.ProwlarrUrl.TrimEnd('/')}/{indexer.Id}/";
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiPath").Value = "/api";
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "apiKey").Value = _configFileProvider.ApiKey;
sonarrIndexer.Fields.FirstOrDefault(x => x.Name == "categories").Value = JArray.FromObject(indexer.Capabilities.Categories.SupportedCategories(Settings.SyncCategories.ToArray()));

View File

@@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Sonarr
return other.EnableRss == EnableRss &&
other.EnableAutomaticSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableAutomaticSearch &&
other.EnableInteractiveSearch == EnableInteractiveSearch &&
other.Name == Name &&
other.Implementation == Implementation &&
other.Priority == Priority &&

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Applications.Sonarr
public IEnumerable<int> SyncCategories { get; set; }
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s):// and port if needed")]
[FieldDefinition(0, Label = "Prowlarr Server", HelpText = "Prowlarr server URL as Sonarr sees it, including http(s)://, port, and urlbase if needed")]
public string ProwlarrUrl { get; set; }
[FieldDefinition(1, Label = "Sonarr Server", HelpText = "Sonarr server URL, including http(s):// and port if needed")]

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Applications.Sonarr
List<SonarrIndexer> GetIndexerSchema(SonarrSettings settings);
void RemoveIndexer(int indexerId, SonarrSettings settings);
SonarrIndexer UpdateIndexer(SonarrIndexer indexer, SonarrSettings settings);
ValidationFailure Test(SonarrSettings settings);
ValidationFailure TestConnection(SonarrIndexer indexer, SonarrSettings settings);
}
public class SonarrV3Proxy : ISonarrV3Proxy
@@ -91,11 +91,15 @@ namespace NzbDrone.Core.Applications.Sonarr
return Execute<SonarrIndexer>(request);
}
public ValidationFailure Test(SonarrSettings settings)
public ValidationFailure TestConnection(SonarrIndexer indexer, SonarrSettings settings)
{
var request = BuildRequest(settings, $"/api/v3/indexer/test", HttpMethod.POST);
request.SetContent(indexer.ToJson());
try
{
GetStatus(settings);
Execute<SonarrIndexer>(request);
}
catch (HttpException ex)
{
@@ -105,8 +109,14 @@ namespace NzbDrone.Core.Applications.Sonarr
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Sonarr cannot connect to Prowlarr");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ApiKey", "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{

View File

@@ -1,11 +1,7 @@
using System;
using System.Linq;
using System.Xml.Linq;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Authentication
{

View File

@@ -180,7 +180,7 @@ namespace NzbDrone.Core.Configuration
public bool AnalyticsEnabled => GetValueBoolean("AnalyticsEnabled", true, persist: false);
// TODO: Change back to "master" for the first stable release.
public string Branch => GetValue("Branch", "nightly").ToLowerInvariant();
public string Branch => GetValue("Branch", "develop").ToLowerInvariant();
public string LogLevel => GetValue("LogLevel", "info").ToLowerInvariant();
public string ConsoleLogLevel => GetValue("ConsoleLogLevel", string.Empty, persist: false);

View File

@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Configuration
var releaseInfoPath = Path.Combine(bin, "release_info");
PackageUpdateMechanism = UpdateMechanism.BuiltIn;
DefaultBranch = "nightly";
DefaultBranch = "develop";
if (Path.GetFileName(bin) == "bin" && diskProvider.FileExists(packageInfoPath))
{

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Data;
using System.Text.Json;
using Dapper;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Datastore.Converters
{
public class CookieConverter : SqlMapper.TypeHandler<IDictionary<string, string>>
{
protected readonly JsonSerializerOptions SerializerSettings;
public CookieConverter()
{
var serializerSettings = new JsonSerializerOptions
{
AllowTrailingCommas = true,
IgnoreNullValues = true,
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
SerializerSettings = serializerSettings;
}
public override void SetValue(IDbDataParameter parameter, IDictionary<string, string> value)
{
parameter.Value = JsonSerializer.Serialize(value, SerializerSettings);
}
public override IDictionary<string, string> Parse(object value)
{
return JsonSerializer.Deserialize<Dictionary<string, string>>((string)value, SerializerSettings);
}
}
}

View File

@@ -108,10 +108,10 @@ namespace NzbDrone.Core.Datastore
if (OsInfo.IsOsx)
{
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/Prowlarr_FAQ#I_use_Prowlarr_on_a_Mac_and_it_suddenly_stopped_working_What_happened", e, fileName);
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-use-prowlarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", e, fileName);
}
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/Prowlarr_FAQ#I_am_getting_an_error_Database_disk_image_is_malformed", e, fileName);
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/prowlarr/faq#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
}
catch (Exception e)
{

View File

@@ -1,6 +1,3 @@
using System;
using System.Collections.Generic;
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;

View File

@@ -1,5 +1,4 @@
using FluentMigrator;
using Newtonsoft.Json.Linq;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration

View File

@@ -0,0 +1,63 @@
using System.Data;
using FluentMigrator;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(8)]
public class redacted_api : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(MigrateToRedactedApi);
}
private void MigrateToRedactedApi(IDbConnection conn, IDbTransaction tran)
{
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = tran;
cmd.CommandText = "SELECT Id, Settings FROM Indexers WHERE Implementation = 'Redacted'";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var id = reader.GetInt32(0);
var settings = reader.GetString(1);
if (!string.IsNullOrWhiteSpace(settings))
{
var jsonObject = Json.Deserialize<JObject>(settings);
// Remove username
if (jsonObject.ContainsKey("username"))
{
jsonObject.Remove("username");
}
// Remove password
if (jsonObject.ContainsKey("password"))
{
jsonObject.Remove("password");
}
// write new json back to db, switch to new ConfigContract, and disable the indexer
settings = jsonObject.ToJson();
using (var updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Indexers SET Settings = ?, ConfigContract = ?, Enable = 0 WHERE Id = ?";
updateCmd.AddParameter(settings);
updateCmd.AddParameter("RedactedSettings");
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}
}

View File

@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Datastore
.Ignore(i => i.Description)
.Ignore(i => i.Language)
.Ignore(i => i.Encoding)
.Ignore(i => i.BaseUrl)
.Ignore(i => i.IndexerUrls)
.Ignore(i => i.Protocol)
.Ignore(i => i.Privacy)
.Ignore(i => i.SupportsRss)
@@ -100,7 +100,7 @@ namespace NzbDrone.Core.Datastore
SqlMapper.RemoveTypeMap(typeof(DateTime));
SqlMapper.AddTypeHandler(new DapperUtcConverter());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<Dictionary<string, string>>());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<IDictionary<string, string>>());
SqlMapper.AddTypeHandler(new CookieConverter());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<int>>());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<List<KeyValuePair<string, int>>>());
SqlMapper.AddTypeHandler(new EmbeddedDocumentConverter<KeyValuePair<string, int>>());

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public class TorrentBlackhole : TorrentClientBase<TorrentBlackholeSettings>
{
public override bool PreferTorrentFile => true;
public TorrentBlackhole(ITorrentFileInfoReader torrentFileInfoReader,
IHttpClient httpClient,
IConfigService configService,
IDiskProvider diskProvider,
Logger logger)
: base(torrentFileInfoReader, httpClient, configService, diskProvider, logger)
{
}
protected override string AddFromTorrentLink(ReleaseInfo release, string hash, string torrentLink)
{
throw new NotImplementedException("Blackhole does not support redirected indexers.");
}
protected override string AddFromMagnetLink(ReleaseInfo release, string hash, string magnetLink)
{
if (!Settings.SaveMagnetFiles)
{
throw new NotSupportedException("Blackhole does not support magnet links.");
}
var title = release.Title;
title = title.CleanFileName();
var filepath = Path.Combine(Settings.TorrentFolder, $"{title}.{Settings.MagnetFileExtension.Trim('.')}");
var fileContent = Encoding.UTF8.GetBytes(magnetLink);
using (var stream = _diskProvider.OpenWriteStream(filepath))
{
stream.Write(fileContent, 0, fileContent.Length);
}
_logger.Debug("Saving magnet link succeeded, saved to: {0}", filepath);
return null;
}
protected override string AddFromTorrentFile(ReleaseInfo release, string hash, string filename, byte[] fileContent)
{
var title = release.Title;
title = title.CleanFileName();
var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.torrent", title));
using (var stream = _diskProvider.OpenWriteStream(filepath))
{
stream.Write(fileContent, 0, fileContent.Length);
}
_logger.Debug("Torrent Download succeeded, saved to: {0}", filepath);
return null;
}
public override string Name => "Torrent Blackhole";
protected override void Test(List<ValidationFailure> failures)
{
failures.AddIfNotNull(TestFolder(Settings.TorrentFolder, "TorrentFolder"));
}
}
}

View File

@@ -0,0 +1,46 @@
using System.ComponentModel;
using FluentValidation;
using Newtonsoft.Json;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public class TorrentBlackholeSettingsValidator : AbstractValidator<TorrentBlackholeSettings>
{
public TorrentBlackholeSettingsValidator()
{
//Todo: Validate that the path actually exists
RuleFor(c => c.TorrentFolder).IsValidPath();
RuleFor(c => c.MagnetFileExtension).NotEmpty();
}
}
public class TorrentBlackholeSettings : IProviderConfig
{
public TorrentBlackholeSettings()
{
MagnetFileExtension = ".magnet";
}
private static readonly TorrentBlackholeSettingsValidator Validator = new TorrentBlackholeSettingsValidator();
[FieldDefinition(0, Label = "Torrent Folder", Type = FieldType.Path, HelpText = "Folder in which Prowlarr will store the .torrent file")]
public string TorrentFolder { get; set; }
[DefaultValue(false)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[FieldDefinition(1, Label = "Save Magnet Files", Type = FieldType.Checkbox, HelpText = "Save a .magnet file with the magnet link if no .torrent file is available (only useful if the download client supports .magnet files)")]
public bool SaveMagnetFiles { get; set; }
[FieldDefinition(2, Label = "Save Magnet Files", Type = FieldType.Textbox, HelpText = "Extension to use for magnet links, defaults to '.magnet'")]
public string MagnetFileExtension { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

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