1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-18 21:35:51 -04:00

Compare commits

...

131 Commits

Author SHA1 Message Date
Bogdan 204a8bab79 Fixed: (Notifications) Consistency in notification titles 2023-04-23 07:36:08 -07:00
Bogdan 0158c84a98 Fixed: (FileList) Use labels for category options 2023-04-22 22:12:02 -07:00
Bogdan ac51a943fb New: (Notifications) Add Apprise 2023-04-22 21:23:13 -07:00
Servarr 78edc9aa43 Automated API Docs update 2023-04-22 18:48:01 -07:00
Qstick f2bf494cef New: Rescan movie if destination file already exists during import
Closes #8230

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-04-22 20:27:26 -05:00
Qstick 5727e7c43b New: Improve accepted and rejected release logging
Closes #8236

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-04-22 20:23:55 -05:00
Qstick a7ba1a6454 Update SixLabors.ImageSharp, MailKit, DryIoc libraries
Closes #8282

Co-Authored-By: Stepan Goremykin <25577658+goremykin@users.noreply.github.com>
2023-04-22 20:18:22 -05:00
Qstick cc285fab45 Use MinBy and MaxBy instead of OrderBy + First
Co-Authored-By: Stepan Goremykin <25577658+goremykin@users.noreply.github.com>
2023-04-22 20:10:04 -05:00
Bogdan e0ad573e7f New: Add version and timestamp to backup archive
(cherry picked from commit ed3d880974ae6a1430866eebaf72533f35258f6f)
2023-04-22 20:00:45 -05:00
Qstick 9a23b7f0fc New: Improve video stream formatting
(cherry picked from commit 39350ed0de4aca769ef7661f1dce08f9f462e7c3)
2023-04-22 19:59:11 -05:00
Qstick 85aecbe67e New: Improve primary video stream selection
(cherry picked from commit b0834015e7b4bcc37a72cd7d6d47879a6ef2a494)
2023-04-22 19:59:11 -05:00
Qstick bbb20e95af Fixed: DrunkenSlug Default URL
Fixes #8333

Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-04-22 19:59:11 -05:00
Qstick 3fb337e20b Fixed: Tag filtering on iCal feed
Fixes #8359
2023-04-22 19:59:11 -05:00
Weblate 5e63da418e Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Co-authored-by: Deflector8249 <lh2jwko5@gomail.me>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: SHUAI.W <x@ousui.org>
Co-authored-by: Sascha Brockel <gsydaydreamer@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-04-22 17:39:35 -07:00
Qstick 890f9d6fe4 Fixed: Prevent error on manual import processing with multi languages
Closes #7713
2023-04-22 19:36:04 -05:00
Mark McDowall 8a496cbdae New: Don't try to analyze disk image files (iso, img, etc)
(cherry picked from commit 764c08498783865834e607bd41feaaedf69a254a)
2023-04-22 16:41:57 -07:00
Stevie Robinson f54a5388a0 Fixed: Border hover colors in dark theme
(cherry picked from commit bead56893f080a1ac1df230908314f3ba8e0c6ce)
2023-04-22 10:18:21 -07:00
Bogdan 6961633cc9 Serve plain text files (eg. logs) as UTF-8 2023-04-22 10:03:17 -07:00
Qstick 1be450a9d0 Remove mono process detection
(cherry picked from commit 5a046026725084bc880a7b63d7105dcf4d882128)
2023-04-16 19:51:07 -05:00
Bogdan 2b4d6464e2 Rename CC to Cc 2023-04-16 19:50:55 -05:00
Lars ee4c34bd6c New: Option to use Telegram topics for notifications
(cherry picked from commit c8933d812490ba375c6f7e07cd4355921dc513ac)
2023-04-16 17:46:45 -05:00
Qstick 07d41f7902 Bump version to 4.5.0 2023-04-15 10:29:39 -05:00
Qstick bb573594d9 Fix Blocklist Tests 2023-04-13 22:35:22 -05:00
Qstick 12e360ab4f Fixed: Some posters not showing for new movies search results
Fixes #8175

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-04-13 22:09:55 -05:00
Qstick bae555f63e Fixed: Custom Format calculation error on Blocklist by Movie
Fixes #8136
2023-04-13 21:55:01 -05:00
Qstick 31abb93d8c Bump dotnet to 6.0.16 2023-04-13 19:15:09 -05:00
LarsHelo 75035035e1 Fixed: Remote path mapping UI being partially hidden on smaller screens 2023-04-13 19:08:19 -05:00
bakerboy448 c1e5990a58 Update library clean helptext 2023-04-13 19:07:39 -05:00
Weblate 4a42ebe44c Translated using Weblate (German) [skip ci]
Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 90.7% (1052 of 1159 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 92.9% (1077 of 1159 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 95.4% (1106 of 1159 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 90.4% (1048 of 1159 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 94.6% (1097 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.5% (261 of 1159 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 94.3% (1094 of 1159 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.5% (1154 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 21.4% (249 of 1159 strings)

Co-authored-by: Bendik Remoy <Bendikremoy@hotmail.com>
Co-authored-by: Cassio Rizzi <clrizzi@gmail.com>
Co-authored-by: Deflector8249 <lh2jwko5@gomail.me>
Co-authored-by: Elias Benbourenane <eliasbenbourenane@gmail.com>
Co-authored-by: Florian <sephrat.flo@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ivan Mazzoli <dreadtank27@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Michele Caputo <michele@caputoweb.xyz>
Co-authored-by: Nir Israel Hen <nirisraelh@gmail.com>
Co-authored-by: Remy <remy@mrbk.fr>
Co-authored-by: TheHrle <Hpranjkovic@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: federicofortini <federico.fortini@yahoo.it>
Co-authored-by: libsu <libsu@qq.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: tomas15420 <tomas15420@gmail.com>
Co-authored-by: zobe123 <manuel.zobl@gmx.at>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-04-13 19:06:57 -05:00
Qstick c82aa5c2c7 Fixed: Validation for CleanOriginalTitle
Fixes #8331
Closes #8332

Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-04-13 19:03:13 -05:00
Qstick d1bae32e1c Fixed: Correct TitleThe naming token parsing 2023-04-13 18:59:15 -05:00
Qstick c514c7cac0 Fixed: Default value in new Delay Profile 2023-04-13 18:52:13 -05:00
Qstick 3d244057b5 Fixed: Don't grab propers/repacks when item in queue meets cutoff and propers/repacks are not downloaded automatically
Fixes #8134
2023-04-13 18:47:21 -05:00
Bakerboy448 323510300c Fixed: Cleanup erroneous QBittorrent Seeding calls 2023-04-13 18:14:36 -05:00
Bakerboy448 669d87b7ef Fixed: Include Digital Only Releases for Recent Movie determination
Use most recent of physical or digital release date
2023-04-13 18:14:08 -05:00
Bakerboy448 ec7f7b085a New: More information on on why hardlinks should be used over copying
Closes #8327

(cherry picked from commit 83a9d15ff8721c8effdc2c8055e37bfb757022d4)
2023-04-13 18:13:43 -05:00
Bogdan ecc906a754 Fixed: Config file settings do not need to be case-sensitive
(cherry picked from commit 2107635b7e7e5392624f2957af7d7b88ba6be283)
2023-04-11 20:00:35 -05:00
Bogdan d0fcac389c Fixed: Ensure default config file on starting app
(cherry picked from commit 5326a102e23eacfc1132eb544a92af737a531df5)
2023-04-11 20:00:35 -05:00
Qstick 621acbef9a Bump version to 4.4.4 2023-04-09 12:23:51 -05:00
Mark McDowall 7fb1163b23 Fixed: Number input changing while scrolling
(cherry picked from commit cc46ed56b4b70fe1f1443c0a927383f19c989c47)
2023-04-09 12:12:29 -05:00
Sergey M b48eda95dd Fixed: Mapping by MovieTitles collection instead of PrimaryMovieTitle (#8157)
Co-authored-by: Sergey M <msergein>
2023-04-02 16:53:24 -05:00
Mark McDowall 4627093616 Fixed: Multiple Downloaded Episodes Scan commands should not run in parallel
(cherry picked from commit b3d1e4f520d14c41aa6a7dff049ee9b9ef48fecb)
2023-04-02 15:28:14 -05:00
Lagicrus a006984d5e Fixed: Lock rating to 0 decimal places in Discovery (#8279)
* Locks to 1 decimal place instead of infinite
2023-04-02 15:27:36 -05:00
Qstick 7d9183ef12 Fixed: Queue error for language custom format on unknown items 2023-03-29 19:21:35 -05:00
Qstick d35c6683e9 New: Add indexer option for Discord on grab notifications
Fixes #8242

Co-Authored-By: lodu <48859312+lodu@users.noreply.github.com>
2023-03-29 19:01:11 -05:00
Qstick ac26bcddd9 Fixed: Page Plex Watchlist results
Fixes #8223
Fixes #8042
2023-03-29 18:44:18 -05:00
Devin Buhl 15bafce8cc Add Overview to CustomScript and Webhook Notifications (#8239)
* Add Overview to customscript
2023-03-29 18:34:29 -05:00
Qstick 2167da87ce Enable all analyzers and enforce code style on build
Fixes #8201
Fixes #8202
Fixes #8203
Fixes #8204
Fixes #8205
Fixes #8207
Fixes #8208
Fixes #8209
Fixes #8210
Fixes #8211
Fixes #8212
Fixes #8213
Fixes #8214
Fixes #8215
Closes #8216
Fixes #8217
Closes #8218
Fixes #8219
Closes #8220
2023-03-29 18:27:30 -05:00
Mark McDowall 926d37a572 Fixed: Permissions after installing on Windows and opening Firewall port
(cherry picked from commit ff2e8ffc372a34d08028db3c49f603cdfb87d832)
2023-03-29 17:43:11 -05:00
Bogdan 42c9e4e3e5 Fixed: Parsing of RoDubbed releases as Romanian 2023-03-24 20:40:01 -04:00
bakerboy448 89b609a221 Fixed: Improve some request failure messaging
(cherry picked from commit e968919e63616e30cc401964bd51db8e9e0e26de)

Fixes #8152
2023-03-24 20:38:48 -04:00
Qstick dfc9f74116 Fixed broken path tests
Fixes #8132

(cherry picked from commit 5a22afc42bb03c9cdfb0a46d470d084dbdd495d5)
2023-03-12 16:56:29 -05:00
Mark McDowall 189603c756 Fixed: USB drives mounted to folders are treated as different mounts
(cherry picked from commit 75378f7bde90b9d3d9b72404c25c017da2cd147c)
2023-03-12 16:56:29 -05:00
Mark McDowall a78693a2f7 Fixed: Prevent getting disk space from returning no information when it partially fails
(cherry picked from commit 2c65e4fa41418157d0d27b34c3bab80158cff219)
2023-03-12 16:07:22 -05:00
Servarr cea0c5033a Automated API Docs update 2023-03-12 16:02:48 -05:00
Derek Antrican 1e3a42bf42 Implemented OnMovieAdded for Discord 2023-03-12 16:00:41 -05:00
Qstick 030744ab7b Fixed: Indexer Flags CF Scores not shown in Search
Fixes #8165
2023-03-12 15:51:39 -05:00
Qstick 17fda02d8c Fixed: Drag with touch on Profiles page 2023-03-12 15:32:58 -05:00
cicomalieran aabf6b9ff8 Fixed: Processing very long ETA from Transmission
(cherry picked from commit 9800bd6b439257e73e3545e125cd03900a3036bb)
2023-03-12 12:28:33 -05:00
Mark McDowall 7b2fd5140b Switch to eslint for linting
(cherry picked from commit a18c3774661f466727ab46315211aecb43ef1def)
2023-03-08 14:31:03 +00:00
Weblate b6b10d7c6f Translated using Weblate (Croatian) [skip ci]
Currently translated at 19.7% (229 of 1159 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.8% (1146 of 1159 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 95.5% (1107 of 1159 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Update translation files  [skip ci]

Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Spanish) [skip ci]

Currently translated at 98.7% (1145 of 1159 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 16.1% (187 of 1159 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 16.1% (187 of 1159 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 100.0% (1159 of 1159 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 13.2% (153 of 1159 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 13.2% (153 of 1159 strings)

Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

Currently translated at 1.6% (19 of 1159 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 99.8% (1157 of 1159 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 21.4% (249 of 1159 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.1% (257 of 1159 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 98.9% (1147 of 1159 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 90.3% (1047 of 1159 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 87.8% (1018 of 1159 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 87.5% (1015 of 1159 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 89.7% (1040 of 1159 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 90.7% (1052 of 1159 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.8% (1146 of 1159 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 98.8% (1146 of 1159 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 95.5% (1107 of 1159 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 21.8% (253 of 1159 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 92.8% (1076 of 1159 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.8% (1157 of 1159 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 89.9% (1042 of 1159 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 90.7% (1052 of 1159 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 94.3% (1094 of 1159 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 98.5% (1142 of 1159 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.5% (1154 of 1159 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.9% (1158 of 1159 strings)

Added translation using Weblate (Tamil) [skip ci]

Added translation using Weblate (Indonesian) [skip ci]

Added translation using Weblate (Estonian) [skip ci]

Added translation using Weblate (Serbian) [skip ci]

Added translation using Weblate (Croatian) [skip ci]

Added translation using Weblate (Bosnian) [skip ci]

Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

Currently translated at 1.5% (18 of 1157 strings)

Added translation using Weblate (Spanish (Mexico)) [skip ci]

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: TheHrle <Hpranjkovic@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: dtalens <databio@gmail.com>
Co-authored-by: fiego14 <alvaross_96@hotmail.com>
Co-authored-by: libsu <libsu@qq.com>
Co-authored-by: pedrom20 <pedrom20@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_TW/
Translation: Servarr/Radarr
2023-02-27 19:12:11 -06:00
Qstick 16fcf0b56b New: Additional custom filter predicates for strings
(cherry picked from commit 6082253166b67d59d7907d83c362116d47bcdaeb)
2023-02-27 19:10:58 -06:00
Bakerboy448 c222a1a434 New: Use Best PageSize for Newznab/Torznab
Max of Default or Max and no more than 100
2023-02-12 18:34:22 -06:00
Qstick c6e91e028b New: Add Additional Languages
Fixes #6257
Fixes #7967
Closes #7592
Reference #7788

Co-Authored-By: dtalens <6631832+dtalens@users.noreply.github.com>
2023-02-12 15:03:45 -06:00
Bakerboy448 fcf5984944 Fixed: Translations 2023-02-12 13:29:46 -06:00
Mark McDowall fdfe8ca656 New: Return static response to requests while app is starting
(cherry picked from commit 303fc5d786ccf2ad14c8523fc239696c5d37ea53)

Fixes #8079
Closes #8080
2023-02-12 13:29:46 -06:00
Qstick 150a5c1fc6 Bump version to 4.4.2 2023-02-11 13:23:52 -06:00
Matthew Barrington 9ea0957351 New: Add Ireland as a Certification Country (#8085)
Co-authored-by: Matthew Barrington <git@barrington.it>
2023-02-11 12:36:04 -06:00
Weblate 8befa436cc Translated using Weblate (French) [skip ci]
Currently translated at 99.6% (1153 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: KevoM <lilmarsu@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-02-11 12:35:19 -06:00
Qstick 53fdb6f07f Delete azuresync.yml 2023-02-11 10:36:40 -06:00
Servarr 0697dbff96 Automated API Docs update 2023-02-07 20:26:31 -06:00
Qstick 34924859aa Fixed: Settings fail to save for some auth setups
(cherry picked from commit a379d0c403449b2623f84aa6851c850971528ff8)
2023-02-07 20:24:48 -06:00
Qstick 9c86598b54 Fixup language specification tests 2023-02-06 19:38:44 -06:00
Qstick 0fe2262162 Fixed: Releases incorrectly rejected due to language 2023-02-06 19:06:03 -06:00
Qstick 47353aea75 Fixed: Avoid failure on null SceneName 2023-02-05 23:31:00 -06:00
Giulia Petenazzi af43cb2aca New: Added release year to queue ( issue #6330) (#8019) 2023-02-05 19:09:20 -06:00
Fuochi bc838b74c7 Fixed: Remove initial dot in filename (#4509) 2023-02-05 17:22:07 -06:00
Qstick cbcf3d1058 New: Custom Format Updates (#8067) 2023-02-05 17:09:37 -06:00
Qstick c72e64f081 Bump version to 4.4.2 2023-02-04 21:15:36 -06:00
Qstick e09607edb0 Remove old, broken test
Fixes #7186
2023-02-04 21:12:22 -06:00
Winter d91578aee3 Fixed: Releases from PTP showing skewed publish date
PTP returns UTC timestamps, without a timezone specifier. Previously, users
would see skewed publish dates, as the UTC timestamps were being parsed
as if they were in the system's timezone. To fix this, we just assume the
publish date is in UTC.
2023-02-04 17:46:23 -06:00
Mark McDowall affedd7f9d Fixed: Ping endpoint no longer requires authentication
(cherry picked from commit ad42d4a14c814d5911dafb5e78e97ec09b4b13a5)
2023-02-04 17:44:37 -06:00
Qstick c3665e9fea New: Spanish (Latino) languages
Closes #7914
Closes #3467
Closes #6415
2023-02-04 17:42:39 -06:00
Mark McDowall 364d8bd7c5 Fixed: Don't try to remove the same item from queue multiple times
Closes #7932

(cherry picked from commit 2491da067815e129df3a3a79c0cc7221a9d87094)
2023-02-04 17:32:18 -06:00
Mark McDowall 7142d1f224 Improve usage of Original Title renaming token
Closes #7168

Fixed: Don't recursively add the current file name to new file name when '{Original Title}' is used in addition to other naming tokens
(cherry picked from commit ebb48a19cc792c71bfbd57d5f106067190d95339)
2023-02-04 17:26:07 -06:00
Stevie Robinson 86777e021b Fixed: Mass Editor Footer on Smaller Screens
Closes #6968

(cherry picked from commit 9afcec8b1ffc11da93ae50b73f77f5ebe6e12391)
2023-02-04 17:26:07 -06:00
bakerboy448 9d2dacea97 New: Improve Manual Import logging when not parsing files
Closes #8059

(cherry picked from commit 83f63590630ae0728fd9f9f03567a294934eebcc)
2023-02-04 17:26:07 -06:00
Mark McDowall d98c86c3d9 Fixed: Parse year in title from square brackets
(cherry picked from commit 99e60196a4e513d6340a090de4a5517f205e7a29)
2023-02-04 17:22:26 -06:00
Qstick df681d82be Fixed: Update Images on MovieMetadata refresh 2023-02-03 21:37:30 -06:00
Weblate daf81c5b26 Translated using Weblate (French) [skip ci]
Currently translated at 97.5% (1129 of 1157 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 89.9% (1041 of 1157 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 95.2% (1102 of 1157 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 95.5% (1106 of 1157 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 97.4% (1128 of 1157 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 21.4% (248 of 1157 strings)

Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

Currently translated at 1.4% (17 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 94.4% (1093 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 99.9% (1156 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 99.9% (1156 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 90.8% (1051 of 1157 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Florian <sephrat.flo@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Uxose <nathan.renault@live.fr>
Co-authored-by: Vasilis Ieropoulos <kirav96@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: buzzke <buzzke@me.com>
Co-authored-by: hhjuhl <hans@kopula.dk>
Co-authored-by: oskhel <oskar.hellgren@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: ryabov-artem <art.rya@gmail.com>
Co-authored-by: zhuzhe1983 <zhuzhe1983@gmail.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_TW/
Translation: Servarr/Radarr
2023-01-30 22:31:53 -06:00
Zak Saunders 78f929c60b Fixup File Name Tokens (#8036) 2023-01-30 22:30:37 -06:00
Qstick 87d59d12a4 Fixed: Avoid Sqlite Error when all profiles have lowest quality cutoff
(cherry picked from commit  f05e109b50cca496e7b42e2833eff161a43e12f4)
2023-01-26 16:36:25 +00:00
Mark McDowall ce031124c7 Improve handling of releases without video files
New: Show warning in queue if download contains executable or archive file and no video file was detected

(cherry picked from commit b15b6a079846b21cac8476820fce9cde81732291)
2023-01-26 16:36:09 +00:00
Mark McDowall d4ce08a044 Fixed: UTC time sent to UI for already imported message
(cherry picked from commit 3f598ffa6fbec90ecdbb266de4b0fe7558fbbc30)
2023-01-25 13:04:18 +00:00
Mark McDowall 871e78b314 Updated some JS dependencies 2023-01-25 13:03:33 +00:00
Mark McDowall eeee682f6c New: Parse release group from VARYG releases with junk at the end
(cherry picked from commit 5ce8ea8985f880d4e68db852f04558a59461ae3d)
2023-01-25 13:02:25 +00:00
Qstick 9c594c3e53 Bump ImageSharp to 2.1.3
(cherry picked from commit c08b45156425d84e51072093d0ead42f1c105ad5)
2023-01-25 13:02:12 +00:00
voltron4lyfe 0b1b19a165 Fix Filter Button being squished #8024 2023-01-23 21:40:41 -06:00
Weblate f1ff7b3b61 Translated using Weblate (Greek) [skip ci]
Currently translated at 95.2% (1102 of 1157 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 95.5% (1106 of 1157 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 97.4% (1128 of 1157 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 21.4% (248 of 1157 strings)

Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

Currently translated at 1.4% (17 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 94.4% (1093 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 99.9% (1156 of 1157 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 99.9% (1156 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 90.8% (1051 of 1157 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1157 of 1157 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Florian <sephrat.flo@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Vasilis Ieropoulos <kirav96@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: buzzke <buzzke@me.com>
Co-authored-by: oskhel <oskar.hellgren@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: zhuzhe1983 <zhuzhe1983@gmail.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_TW/
Translation: Servarr/Radarr
2023-01-23 19:21:10 -06:00
Robert Dailey 165c588557 Updated .gitignore to ignore .idea/ completely
Unless the repository owners wish to have these files in their repo,
they should be ignored so that contributors are not stepping around
these files.

[skip-ci]
2023-01-24 00:13:47 +00:00
Mark McDowall 327e18bc7a New: Filter by Custom Format Score in Interactive Search
Closes #7825

(cherry picked from commit 998768bcf2c3308611a05a4518e7ef3fbcb473cc)
2023-01-22 18:34:30 -06:00
Qstick f61f2c89dc Remove OMG indexer
Closes #7527

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-01-22 18:27:24 -06:00
Qstick 2327b72558 New: Send additional information with Webhook and Custom Scripts
Closes #7730

Co-Authored-By: Devin Buhl <onedr0p@users.noreply.github.com>
2023-01-22 17:52:54 -06:00
Qstick 66ddd08684 New: Improve logging when processing files for import
Closes #7754
2023-01-22 17:41:24 -06:00
Robert Dailey 4d2143e9b2 Fixed: Unable to load UI if Quality Profiles contain removed Custom Format items
Manually cherry picked from Sonarr commits:

- 2c004e1f9665763111fcd964b81338bdbe735865
- 4b4301a076488c595969921697d7002ca427c955
2023-01-22 16:24:24 -06:00
Qstick 7906ea2a0c Rejection string improvements
Closes #7611
2023-01-22 14:27:15 -06:00
Zak Saunders 9d1956794e Fixed: Progress bar text colour in Dark theme
(cherry picked from commit ca61efa57fc04a7f6753aedb4b8044d17e345429)
2023-01-22 14:05:04 -06:00
voltron4lyfe 4956ff7914 Adding indicator display option to PageMenuButton. 2023-01-22 14:04:15 -06:00
Mark McDowall f22a589cb8 Fixed: Filter indicator in interactive search
(cherry picked from commit 80d36a06c8f42f239304d2f5a7edcb573b5072db)
2023-01-22 14:04:15 -06:00
Qstick 04185d6839 Filter useless PG Errors from coming to Sentry 2023-01-22 11:46:52 -06:00
Qstick fb25e5d577 Fixed: Catch InvalidDataException during initial config to prevent boot loop
[Common]
2023-01-21 13:06:18 -06:00
Qstick 6845eaa9b2 Re-enable some update tests 2023-01-21 13:03:48 -06:00
Qstick c1e65874bc Bump version to 4.4.1 2023-01-21 11:43:48 -06:00
Bakerboy448 226a5da0c9 Fixed: Parse HDCAMRip as CAM 2023-01-21 11:41:37 -06:00
Qstick 685a24e476 Fixed: RemotePathMappingCheck Improvements 2023-01-16 22:45:55 -06:00
Qstick cae4faae61 Fixed: DownloadClientRootFolderCheck Improvements 2023-01-16 22:38:05 -06:00
Qstick 5dac6badf2 Fixed: Ignore movie add errors during collection sync
Fixes #7982
2023-01-11 23:34:21 -06:00
Weblate 5948f56482 Translated using Weblate (Ukrainian) [skip ci]
Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 95.5% (1105 of 1156 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 100.0% (1156 of 1156 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 97.5% (1128 of 1156 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: aenron <1414004038@qq.com>
Co-authored-by: andrey4korop <andrey999@i.ua>
Co-authored-by: jjTogo228 <juniorbiam@gmail.com>
Co-authored-by: verhese <sean.verheyen1@telenet.be>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-01-08 22:28:28 -06:00
Mark McDowall 98ddd0386b Fixed: Trakt connection auth tokens not being refreshed
Closes #7873

(cherry picked from commit d09e5d8eb4097cbba1ee0a668dbb27f941cc4f68)
2023-01-08 22:22:01 -06:00
Mark McDowall 2947b244e4 Fixed: Quality cutoff updating in UI when adding/removing qualities
Closes #7879

(cherry picked from commit fea66cb7bccc7e94523614db38b157fa38f55ea5)
2023-01-08 21:43:55 -06:00
Mark McDowall 72552b8084 New: Option to include movie image for Gotify notifications
Closes #7920

(cherry picked from commit e57e68c97a9d24f8344623ac8f731c2da220686b)
2023-01-08 21:41:08 -06:00
Qstick 09642444d7 Switch Trakt to STJson
Fixes #7913
2023-01-08 21:11:59 -06:00
Qstick d1080b825c Fixed: Truncate custom format card tags
Fixes #7725
Fixes #7973

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-01-08 21:00:43 -06:00
Qstick 001421de10 New: Improve messaging for rejected quality upgrades
Fixes #7461

Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-01-08 20:52:47 -06:00
Qstick bab9b8b36a Add Volta node config
Fixes #7600
Fixes #7747

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-01-08 20:52:47 -06:00
Qstick 0fb738aa2e Fixed: Kodi Metadata Subtitle Language
Fixes #7962

Co-Authored-By: Stevie Robinson <stevie.robinson@gmail.com>
2023-01-08 20:52:47 -06:00
Mark McDowall 4963920a46 New: Added health check warning if SABnzbd sorting is enabled
(cherry picked from commit 61fa1e5e3f00072f0d5f59cc883fac74fe12ee9d)
2023-01-08 20:38:26 -06:00
Qstick f0d10fe1cd Fixed: Correct messaging when release is not upgrade
Fixes #7963
2023-01-08 20:24:13 -06:00
James Hu 386b33b624 New: Include movie title and year when logging report
* Include movie title and year when logging report

* Change verbage

Co-authored-by: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com>
2023-01-05 21:07:59 +00:00
Mark McDowall 98201508f2 New: Description for indexer RSS setting
(cherry picked from commit 396406b2174c4876057175e7537a4718eee2abca)
2023-01-04 10:19:57 +00:00
Qstick 9723c569a1 Bump version to 4.4.0 2023-01-03 18:48:07 -06:00
343 changed files with 4416 additions and 3978 deletions
+15 -11
View File
@@ -19,10 +19,10 @@ indent_size = 4
dotnet_sort_system_directives_first = true dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary # Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:warning dotnet_style_qualification_for_field = false:refactoring
dotnet_style_qualification_for_property = false:warning dotnet_style_qualification_for_property = false:refactoring
dotnet_style_qualification_for_method = false:warning dotnet_style_qualification_for_method = false:refactoring
dotnet_style_qualification_for_event = false:warning dotnet_style_qualification_for_event = false:refactoring
# Indentation preferences # Indentation preferences
csharp_indent_block_contents = true csharp_indent_block_contents = true
@@ -32,6 +32,10 @@ csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true csharp_indent_switch_labels = true
csharp_indent_labels = flush_left csharp_indent_labels = flush_left
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_naming_style.instance_field_style.capitalization = camel_case dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _ dotnet_naming_style.instance_field_style.required_prefix = _
@@ -64,6 +68,7 @@ dotnet_diagnostic.SA1406.severity = suggestion
dotnet_diagnostic.SA1410.severity = suggestion dotnet_diagnostic.SA1410.severity = suggestion
dotnet_diagnostic.SA1411.severity = suggestion dotnet_diagnostic.SA1411.severity = suggestion
dotnet_diagnostic.SA1413.severity = none dotnet_diagnostic.SA1413.severity = none
dotnet_diagnostic.SA1512.severity = none
dotnet_diagnostic.SA1516.severity = none dotnet_diagnostic.SA1516.severity = none
dotnet_diagnostic.SA1600.severity = none dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1601.severity = none dotnet_diagnostic.SA1601.severity = none
@@ -162,6 +167,7 @@ dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = suggestion dotnet_diagnostic.CA1310.severity = suggestion
dotnet_diagnostic.CA1401.severity = suggestion dotnet_diagnostic.CA1401.severity = suggestion
dotnet_diagnostic.CA1416.severity = suggestion dotnet_diagnostic.CA1416.severity = suggestion
dotnet_diagnostic.CA1419.severity = suggestion
dotnet_diagnostic.CA1507.severity = suggestion dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1508.severity = suggestion dotnet_diagnostic.CA1508.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion dotnet_diagnostic.CA1707.severity = suggestion
@@ -177,9 +183,6 @@ dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1721.severity = suggestion dotnet_diagnostic.CA1721.severity = suggestion
dotnet_diagnostic.CA1724.severity = suggestion dotnet_diagnostic.CA1724.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1801.severity = suggestion
dotnet_diagnostic.CA1802.severity = suggestion
dotnet_diagnostic.CA1805.severity = suggestion
dotnet_diagnostic.CA1806.severity = suggestion dotnet_diagnostic.CA1806.severity = suggestion
dotnet_diagnostic.CA1810.severity = suggestion dotnet_diagnostic.CA1810.severity = suggestion
dotnet_diagnostic.CA1812.severity = suggestion dotnet_diagnostic.CA1812.severity = suggestion
@@ -191,13 +194,11 @@ dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion dotnet_diagnostic.CA2007.severity = suggestion
dotnet_diagnostic.CA2008.severity = suggestion dotnet_diagnostic.CA2008.severity = suggestion
dotnet_diagnostic.CA2009.severity = suggestion
dotnet_diagnostic.CA2010.severity = suggestion
dotnet_diagnostic.CA2011.severity = suggestion
dotnet_diagnostic.CA2012.severity = suggestion dotnet_diagnostic.CA2012.severity = suggestion
dotnet_diagnostic.CA2013.severity = suggestion dotnet_diagnostic.CA2013.severity = suggestion
dotnet_diagnostic.CA2100.severity = suggestion dotnet_diagnostic.CA2100.severity = suggestion
@@ -228,6 +229,9 @@ dotnet_diagnostic.CA2243.severity = suggestion
dotnet_diagnostic.CA2244.severity = suggestion dotnet_diagnostic.CA2244.severity = suggestion
dotnet_diagnostic.CA2245.severity = suggestion dotnet_diagnostic.CA2245.severity = suggestion
dotnet_diagnostic.CA2246.severity = suggestion dotnet_diagnostic.CA2246.severity = suggestion
dotnet_diagnostic.CA2249.severity = suggestion
dotnet_diagnostic.CA2251.severity = suggestion
dotnet_diagnostic.CA2254.severity = suggestion
dotnet_diagnostic.CA3061.severity = suggestion dotnet_diagnostic.CA3061.severity = suggestion
dotnet_diagnostic.CA3075.severity = suggestion dotnet_diagnostic.CA3075.severity = suggestion
dotnet_diagnostic.CA3076.severity = suggestion dotnet_diagnostic.CA3076.severity = suggestion
@@ -255,7 +259,7 @@ dotnet_diagnostic.CA5392.severity = suggestion
dotnet_diagnostic.CA5394.severity = suggestion dotnet_diagnostic.CA5394.severity = suggestion
dotnet_diagnostic.CA5397.severity = suggestion dotnet_diagnostic.CA5397.severity = suggestion
dotnet_diagnostic.SYSLIB0006.severity = none
[*.{js,html,js,hbs,less,css}] [*.{js,html,js,hbs,less,css}]
charset = utf-8 charset = utf-8
-9
View File
@@ -1,9 +0,0 @@
{
"paths": [
"frontend/src/**/*.js"
],
"ignored": [
"**/node_modules/**/*"
],
"port": 5004
}
-45
View File
@@ -1,45 +0,0 @@
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 }}
permissions: {}
jobs:
alert:
permissions:
issues: write # to update issue body
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\\Radarr"
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\\Radarr"
ado_wit: "User Story"
ado_new_state: "New"
ado_active_state: "Active"
ado_close_state: "Closed"
ado_bypassrules: true
log_level: 100
+2 -21
View File
@@ -166,27 +166,8 @@ packages.config.md5sum
# Common IntelliJ Platform excludes # Common IntelliJ Platform excludes
# User specific # Ignore Rider projects completely for now
**/.idea/**/workspace.xml .idea/
**/.idea/**/tasks.xml
**/.idea/shelf/*
**/.idea/dictionaries
**/.idea/.idea.Radarr.Posix
**/.idea/.idea.Radarr.Windows
# Sensitive or high-churn files
**/.idea/**/dataSources/
**/.idea/**/dataSources.ids
**/.idea/**/dataSources.xml
**/.idea/**/dataSources.local.xml
**/.idea/**/sqlDataSources.xml
**/.idea/**/dynamic.xml
# Rider
# Rider auto-generates .iml files, and contentModel.xml
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
# ignore node_modules symlink # ignore node_modules symlink
node_modules node_modules
+2 -2
View File
@@ -9,13 +9,13 @@ variables:
testsFolder: './_tests' testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '4.3.2' majorVersion: '4.5.0'
minorVersion: $[counter('minorVersion', 2000)] minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)' radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)' buildName: '$(Build.SourceBranchName).$(radarrVersion)'
sentryOrg: 'servarr' sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com' sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.400' dotnetVersion: '6.0.408'
nodeVersion: '16.X' nodeVersion: '16.X'
innoVersion: '6.2.0' innoVersion: '6.2.0'
windowsImage: 'windows-2022' windowsImage: 'windows-2022'
@@ -1,3 +1,4 @@
// eslint-disable-next-line filenames/match-exported
const loaderUtils = require('loader-utils'); const loaderUtils = require('loader-utils');
module.exports = function cssVariablesLoader(source) { module.exports = function cssVariablesLoader(source) {
+4 -2
View File
@@ -56,6 +56,7 @@ class HistoryRow extends Component {
movie, movie,
quality, quality,
customFormats, customFormats,
customFormatScore,
languages, languages,
qualityCutoffNotMet, qualityCutoffNotMet,
eventType, eventType,
@@ -175,7 +176,7 @@ class HistoryRow extends Component {
key={name} key={name}
className={styles.customFormatScore} className={styles.customFormatScore}
> >
{formatCustomFormatScore(data.customFormatScore)} {formatCustomFormatScore(customFormatScore)}
</TableRowCell> </TableRowCell>
); );
} }
@@ -241,8 +242,9 @@ HistoryRow.propTypes = {
movie: PropTypes.object.isRequired, movie: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired, languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired, qualityCutoffNotMet: PropTypes.bool.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
eventType: PropTypes.string.isRequired, eventType: PropTypes.string.isRequired,
sourceTitle: PropTypes.string.isRequired, sourceTitle: PropTypes.string.isRequired,
date: PropTypes.string.isRequired, date: PropTypes.string.isRequired,
+12
View File
@@ -128,6 +128,7 @@ class QueueRow extends Component {
{ {
columns.map((column) => { columns.map((column) => {
const { const {
name, name,
isVisible isVisible
@@ -234,6 +235,16 @@ class QueueRow extends Component {
); );
} }
if (name === 'year') {
return (
<TableRowCell key={name}>
{
movie ? movie.year : ''
}
</TableRowCell>
);
}
if (name === 'title') { if (name === 'title') {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
@@ -362,6 +373,7 @@ QueueRow.propTypes = {
estimatedCompletionTime: PropTypes.string, estimatedCompletionTime: PropTypes.string,
timeleft: PropTypes.string, timeleft: PropTypes.string,
size: PropTypes.number, size: PropTypes.number,
year: PropTypes.number,
sizeleft: PropTypes.number, sizeleft: PropTypes.number,
showRelativeDates: PropTypes.bool.isRequired, showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired, shortDateFormat: PropTypes.string.isRequired,
@@ -113,6 +113,7 @@ class AddNewMovieSearchResult extends Component {
images={images} images={images}
size={250} size={250}
overflow={true} overflow={true}
lazy={false}
/> />
</div> </div>
@@ -162,7 +162,7 @@ class CalendarOptionsModalContent extends Component {
values={weekColumnOptions} values={weekColumnOptions}
value={calendarWeekColumnHeader} value={calendarWeekColumnHeader}
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
helpText={translate('HelpText')} helpText={translate('SettingsWeekColumnHeaderHelpText')}
/> />
</FormGroup> </FormGroup>
@@ -113,10 +113,12 @@ class EnhancedSelectInput extends Component {
this._scheduleUpdate(); this._scheduleUpdate();
} }
if (!Array.isArray(this.props.value) && prevProps.value !== this.props.value) { if (!Array.isArray(this.props.value)) {
this.setState({ if (prevProps.value !== this.props.value || prevProps.values !== this.props.values) {
selectedIndex: getSelectedIndex(this.props) this.setState({
}); selectedIndex: getSelectedIndex(this.props)
});
}
} }
} }
@@ -332,6 +334,11 @@ class EnhancedSelectInput extends Component {
const isMultiSelect = Array.isArray(value); const isMultiSelect = Array.isArray(value);
const selectedOption = getSelectedOption(selectedIndex, values); const selectedOption = getSelectedOption(selectedIndex, values);
let selectedValue = value;
if (!values.length) {
selectedValue = isMultiSelect ? [] : '';
}
return ( return (
<div> <div>
@@ -372,15 +379,17 @@ class EnhancedSelectInput extends Component {
onPress={this.onPress} onPress={this.onPress}
> >
{ {
isFetching && isFetching ?
<LoadingIndicator <LoadingIndicator
className={styles.loading} className={styles.loading}
size={20} size={20}
/> /> :
null
} }
{ {
!isFetching && isFetching ?
null :
<Icon <Icon
name={icons.CARET_DOWN} name={icons.CARET_DOWN}
/> />
@@ -400,7 +409,7 @@ class EnhancedSelectInput extends Component {
onPress={this.onPress} onPress={this.onPress}
> >
<SelectedValueComponent <SelectedValueComponent
value={value} value={selectedValue}
values={values} values={values}
{...selectedValueOptions} {...selectedValueOptions}
{...selectedOption} {...selectedOption}
@@ -418,15 +427,17 @@ class EnhancedSelectInput extends Component {
> >
{ {
isFetching && isFetching ?
<LoadingIndicator <LoadingIndicator
className={styles.loading} className={styles.loading}
size={20} size={20}
/> /> :
null
} }
{ {
!isFetching && isFetching ?
null :
<Icon <Icon
name={icons.CARET_DOWN} name={icons.CARET_DOWN}
/> />
@@ -506,7 +517,7 @@ class EnhancedSelectInput extends Component {
</Manager> </Manager>
{ {
isMobile && isMobile ?
<Modal <Modal
className={styles.optionsModal} className={styles.optionsModal}
size={sizes.EXTRA_SMALL} size={sizes.EXTRA_SMALL}
@@ -557,7 +568,8 @@ class EnhancedSelectInput extends Component {
} }
</Scroller> </Scroller>
</ModalBody> </ModalBody>
</Modal> </Modal> :
null
} }
</div> </div>
); );
@@ -24,7 +24,7 @@ function HintedSelectInputSelectedValue(props) {
> >
<div className={styles.valueText}> <div className={styles.valueText}>
{ {
isMultiSelect && isMultiSelect ?
value.map((key, index) => { value.map((key, index) => {
const v = valuesMap[key]; const v = valuesMap[key];
return ( return (
@@ -32,26 +32,28 @@ function HintedSelectInputSelectedValue(props) {
{v ? v.value : key} {v ? v.value : key}
</Label> </Label>
); );
}) }) :
null
} }
{ {
!isMultiSelect && value isMultiSelect ? null : value
} }
</div> </div>
{ {
hint != null && includeHint && hint != null && includeHint ?
<div className={styles.hintText}> <div className={styles.hintText}>
{hint} {hint}
</div> </div> :
null
} }
</EnhancedSelectInputSelectedValue> </EnhancedSelectInputSelectedValue>
); );
} }
HintedSelectInputSelectedValue.propTypes = { HintedSelectInputSelectedValue.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired, value: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number]))]).isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired, values: PropTypes.arrayOf(PropTypes.object).isRequired,
hint: PropTypes.string, hint: PropTypes.string,
isMultiSelect: PropTypes.bool.isRequired, isMultiSelect: PropTypes.bool.isRequired,
@@ -68,7 +68,7 @@ RootFolderSelectInputOption.propTypes = {
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
freeSpace: PropTypes.number, freeSpace: PropTypes.number,
movieFolder: PropTypes.string, movieFolder: PropTypes.string,
isMissing: PropTypes.boolean, isMissing: PropTypes.bool,
isMobile: PropTypes.bool.isRequired, isMobile: PropTypes.bool.isRequired,
isWindows: PropTypes.bool isWindows: PropTypes.bool
}; };
@@ -112,6 +112,12 @@ class TextInput extends Component {
this._isMouseTarget = false; this._isMouseTarget = false;
}; };
onWheel = () => {
if (this.props.type === 'number') {
this._input.blur();
}
};
// //
// Render // Render
@@ -161,6 +167,7 @@ class TextInput extends Component {
onKeyUp={this.onKeyUp} onKeyUp={this.onKeyUp}
onMouseDown={this.onMouseDown} onMouseDown={this.onMouseDown}
onMouseUp={this.onMouseUp} onMouseUp={this.onMouseUp}
onWheel={this.onWheel}
/> />
); );
} }
+4 -3
View File
@@ -1,6 +1,7 @@
/* eslint-disable no-bitwise */ /* eslint-disable no-bitwise */
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import translate from 'Utilities/String/translate';
import EnhancedSelectInput from './EnhancedSelectInput'; import EnhancedSelectInput from './EnhancedSelectInput';
import styles from './UMaskInput.css'; import styles from './UMaskInput.css';
@@ -101,16 +102,16 @@ class UMaskInput extends Component {
</div> </div>
<div className={styles.details}> <div className={styles.details}>
<div> <div>
<label>UMask</label> <label>{translate('UMask')}</label>
<div className={styles.value}>{umask}</div> <div className={styles.value}>{umask}</div>
</div> </div>
<div> <div>
<label>Folder</label> <label>{translate('Folder')}</label>
<div className={styles.value}>{folder}</div> <div className={styles.value}>{folder}</div>
<div className={styles.unit}>d{formatPermissions(folderNum)}</div> <div className={styles.unit}>d{formatPermissions(folderNum)}</div>
</div> </div>
<div> <div>
<label>File</label> <label>{translate('File')}</label>
<div className={styles.value}>{file}</div> <div className={styles.value}>{file}</div>
<div className={styles.unit}>{formatPermissions(fileNum)}</div> <div className={styles.unit}>{formatPermissions(fileNum)}</div>
</div> </div>
+1 -1
View File
@@ -60,7 +60,7 @@ class FilterMenu extends Component {
iconName={icons.FILTER} iconName={icons.FILTER}
text={translate('Filter')} text={translate('Filter')}
isDisabled={isDisabled} isDisabled={isDisabled}
indicator={selectedFilterKey !== 'all'} showIndicator={selectedFilterKey !== 'all'}
/> />
<FilterMenuContent <FilterMenuContent
@@ -1,11 +1,19 @@
.menuButton { .menuButton {
composes: menuButton from '~./MenuButton.css'; composes: menuButton from '~./MenuButton.css';
position: relative;
&:hover { &:hover {
color: #666; color: #666;
} }
} }
.indicatorContainer {
position: absolute;
top: 10px;
left: 10px;
}
.label { .label {
margin-left: 5px; margin-left: 5px;
} }
+21 -3
View File
@@ -1,13 +1,15 @@
import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import MenuButton from 'Components/Menu/MenuButton'; import MenuButton from 'Components/Menu/MenuButton';
import { icons } from 'Helpers/Props';
import styles from './PageMenuButton.css'; import styles from './PageMenuButton.css';
function PageMenuButton(props) { function PageMenuButton(props) {
const { const {
iconName, iconName,
indicator, showIndicator,
text, text,
...otherProps ...otherProps
} = props; } = props;
@@ -22,6 +24,22 @@ function PageMenuButton(props) {
size={18} size={18}
/> />
{
showIndicator ?
<span
className={classNames(
styles.indicatorContainer,
'fa-layers fa-fw'
)}
>
<Icon
name={icons.CIRCLE}
size={9}
/>
</span> :
null
}
<div className={styles.label}> <div className={styles.label}>
{text} {text}
</div> </div>
@@ -32,11 +50,11 @@ function PageMenuButton(props) {
PageMenuButton.propTypes = { PageMenuButton.propTypes = {
iconName: PropTypes.object.isRequired, iconName: PropTypes.object.isRequired,
text: PropTypes.string, text: PropTypes.string,
indicator: PropTypes.bool.isRequired showIndicator: PropTypes.bool.isRequired
}; };
PageMenuButton.defaultProps = { PageMenuButton.defaultProps = {
indicator: false showIndicator: false
}; };
export default PageMenuButton; export default PageMenuButton;
@@ -9,7 +9,7 @@ import styles from './ToolbarMenuButton.css';
function ToolbarMenuButton(props) { function ToolbarMenuButton(props) {
const { const {
iconName, iconName,
indicator, showIndicator,
text, text,
...otherProps ...otherProps
} = props; } = props;
@@ -26,7 +26,7 @@ function ToolbarMenuButton(props) {
/> />
{ {
indicator && showIndicator &&
<span <span
className={classNames( className={classNames(
styles.indicatorContainer, styles.indicatorContainer,
@@ -53,11 +53,11 @@ function ToolbarMenuButton(props) {
ToolbarMenuButton.propTypes = { ToolbarMenuButton.propTypes = {
iconName: PropTypes.object.isRequired, iconName: PropTypes.object.isRequired,
text: PropTypes.string, text: PropTypes.string,
indicator: PropTypes.bool.isRequired showIndicator: PropTypes.bool.isRequired
}; };
ToolbarMenuButton.defaultProps = { ToolbarMenuButton.defaultProps = {
indicator: false showIndicator: false
}; };
export default ToolbarMenuButton; export default ToolbarMenuButton;
@@ -19,7 +19,7 @@
} }
} }
@media only screen and (max-width: $breakpointLarge) { @media only screen and (max-width: $breakpointExtraLarge) {
.contentFooter { .contentFooter {
flex-wrap: wrap; flex-wrap: wrap;
} }
+5 -1
View File
@@ -20,7 +20,11 @@
.frontTextContainer { .frontTextContainer {
z-index: 1; z-index: 1;
color: var(--white); color: var(--progressBarFrontTextColor);
}
.backTextContainer {
color: var(--progressBarBackTextColor);
} }
.backTextContainer, .backTextContainer,
@@ -73,7 +73,7 @@ function getInfoRowProps(row, props) {
return { return {
title: translate('Ratings'), title: translate('Ratings'),
iconName: icons.HEART, iconName: icons.HEART,
label: `${props.ratings.tmdb.value * 10}%` label: `${(props.ratings.tmdb.value * 10).toFixed()}%`
}; };
} }
@@ -47,6 +47,10 @@ export const possibleFilterTypes = {
{ key: filterTypes.CONTAINS, value: 'contains' }, { key: filterTypes.CONTAINS, value: 'contains' },
{ key: filterTypes.NOT_CONTAINS, value: 'does not contain' }, { key: filterTypes.NOT_CONTAINS, value: 'does not contain' },
{ key: filterTypes.EQUAL, value: 'equal' }, { key: filterTypes.EQUAL, value: 'equal' },
{ key: filterTypes.NOT_EQUAL, value: 'not equal' } { key: filterTypes.NOT_EQUAL, value: 'not equal' },
{ key: filterTypes.STARTS_WITH, value: 'starts with' },
{ key: filterTypes.NOT_STARTS_WITH, value: 'does not start with' },
{ key: filterTypes.ENDS_WITH, value: 'ends with' },
{ key: filterTypes.NOT_ENDS_WITH, value: 'does not end with' }
] ]
}; };
@@ -39,6 +39,22 @@ const filterTypePredicates = {
[filterTypes.NOT_EQUAL]: function(itemValue, filterValue) { [filterTypes.NOT_EQUAL]: function(itemValue, filterValue) {
return itemValue !== filterValue; return itemValue !== filterValue;
},
[filterTypes.STARTS_WITH]: function(itemValue, filterValue) {
return itemValue.toLowerCase().startsWith(filterValue.toLowerCase());
},
[filterTypes.NOT_STARTS_WITH]: function(itemValue, filterValue) {
return !itemValue.toLowerCase().startsWith(filterValue.toLowerCase());
},
[filterTypes.ENDS_WITH]: function(itemValue, filterValue) {
return itemValue.toLowerCase().endsWith(filterValue.toLowerCase());
},
[filterTypes.NOT_ENDS_WITH]: function(itemValue, filterValue) {
return !itemValue.toLowerCase().endsWith(filterValue.toLowerCase());
} }
}; };
+9 -1
View File
@@ -10,6 +10,10 @@ export const LESS_THAN = 'lessThan';
export const LESS_THAN_OR_EQUAL = 'lessThanOrEqual'; export const LESS_THAN_OR_EQUAL = 'lessThanOrEqual';
export const NOT_CONTAINS = 'notContains'; export const NOT_CONTAINS = 'notContains';
export const NOT_EQUAL = 'notEqual'; export const NOT_EQUAL = 'notEqual';
export const STARTS_WITH = 'startsWith';
export const NOT_STARTS_WITH = 'notStartsWith';
export const ENDS_WITH = 'endsWith';
export const NOT_ENDS_WITH = 'notEndsWith';
export const all = [ export const all = [
CONTAINS, CONTAINS,
@@ -23,5 +27,9 @@ export const all = [
IN_LAST, IN_LAST,
NOT_IN_LAST, NOT_IN_LAST,
IN_NEXT, IN_NEXT,
NOT_IN_NEXT NOT_IN_NEXT,
STARTS_WITH,
NOT_STARTS_WITH,
ENDS_WITH,
NOT_ENDS_WITH
]; ];
@@ -64,6 +64,15 @@ const columns = [
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{
name: 'customFormats',
label: React.createElement(Icon, {
name: icons.INTERACTIVE,
title: translate('CustomFormat')
}),
isSortable: true,
isVisible: true
},
{ {
name: 'rejections', name: 'rejections',
label: React.createElement(Icon, { label: React.createElement(Icon, {
@@ -5,8 +5,10 @@
} }
.quality, .quality,
.language { .languages {
composes: cell from '~Components/Table/Cells/TableRowCell.css'; composes: cell from '~Components/Table/Cells/TableRowCell.css';
text-align: center;
} }
.label { .label {
@@ -21,3 +23,7 @@
margin-top: 0; margin-top: 0;
text-align: start; text-align: start;
} }
.customFormatTooltip {
max-width: 250px;
}
@@ -12,6 +12,7 @@ import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal'; import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal'; import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal'; import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage'; import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality'; import MovieQuality from 'Movie/MovieQuality';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
@@ -150,6 +151,7 @@ class InteractiveImportRow extends Component {
languages, languages,
releaseGroup, releaseGroup,
size, size,
customFormats,
rejections, rejections,
isReprocessing, isReprocessing,
isSelected, isSelected,
@@ -226,7 +228,7 @@ class InteractiveImportRow extends Component {
</TableRowCellButton> </TableRowCellButton>
<TableRowCellButton <TableRowCellButton
className={styles.language} className={styles.languages}
title={translate('ClickToChangeLanguage')} title={translate('ClickToChangeLanguage')}
onPress={this.onSelectLanguagePress} onPress={this.onSelectLanguagePress}
> >
@@ -259,7 +261,26 @@ class InteractiveImportRow extends Component {
<TableRowCell> <TableRowCell>
{ {
!!rejections.length && customFormats?.length ?
<Popover
anchor={
<Icon name={icons.INTERACTIVE} />
}
title={translate('Formats')}
body={
<div className={styles.customFormatTooltip}>
<MovieFormats formats={customFormats} />
</div>
}
position={tooltipPositions.LEFT}
/> :
null
}
</TableRowCell>
<TableRowCell>
{
rejections.length ?
<Popover <Popover
anchor={ anchor={
<Icon <Icon
@@ -282,7 +303,9 @@ class InteractiveImportRow extends Component {
</ul> </ul>
} }
position={tooltipPositions.LEFT} position={tooltipPositions.LEFT}
/> canFlip={false}
/> :
null
} }
</TableRowCell> </TableRowCell>
@@ -330,6 +353,7 @@ InteractiveImportRow.propTypes = {
languages: PropTypes.arrayOf(PropTypes.object), languages: PropTypes.arrayOf(PropTypes.object),
releaseGroup: PropTypes.string, releaseGroup: PropTypes.string,
size: PropTypes.number.isRequired, size: PropTypes.number.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
rejections: PropTypes.arrayOf(PropTypes.object).isRequired, rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
isReprocessing: PropTypes.bool, isReprocessing: PropTypes.bool,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
@@ -62,6 +62,7 @@ class MovieHistoryRow extends Component {
sourceTitle, sourceTitle,
quality, quality,
customFormats, customFormats,
customFormatScore,
languages, languages,
qualityCutoffNotMet, qualityCutoffNotMet,
date, date,
@@ -106,7 +107,7 @@ class MovieHistoryRow extends Component {
</TableRowCell> </TableRowCell>
<TableRowCell key={name}> <TableRowCell key={name}>
{formatCustomFormatScore(data.customFormatScore)} {formatCustomFormatScore(customFormatScore)}
</TableRowCell> </TableRowCell>
<RelativeDateCellConnector <RelativeDateCellConnector
@@ -161,7 +162,8 @@ MovieHistoryRow.propTypes = {
sourceTitle: PropTypes.string.isRequired, sourceTitle: PropTypes.string.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired, languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired, customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired, qualityCutoffNotMet: PropTypes.bool.isRequired,
date: PropTypes.string.isRequired, date: PropTypes.string.isRequired,
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
@@ -17,6 +17,10 @@
font-size: 24px; font-size: 24px;
} }
.buttons {
flex: 0 0 auto;
}
.cloneButton { .cloneButton {
composes: button from '~Components/Link/IconButton.css'; composes: button from '~Components/Link/IconButton.css';
@@ -36,3 +40,10 @@
margin: 0; margin: 0;
border: none; border: none;
} }
.label {
@add-mixin truncate;
composes: label from '~Components/Label.css';
max-width: 100%;
}
@@ -90,7 +90,7 @@ class CustomFormat extends Component {
{name} {name}
</div> </div>
<div> <div className={styles.buttons}>
<IconButton <IconButton
className={styles.cloneButton} className={styles.cloneButton}
title={translate('CloneCustomFormat')} title={translate('CloneCustomFormat')}
@@ -124,6 +124,7 @@ class CustomFormat extends Component {
return ( return (
<Label <Label
className={styles.label}
key={index} key={index}
kind={kind} kind={kind}
> >
@@ -8,11 +8,15 @@
} }
.host { .host {
flex: 0 0 300px; @add-mixin truncate;
flex: 0 1 300px;
} }
.path { .path {
flex: 0 0 400px; @add-mixin truncate;
flex: 0 1 400px;
} }
.actions { .actions {
@@ -1,15 +1,20 @@
.remotePathMappingsHeader { .remotePathMappingsHeader {
display: flex; display: flex;
margin-bottom: 10px; margin-bottom: 10px;
padding-right: 24px;
font-weight: bold; font-weight: bold;
} }
.host { .host {
flex: 0 0 300px; @add-mixin truncate;
flex: 0 1 300px;
} }
.path { .path {
flex: 0 0 400px; @add-mixin truncate;
flex: 0 1 400px;
} }
.addRemotePathMapping { .addRemotePathMapping {
@@ -89,6 +89,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup <FormInputGroup
type={inputTypes.CHECK} type={inputTypes.CHECK}
name="enableRss" name="enableRss"
helpText={supportsRss.value ? translate('RSSHelpText') : undefined}
helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')} helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')}
isDisabled={!supportsRss.value} isDisabled={!supportsRss.value}
{...enableRss} {...enableRss}
@@ -30,6 +30,7 @@
code { code {
padding: 0 1px; padding: 0 1px;
border: 1px solid var(--borderColor); border: 1px solid var(--borderColor);
background-color: #f7f7f7; background-color: var(--modalCloseButtonHoverColor);
color: var(--movieBackgroundColor);
} }
} }
@@ -7,11 +7,11 @@
&:hover { &:hover {
.token { .token {
background-color: #ddd; background-color: var(--popoverTitleBackgroundInverseColor);
} }
.example { .example {
background-color: #ccc; background-color: var(--popoverTitleBorderInverseColor);
} }
} }
} }
@@ -27,7 +27,7 @@
.token { .token {
flex: 0 0 50%; flex: 0 0 50%;
padding: 6px 16px; padding: 6px 16px;
background-color: #eee; background-color: var(--popoverTitleBorderColor);
font-family: $monoSpaceFontFamily; font-family: $monoSpaceFontFamily;
} }
@@ -38,7 +38,7 @@
justify-content: space-between; justify-content: space-between;
flex: 0 0 50%; flex: 0 0 50%;
padding: 6px 16px; padding: 6px 16px;
background-color: #ddd; background-color: var(--popoverTitleBackgroundColor);
.footNote { .footNote {
padding: 2px; padding: 2px;
@@ -18,6 +18,7 @@ export const certificationCountryOptions = [
{ key: 'fr', value: 'France' }, { key: 'fr', value: 'France' },
{ key: 'de', value: 'Germany' }, { key: 'de', value: 'Germany' },
{ key: 'gb', value: 'Great Britain' }, { key: 'gb', value: 'Great Britain' },
{ key: 'ie', value: 'Ireland' },
{ key: 'it', value: 'Italy' }, { key: 'it', value: 'Italy' },
{ key: 'es', value: 'Spain' }, { key: 'es', value: 'Spain' },
{ key: 'us', value: 'United States' }, { key: 'us', value: 'United States' },
@@ -191,6 +191,7 @@ const delayProfileShape = {
enableTorrent: PropTypes.shape(boolSettingShape).isRequired, enableTorrent: PropTypes.shape(boolSettingShape).isRequired,
usenetDelay: PropTypes.shape(numberSettingShape).isRequired, usenetDelay: PropTypes.shape(numberSettingShape).isRequired,
torrentDelay: PropTypes.shape(numberSettingShape).isRequired, torrentDelay: PropTypes.shape(numberSettingShape).isRequired,
bypassIfHighestQuality: PropTypes.shape(boolSettingShape).isRequired,
order: PropTypes.shape(numberSettingShape), order: PropTypes.shape(numberSettingShape),
tags: PropTypes.shape(tagSettingShape).isRequired tags: PropTypes.shape(tagSettingShape).isRequired
}; };
@@ -13,6 +13,7 @@ const newDelayProfile = {
preferredProtocol: 'usenet', preferredProtocol: 'usenet',
usenetDelay: 0, usenetDelay: 0,
torrentDelay: 0, torrentDelay: 0,
bypassIfHighestQuality: false,
tags: [] tags: []
}; };
+3 -3
View File
@@ -1,6 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { DndProvider } from 'react-dnd'; import { DndProvider } from 'react-dnd-multi-backend';
import { HTML5Backend } from 'react-dnd-html5-backend'; import HTML5toTouch from 'react-dnd-multi-backend/dist/esm/HTML5toTouch';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import PageContent from 'Components/Page/PageContent'; import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody'; import PageContentBody from 'Components/Page/PageContentBody';
@@ -25,7 +25,7 @@ class Profiles extends Component {
/> />
<PageContentBody> <PageContentBody>
<DndProvider backend={HTML5Backend}> <DndProvider options={HTML5toTouch}>
<QualityProfilesConnector /> <QualityProfilesConnector />
<DelayProfilesConnector /> <DelayProfilesConnector />
<div className={styles.addCustomFormatMessage}> <div className={styles.addCustomFormatMessage}>
@@ -118,6 +118,12 @@ export const defaultState = {
isSortable: true, isSortable: true,
isVisible: false isVisible: false
}, },
{
name: 'year',
label: translate('Year'),
isSortable: true,
isVisible: true
},
{ {
name: 'outputPath', name: 'outputPath',
label: translate('OutputPath'), label: translate('OutputPath'),
@@ -201,6 +201,11 @@ export const defaultState = {
return genreList.sort(sortByName); return genreList.sort(sortByName);
} }
}, },
{
name: 'customFormatScore',
label: translate('CustomFormatScore'),
type: filterBuilderTypes.NUMBER
},
{ {
name: 'rejectionCount', name: 'rejectionCount',
label: translate('RejectionCount'), label: translate('RejectionCount'),
+7 -5
View File
@@ -94,27 +94,27 @@ module.exports = {
defaultBackgroundColor: '#333', defaultBackgroundColor: '#333',
defaultBorderColor: '#eaeaea', defaultBorderColor: '#eaeaea',
defaultHoverBackgroundColor: '#444', defaultHoverBackgroundColor: '#444',
defaultHoverBorderColor: '#d6d6d6;', defaultHoverBorderColor: '#d6d6d6',
primaryBackgroundColor: '#5d9cec', primaryBackgroundColor: '#5d9cec',
primaryBorderColor: '#5899eb', primaryBorderColor: '#5899eb',
primaryHoverBackgroundColor: '#4b91ea', primaryHoverBackgroundColor: '#4b91ea',
primaryHoverBorderColor: '#3483e7;', primaryHoverBorderColor: '#3483e7',
successBackgroundColor: '#27c24c', successBackgroundColor: '#27c24c',
successBorderColor: '#26be4a', successBorderColor: '#26be4a',
successHoverBackgroundColor: '#24b145', successHoverBackgroundColor: '#24b145',
successHoverBorderColor: '#1f9c3d;', successHoverBorderColor: '#1f9c3d',
warningBackgroundColor: '#ff902b', warningBackgroundColor: '#ff902b',
warningBorderColor: '#ff8d26', warningBorderColor: '#ff8d26',
warningHoverBackgroundColor: '#ff8517', warningHoverBackgroundColor: '#ff8517',
warningHoverBorderColor: '#fc7800;', warningHoverBorderColor: '#fc7800',
dangerBackgroundColor: '#f05050', dangerBackgroundColor: '#f05050',
dangerBorderColor: '#f04b4b', dangerBorderColor: '#f04b4b',
dangerHoverBackgroundColor: '#ee3d3d', dangerHoverBackgroundColor: '#ee3d3d',
dangerHoverBorderColor: '#ec2626;', dangerHoverBorderColor: '#ec2626',
iconButtonDisabledColor: '#7a7a7a', iconButtonDisabledColor: '#7a7a7a',
iconButtonHoverColor: '#666', iconButtonHoverColor: '#666',
@@ -226,6 +226,8 @@ module.exports = {
// //
// Misc // Misc
progressBarFrontTextColor: white,
progressBarBackTextColor: white,
progressBarBackgroundColor: '#727070', progressBarBackgroundColor: '#727070',
logEventsBackgroundColor: '#2a2a2a' logEventsBackgroundColor: '#2a2a2a'
}; };
+6 -4
View File
@@ -198,8 +198,8 @@ module.exports = {
popoverShadowColor: 'rgba(0, 0, 0, 0.2)', popoverShadowColor: 'rgba(0, 0, 0, 0.2)',
popoverArrowBorderColor: '#fff', popoverArrowBorderColor: '#fff',
popoverTitleBackgroundInverseColor: '#595959', popoverTitleBackgroundInverseColor: '#9b9b9b',
popoverTitleBorderInverseColor: '#707070', popoverTitleBorderInverseColor: '#bfbfbf',
popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)', popoverShadowInverseColor: 'rgba(0, 0, 0, 0.2)',
popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)', popoverArrowBorderInverseColor: 'rgba(58, 63, 81, 0.75)',
@@ -227,6 +227,8 @@ module.exports = {
// //
// Misc // Misc
progressBarBackgroundColor: '#fff', progressBarFrontTextColor: white,
logEventsBackgroundColor: '#fff' progressBarBackTextColor: darkGray,
progressBarBackgroundColor: white,
logEventsBackgroundColor: white
}; };
@@ -1,5 +1,4 @@
function formatCustomFormatScore(input, customFormatsLength = 0) {
function formatCustomFormatScore(input) {
const score = Number(input); const score = Number(input);
if (score > 0) { if (score > 0) {
@@ -10,7 +9,7 @@ function formatCustomFormatScore(input) {
return score; return score;
} }
return ''; return customFormatsLength > 0 ? '+0' : '';
} }
export default formatCustomFormatScore; export default formatCustomFormatScore;
+9 -6
View File
@@ -8,8 +8,8 @@
"clean": "rimraf ./_output/UI && rimraf \"**/*.js.map\"", "clean": "rimraf ./_output/UI && rimraf \"**/*.js.map\"",
"start": "webpack --watch --config ./frontend/build/webpack.config.js", "start": "webpack --watch --config ./frontend/build/webpack.config.js",
"watch": "webpack --watch --config ./frontend/build/webpack.config.js", "watch": "webpack --watch --config ./frontend/build/webpack.config.js",
"lint": "esprint check", "lint": "eslint --config frontend/.eslintrc.js --ignore-path frontend/.eslintignore frontend/",
"lint-fix": "esprint check --fix", "lint-fix": "yarn lint --fix",
"stylelint-linux": "stylelint $(find frontend -name '*.css') --config frontend/.stylelintrc", "stylelint-linux": "stylelint $(find frontend -name '*.css') --config frontend/.stylelintrc",
"stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc" "stylelint-windows": "stylelint frontend/**/*.css --config frontend/.stylelintrc"
}, },
@@ -30,7 +30,7 @@
"@fortawesome/free-regular-svg-icons": "6.1.0", "@fortawesome/free-regular-svg-icons": "6.1.0",
"@fortawesome/free-solid-svg-icons": "6.1.0", "@fortawesome/free-solid-svg-icons": "6.1.0",
"@fortawesome/react-fontawesome": "0.1.18", "@fortawesome/react-fontawesome": "0.1.18",
"@microsoft/signalr": "6.0.8", "@microsoft/signalr": "6.0.16",
"@sentry/browser": "6.18.2", "@sentry/browser": "6.18.2",
"@sentry/integrations": "6.18.2", "@sentry/integrations": "6.18.2",
"classnames": "2.3.1", "classnames": "2.3.1",
@@ -108,12 +108,11 @@
"eslint-plugin-json": "3.1.0", "eslint-plugin-json": "3.1.0",
"eslint-plugin-react": "7.29.4", "eslint-plugin-react": "7.29.4",
"eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-react-hooks": "4.6.0",
"eslint-plugin-simple-import-sort": "7.0.0", "eslint-plugin-simple-import-sort": "8.0.0",
"esprint": "3.3.0",
"file-loader": "6.2.0", "file-loader": "6.2.0",
"filemanager-webpack-plugin": "5.0.0", "filemanager-webpack-plugin": "5.0.0",
"html-webpack-plugin": "5.3.1", "html-webpack-plugin": "5.3.1",
"loader-utils": "^2.0.0", "loader-utils": "^3.2.1",
"mini-css-extract-plugin": "1.5.0", "mini-css-extract-plugin": "1.5.0",
"postcss": "8.2.12", "postcss": "8.2.12",
"postcss-color-function": "4.1.0", "postcss-color-function": "4.1.0",
@@ -134,5 +133,9 @@
"webpack-cli": "4.9.1", "webpack-cli": "4.9.1",
"webpack-livereload-plugin": "3.0.2", "webpack-livereload-plugin": "3.0.2",
"worker-loader": "3.0.8" "worker-loader": "3.0.8"
},
"volta": {
"node": "16.17.0",
"yarn": "1.22.19"
} }
} }
+3
View File
@@ -0,0 +1,3 @@
is_global = true
dotnet_diagnostic.CA1014.severity = none
+3 -1
View File
@@ -1,7 +1,9 @@
<Project> <Project>
<!-- Common to all Radarr Projects --> <!-- Common to all Radarr Projects -->
<PropertyGroup> <PropertyGroup>
<AnalysisLevel>6.0-all</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles> <ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -90,7 +92,7 @@
<!-- Standard testing packages --> <!-- Standard testing packages -->
<ItemGroup Condition="'$(TestProject)'=='true'"> <ItemGroup Condition="'$(TestProject)'=='true'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" /> <PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />
+3 -4
View File
@@ -356,7 +356,7 @@ namespace NzbDrone.Common.Disk
} }
} }
public string GetPathRoot(string path) public virtual string GetPathRoot(string path)
{ {
Ensure.That(path, () => path).IsValidPath(); Ensure.That(path, () => path).IsValidPath();
@@ -483,12 +483,11 @@ namespace NzbDrone.Common.Disk
return mounts.Where(drive => drive.RootDirectory.PathEquals(path) || return mounts.Where(drive => drive.RootDirectory.PathEquals(path) ||
drive.RootDirectory.IsParentPath(path)) drive.RootDirectory.IsParentPath(path))
.OrderByDescending(drive => drive.RootDirectory.Length) .MaxBy(drive => drive.RootDirectory.Length);
.FirstOrDefault();
} }
catch (Exception ex) catch (Exception ex)
{ {
Logger.Debug(ex, string.Format("Failed to get mount for path {0}", path)); Logger.Debug(ex, $"Failed to get mount for path {path}");
return null; return null;
} }
} }
@@ -11,6 +11,7 @@ namespace NzbDrone.Common.EnvironmentInfo
public interface IAppFolderFactory public interface IAppFolderFactory
{ {
void Register(); void Register();
void SetPermissions();
} }
public class AppFolderFactory : IAppFolderFactory public class AppFolderFactory : IAppFolderFactory
@@ -58,7 +59,7 @@ namespace NzbDrone.Common.EnvironmentInfo
InitializeMonoApplicationData(); InitializeMonoApplicationData();
} }
private void SetPermissions() public void SetPermissions()
{ {
try try
{ {
@@ -9,6 +9,7 @@ namespace NzbDrone.Common.EnvironmentInfo
bool IsAdmin { get; } bool IsAdmin { get; }
bool IsWindowsService { get; } bool IsWindowsService { get; }
bool IsWindowsTray { get; } bool IsWindowsTray { get; }
bool IsStarting { get; set; }
bool IsExiting { get; set; } bool IsExiting { get; set; }
bool IsTray { get; } bool IsTray { get; }
RuntimeMode Mode { get; } RuntimeMode Mode { get; }
@@ -19,6 +19,7 @@ namespace NzbDrone.Common.EnvironmentInfo
_logger = logger; _logger = logger;
IsWindowsService = hostLifetime is WindowsServiceLifetime; IsWindowsService = hostLifetime is WindowsServiceLifetime;
IsStarting = true;
// net6.0 will return Radarr.dll for entry assembly, we need the actual // net6.0 will return Radarr.dll for entry assembly, we need the actual
// executable name (Radarr on linux). On mono this will return the location of // executable name (Radarr on linux). On mono this will return the location of
@@ -82,6 +83,7 @@ namespace NzbDrone.Common.EnvironmentInfo
public bool IsWindowsService { get; private set; } public bool IsWindowsService { get; private set; }
public bool IsStarting { get; set; }
public bool IsExiting { get; set; } public bool IsExiting { get; set; }
public bool IsTray public bool IsTray
{ {
@@ -131,7 +131,7 @@ namespace NzbDrone.Common.Extensions
public static string WrapInQuotes(this string text) public static string WrapInQuotes(this string text)
{ {
if (!text.Contains(" ")) if (!text.Contains(' '))
{ {
return text; return text;
} }
@@ -217,7 +217,7 @@ namespace NzbDrone.Common.Extensions
public static string ToUrlHost(this string input) public static string ToUrlHost(this string input)
{ {
return input.Contains(":") ? $"[{input}]" : input; return input.Contains(':') ? $"[{input}]" : input;
} }
} }
} }
@@ -216,7 +216,7 @@ namespace NzbDrone.Common.Http.Dispatchers
} }
} }
private void AddContentHeader(HttpRequestMessage request, string header, string value) private static void AddContentHeader(HttpRequestMessage request, string header, string value)
{ {
var headers = request.Content?.Headers; var headers = request.Content?.Headers;
if (headers == null) if (headers == null)
+1 -1
View File
@@ -170,7 +170,7 @@ namespace NzbDrone.Common.Http
if (baseSlashIndex >= 0) if (baseSlashIndex >= 0)
{ {
return basePath.Substring(0, baseSlashIndex) + "/" + relativePath; return $"{basePath.AsSpan(0, baseSlashIndex)}/{relativePath}";
} }
return relativePath; return relativePath;
@@ -8,6 +8,7 @@ using System.Threading;
using NLog; using NLog;
using NLog.Common; using NLog.Common;
using NLog.Targets; using NLog.Targets;
using Npgsql;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using Sentry; using Sentry;
@@ -34,6 +35,14 @@ namespace NzbDrone.Common.Instrumentation.Sentry
SQLiteErrorCode.Auth SQLiteErrorCode.Auth
}; };
private static readonly HashSet<string> FilteredPostgresErrorCodes = new HashSet<string>
{
PostgresErrorCodes.OutOfMemory,
PostgresErrorCodes.TooManyConnections,
PostgresErrorCodes.DiskFull,
PostgresErrorCodes.ProgramLimitExceeded
};
// use string and not Type so we don't need a reference to the project // use string and not Type so we don't need a reference to the project
// where these are defined // where these are defined
private static readonly HashSet<string> FilteredExceptionTypeNames = new HashSet<string> private static readonly HashSet<string> FilteredExceptionTypeNames = new HashSet<string>
@@ -250,6 +259,19 @@ namespace NzbDrone.Common.Instrumentation.Sentry
isSentry = false; isSentry = false;
} }
var pgEx = logEvent.Exception as PostgresException;
if (pgEx != null && FilteredPostgresErrorCodes.Contains(pgEx.SqlState))
{
return false;
}
// We don't care about transient network and timeout errors
var npgEx = logEvent.Exception as NpgsqlException;
if (npgEx != null && npgEx.IsTransient)
{
return false;
}
if (FilteredExceptionTypeNames.Contains(ex.GetType().Name)) if (FilteredExceptionTypeNames.Contains(ex.GetType().Name))
{ {
isSentry = false; isSentry = false;
@@ -320,7 +320,7 @@ namespace NzbDrone.Common.Processes
processInfo = new ProcessInfo(); processInfo = new ProcessInfo();
processInfo.Id = process.Id; processInfo.Id = process.Id;
processInfo.Name = process.ProcessName; processInfo.Name = process.ProcessName;
processInfo.StartPath = GetExeFileName(process); processInfo.StartPath = process.MainModule.FileName;
if (process.Id != GetCurrentProcessId() && process.HasExited) if (process.Id != GetCurrentProcessId() && process.HasExited)
{ {
@@ -335,16 +335,6 @@ namespace NzbDrone.Common.Processes
return processInfo; return processInfo;
} }
private static string GetExeFileName(Process process)
{
if (process.MainModule.FileName != "mono.exe")
{
return process.MainModule.FileName;
}
return process.Modules.Cast<ProcessModule>().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName;
}
private List<Process> GetProcessesByName(string name) private List<Process> GetProcessesByName(string name)
{ {
var processes = Process.GetProcessesByName(name).ToList(); var processes = Process.GetProcessesByName(name).ToList();
+6 -5
View File
@@ -4,19 +4,20 @@
<DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants> <DefineConstants Condition="'$(RuntimeIdentifier)' == 'linux-musl-x64' or '$(RuntimeIdentifier)' == 'linux-musl-arm64'">ISMUSL</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DryIoc.dll" Version="5.3.0" /> <PackageReference Include="DryIoc.dll" Version="5.3.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NLog" Version="5.0.1" /> <PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Npgsql" Version="5.0.11" />
<PackageReference Include="Sentry" Version="3.23.1" /> <PackageReference Include="Sentry" Version="3.23.1" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" /> <PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="System.Text.Json" Version="6.0.5" /> <PackageReference Include="System.Text.Json" Version="6.0.7" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" /> <PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" /> <PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" />
+1 -1
View File
@@ -64,7 +64,7 @@ namespace NzbDrone.Common
var args = $"create {serviceName} " + var args = $"create {serviceName} " +
$"DisplayName= \"{serviceName}\" " + $"DisplayName= \"{serviceName}\" " +
$"binpath= \"{Process.GetCurrentProcess().MainModule.FileName}\" " + $"binpath= \"{Environment.ProcessPath}\" " +
"start= auto " + "start= auto " +
"depend= EventLog/Tcpip/http " + "depend= EventLog/Tcpip/http " +
"obj= \"NT AUTHORITY\\LocalService\""; "obj= \"NT AUTHORITY\\LocalService\"";
@@ -19,7 +19,7 @@ namespace NzbDrone.Common.TPL
private readonly int _maxDegreeOfParallelism; private readonly int _maxDegreeOfParallelism;
/// <summary>Whether the scheduler is currently processing work items.</summary> /// <summary>Whether the scheduler is currently processing work items.</summary>
private int _delegatesQueuedOrRunning = 0; private int _delegatesQueuedOrRunning;
/// <summary> /// <summary>
/// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
@@ -81,8 +81,9 @@ namespace NzbDrone.Core.Test.Blocklisting
Subject.DeleteForMovies(new List<int> { _movie1.Id }); Subject.DeleteForMovies(new List<int> { _movie1.Id });
var removedMovieBlocklists = Subject.BlocklistedByMovie(_movie1.Id); var blocklist = Subject.All();
var nonRemovedMovieBlocklists = Subject.BlocklistedByMovie(_movie2.Id); var removedMovieBlocklists = blocklist.Where(b => b.MovieId == _movie1.Id);
var nonRemovedMovieBlocklists = blocklist.Where(b => b.MovieId == _movie2.Id);
removedMovieBlocklists.Should().HaveCount(0); removedMovieBlocklists.Should().HaveCount(0);
nonRemovedMovieBlocklists.Should().HaveCount(1); nonRemovedMovieBlocklists.Should().HaveCount(1);
@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
@@ -9,7 +9,7 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.CustomFormats namespace NzbDrone.Core.Test.CustomFormats
{ {
[TestFixture] [TestFixture]
public class CustomFormatsFixture : CoreTest public class CustomFormatsTestHelpers : CoreTest
{ {
private static List<CustomFormat> _customFormats { get; set; } private static List<CustomFormat> _customFormats { get; set; }
@@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Datastore.Migration
[TestFixture] [TestFixture]
public class custom_formatsFixture : MigrationTest<add_custom_formats> public class custom_formatsFixture : MigrationTest<add_custom_formats>
{ {
public static Dictionary<int, int> QualityToDefinition = null; public static Dictionary<int, int> QualityToDefinition;
public void AddDefaultProfile(add_custom_formats m, string name, Quality cutoff, params Quality[] allowed) public void AddDefaultProfile(add_custom_formats m, string name, Quality cutoff, params Quality[] allowed)
{ {
@@ -46,14 +46,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
ParsedMovieInfo = new ParsedMovieInfo { Quality = new QualityModel(Quality.DVD, new Revision(version: 2)) }, ParsedMovieInfo = new ParsedMovieInfo { Quality = new QualityModel(Quality.DVD, new Revision(version: 2)) },
}; };
CustomFormatsFixture.GivenCustomFormats(_format1, _format2); CustomFormatsTestHelpers.GivenCustomFormats(_format1, _format2);
} }
[Test] [Test]
public void should_allow_if_format_score_greater_than_min() public void should_allow_if_format_score_greater_than_min()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { _format1 }; _remoteMovie.CustomFormats = new List<CustomFormat> { _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_format_score_not_greater_than_min() public void should_deny_if_format_score_not_greater_than_min()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2 }; _remoteMovie.CustomFormats = new List<CustomFormat> { _format2 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Console.WriteLine(_remoteMovie.CustomFormatScore); Console.WriteLine(_remoteMovie.CustomFormatScore);
@@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_format_score_not_greater_than_min_2() public void should_deny_if_format_score_not_greater_than_min_2()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 }; _remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
@@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_allow_if_all_format_is_defined_in_profile() public void should_allow_if_all_format_is_defined_in_profile()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 }; _remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_no_format_was_parsed_and_min_score_positive() public void should_deny_if_no_format_was_parsed_and_min_score_positive()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { }; _remoteMovie.CustomFormats = new List<CustomFormat> { };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
@@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_allow_if_no_format_was_parsed_min_score_is_zero() public void should_allow_if_no_format_was_parsed_min_score_is_zero()
{ {
_remoteMovie.CustomFormats = new List<CustomFormat> { }; _remoteMovie.CustomFormats = new List<CustomFormat> { };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name); _remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.Movie.Profile.MinFormatScore = 0; _remoteMovie.Movie.Profile.MinFormatScore = 0;
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats); _remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
@@ -40,8 +40,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void GivenProfile(Profile profile) private void GivenProfile(Profile profile)
{ {
CustomFormatsFixture.GivenCustomFormats(); CustomFormatsTestHelpers.GivenCustomFormats();
profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(); profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems();
profile.MinFormatScore = 0; profile.MinFormatScore = 0;
_remoteMovie.Movie.Profile = profile; _remoteMovie.Movie.Profile = profile;
@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
_customFormat = new CustomFormat("My Format", new ResolutionSpecification { Value = (int)Resolution.R1080p }) { Id = 1 }; _customFormat = new CustomFormat("My Format", new ResolutionSpecification { Value = (int)Resolution.R1080p }) { Id = 1 };
CustomFormatsFixture.GivenCustomFormats(_customFormat); CustomFormatsTestHelpers.GivenCustomFormats(_customFormat);
} }
[Test] [Test]
@@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
MinFormatScore = 0, MinFormatScore = 0,
FormatItems = CustomFormatsFixture.GetSampleFormatItems("My Format"), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("My Format"),
UpgradeAllowed = true UpgradeAllowed = true
}); });
@@ -38,14 +38,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<UpgradableSpecification>(); Mocker.Resolve<UpgradableSpecification>();
_upgradeHistory = Mocker.Resolve<HistorySpecification>(); _upgradeHistory = Mocker.Resolve<HistorySpecification>();
CustomFormatsFixture.GivenCustomFormats(); CustomFormatsTestHelpers.GivenCustomFormats();
_fakeMovie = Builder<Movie>.CreateNew() _fakeMovie = Builder<Movie>.CreateNew()
.With(c => c.Profile = new Profile .With(c => c.Profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.Bluray1080p.Id, Cutoff = Quality.Bluray1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems("None"), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("None"),
MinFormatScore = 0, MinFormatScore = 0,
UpgradeAllowed = true UpgradeAllowed = true
}) })
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(true); .Returns(true);
Mocker.GetMock<ICustomFormatCalculationService>() Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>())) .Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
.Returns(new List<CustomFormat>()); .Returns(new List<CustomFormat>());
} }
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.Bluray1080p.Id, Cutoff = Quality.Bluray1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0 MinFormatScore = 0
}; };
@@ -171,7 +171,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
Mocker.GetMock<ICustomFormatCalculationService>() Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>())) .Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
.Returns(new List<CustomFormat>()); .Returns(new List<CustomFormat>());
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, MovieHistoryEventType.Grabbed); GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, MovieHistoryEventType.Grabbed);
@@ -186,7 +186,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.WEBDL1080p.Id, Cutoff = Quality.WEBDL1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0 MinFormatScore = 0
}; };
@@ -221,7 +221,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.WEBDL1080p.Id, Cutoff = Quality.WEBDL1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0 MinFormatScore = 0
}; };
@@ -41,17 +41,17 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithEnglishRelease() private void WithEnglishRelease()
{ {
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.English }; _remoteMovie.Languages = new List<Language> { Language.English };
} }
private void WithGermanRelease() private void WithGermanRelease()
{ {
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.German }; _remoteMovie.Languages = new List<Language> { Language.German };
} }
private void WithFrenchRelease() private void WithFrenchRelease()
{ {
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.French }; _remoteMovie.Languages = new List<Language> { Language.French };
} }
[Test] [Test]
@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_customFormat1 = new CustomFormat("My Format 1", new LanguageSpecification { Value = (int)Language.English }) { Id = 1 }; _customFormat1 = new CustomFormat("My Format 1", new LanguageSpecification { Value = (int)Language.English }) { Id = 1 };
_customFormat2 = new CustomFormat("My Format 2", new LanguageSpecification { Value = (int)Language.French }) { Id = 2 }; _customFormat2 = new CustomFormat("My Format 2", new LanguageSpecification { Value = (int)Language.French }) { Id = 2 };
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2); CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
Mocker.GetMock<IQualityDefinitionService>() Mocker.GetMock<IQualityDefinitionService>()
.Setup(s => s.Get(It.IsAny<Quality>())) .Setup(s => s.Get(It.IsAny<Quality>()))
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
MinFormatScore = 0 MinFormatScore = 0
}) })
.With(m => m.Title = "A Movie") .With(m => m.Title = "A Movie")
@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2); CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
} }
private void GivenAutoDownloadPropers(ProperDownloadTypes type) private void GivenAutoDownloadPropers(ProperDownloadTypes type)
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var profile = new Profile var profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
MinFormatScore = 0 MinFormatScore = 0
}; };
@@ -4,9 +4,11 @@ using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.CustomFormats; using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download.TrackedDownloads; using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles; using NzbDrone.Core.Profiles;
@@ -32,13 +34,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
Mocker.Resolve<UpgradableSpecification>(); Mocker.Resolve<UpgradableSpecification>();
CustomFormatsFixture.GivenCustomFormats(); CustomFormatsTestHelpers.GivenCustomFormats();
_movie = Builder<Movie>.CreateNew() _movie = Builder<Movie>.CreateNew()
.With(e => e.Profile = new Profile .With(e => e.Profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0, MinFormatScore = 0,
UpgradeAllowed = true UpgradeAllowed = true
}) })
@@ -58,7 +60,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Build(); .Build();
Mocker.GetMock<ICustomFormatCalculationService>() Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<ParsedMovieInfo>(), _movie)) .Setup(x => x.ParseCustomFormat(It.IsAny<RemoteMovie>(), It.IsAny<long>()))
.Returns(new List<CustomFormat>()); .Returns(new List<CustomFormat>());
} }
@@ -204,5 +206,31 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
} }
[Test]
public void should_return_false_if_same_quality_non_proper_in_queue_and_download_propers_is_do_not_upgrade()
{
_remoteMovie.ParsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p, new Revision(2));
_movie.Profile.Cutoff = _remoteMovie.ParsedMovieInfo.Quality.Quality.Id;
Mocker.GetMock<IConfigService>()
.Setup(s => s.DownloadPropersAndRepacks)
.Returns(ProperDownloadTypes.DoNotUpgrade);
var remoteMovie = Builder<RemoteMovie>.CreateNew()
.With(r => r.Movie = _movie)
.With(r => r.ParsedMovieInfo = new ParsedMovieInfo
{
Quality = new QualityModel(Quality.HDTV720p),
Languages = new List<Language> { Language.English }
})
.With(r => r.Release = _releaseInfo)
.With(r => r.CustomFormats = new List<CustomFormat>())
.Build();
GivenQueue(new List<RemoteMovie> { remoteMovie });
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
}
} }
} }
@@ -0,0 +1,209 @@
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class UpgradeAllowedSpecificationFixture : CoreTest<UpgradableSpecification>
{
private CustomFormat _customFormatOne;
private CustomFormat _customFormatTwo;
private Profile _qualityProfile;
[SetUp]
public void Setup()
{
_customFormatOne = new CustomFormat
{
Id = 1,
Name = "One"
};
_customFormatTwo = new CustomFormat
{
Id = 2,
Name = "Two"
};
_qualityProfile = new Profile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = false,
CutoffFormatScore = 100,
FormatItems = new List<ProfileFormatItem>
{
new ProfileFormatItem
{
Format = _customFormatOne,
Score = 50
},
new ProfileFormatItem
{
Format = _customFormatTwo,
Score = 100
}
}
};
}
[Test]
public void should_return_false_when_quality_is_better_custom_formats_are_the_same_and_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.Bluray1080p),
new List<CustomFormat>())
.Should().BeFalse();
}
[Test]
public void should_return_false_when_quality_is_same_and_custom_format_is_upgrade_and_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne },
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatTwo })
.Should().BeFalse();
}
[Test]
public void should_return_true_for_custom_format_upgrade_when_upgrading_is_allowed()
{
_qualityProfile.UpgradeAllowed = true;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne },
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatTwo })
.Should().BeTrue();
}
[Test]
public void should_return_true_for_same_custom_format_score_when_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne },
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne })
.Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_custom_format_score_when_upgrading_is_allowed()
{
_qualityProfile.UpgradeAllowed = true;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatTwo },
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne })
.Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_language_when_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatTwo },
new QualityModel(Quality.DVD),
new List<CustomFormat> { _customFormatOne })
.Should().BeTrue();
}
[Test]
public void should_return_true_for_quality_upgrade_when_upgrading_is_allowed()
{
_qualityProfile.UpgradeAllowed = true;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.Bluray1080p),
new List<CustomFormat>())
.Should().BeTrue();
}
[Test]
public void should_return_true_for_same_quality_when_upgrading_is_allowed()
{
_qualityProfile.UpgradeAllowed = true;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.DVD),
new List<CustomFormat>())
.Should().BeTrue();
}
[Test]
public void should_return_true_for_same_quality_when_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.DVD),
new List<CustomFormat>())
.Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_quality_when_upgrading_is_allowed()
{
_qualityProfile.UpgradeAllowed = true;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.SDTV),
new List<CustomFormat>())
.Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_quality_when_upgrading_is_not_allowed()
{
_qualityProfile.UpgradeAllowed = false;
Subject.IsUpgradeAllowed(
_qualityProfile,
new QualityModel(Quality.DVD),
new List<CustomFormat>(),
new QualityModel(Quality.SDTV),
new List<CustomFormat>())
.Should().BeTrue();
}
}
}
@@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<UpgradableSpecification>(); Mocker.Resolve<UpgradableSpecification>();
_upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>(); _upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>();
CustomFormatsFixture.GivenCustomFormats(); CustomFormatsTestHelpers.GivenCustomFormats();
_firstFile = new MovieFile { Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 2)), DateAdded = DateTime.Now }; _firstFile = new MovieFile { Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 2)), DateAdded = DateTime.Now };
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.With(c => c.Profile = new Profile .With(c => c.Profile = new Profile
{ {
Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities(), Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(), FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0 MinFormatScore = 0
}) })
.With(e => e.MovieFile = _firstFile) .With(e => e.MovieFile = _firstFile)
@@ -0,0 +1,112 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Download.Aggregation.Aggregators;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Download.Aggregation.Aggregators
{
[TestFixture]
public class AggregateLanguagesFixture : CoreTest<AggregateLanguages>
{
private RemoteMovie _remoteMovie;
private Movie _movie;
private string _simpleReleaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(m => m.MovieMetadata = new MovieMetadata
{
Title = "Some Movie",
OriginalLanguage = Language.English
})
.Build();
_remoteMovie = Builder<RemoteMovie>.CreateNew()
.With(l => l.ParsedMovieInfo = null)
.With(l => l.Movie = _movie)
.Build();
}
private ParsedMovieInfo GetParsedMovieInfo(List<Language> languages, string releaseTitle, string releaseTokens = "")
{
return new ParsedMovieInfo
{
Languages = languages,
ReleaseTitle = releaseTitle,
SimpleReleaseTitle = releaseTokens
};
}
[Test]
public void should_return_existing_language_if_episode_title_does_not_have_language()
{
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Original }, _simpleReleaseTitle);
Subject.Aggregate(_remoteMovie).Languages.Should().Contain(_movie.MovieMetadata.Value.OriginalLanguage);
}
[Test]
public void should_return_parsed_language()
{
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.French }, _simpleReleaseTitle);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_remoteMovie.ParsedMovieInfo.Languages);
}
[Test]
public void should_exclude_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_movie.MovieMetadata.Value.OriginalLanguage);
}
[Test]
public void should_remove_parsed_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.French.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.French.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek, Language.French }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.French);
}
[Test]
public void should_not_exclude_language_that_is_part_of_episode_title_when_release_tokens_does_not_contain_episode_title()
{
var releaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
var releaseTokens = ".xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
}
[Test]
public void should_use_reparse_language_after_determining_languages_that_are_in_episode_titles()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.Greek.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.Greek.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
}
}
}
@@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.FreeboxDownloadTests
Mocker.GetMock<IHttpClient>() Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>())) .Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0])); .Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), Array.Empty<byte>()));
} }
protected void GivenCategory() protected void GivenCategory()
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentAssertions; using FluentAssertions;
@@ -275,7 +276,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
[TestCase(-1)] // Infinite/Unknown [TestCase(-1)] // Infinite/Unknown
[TestCase(-2)] // Magnet Downloading [TestCase(-2)] // Magnet Downloading
public void should_ignore_negative_eta(int eta) public void should_ignore_negative_eta(long eta)
{ {
_completed.Eta = eta; _completed.Eta = eta;
@@ -284,6 +285,26 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
item.RemainingTime.Should().NotHaveValue(); item.RemainingTime.Should().NotHaveValue();
} }
[TestCase(2147483648)] // 2038-01-19T03:14:08Z > int.MaxValue as unix timestamp can be either an int or a long
public void should_support_long_values_for_eta_in_seconds(long eta)
{
_downloading.Eta = eta;
PrepareClientToReturnDownloadingItem();
var item = Subject.GetItems().Single();
item.RemainingTime.Should().Be(TimeSpan.FromSeconds(eta));
}
[TestCase(2147483648000)] // works with milliseconds format too
public void should_support_long_values_for_eta_in_milliseconds(long eta)
{
_downloading.Eta = eta;
PrepareClientToReturnDownloadingItem();
var item = Subject.GetItems().Single();
item.RemainingTime.Should().Be(TimeSpan.FromMilliseconds(eta));
}
[Test] [Test]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_stopped() public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_stopped()
{ {
@@ -271,7 +271,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[TestCase(-1)] // Infinite/Unknown [TestCase(-1)] // Infinite/Unknown
[TestCase(-2)] // Magnet Downloading [TestCase(-2)] // Magnet Downloading
public void should_ignore_negative_eta(int eta) public void should_ignore_negative_eta(long eta)
{ {
_completed.Eta = eta; _completed.Eta = eta;
@@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Download
_downloadClients = new List<IDownloadClient>(); _downloadClients = new List<IDownloadClient>();
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(v => v.GetDownloadClients()) .Setup(v => v.GetDownloadClients(It.IsAny<bool>()))
.Returns(_downloadClients); .Returns(_downloadClients);
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
@@ -54,6 +54,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
Id = id, Id = id,
Title = "Movie.Title.2020.720p-Radarr", Title = "Movie.Title.2020.720p-Radarr",
ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year }, ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year },
Release = Builder<ReleaseInfo>.CreateNew().Build(),
MovieId = _movie.Id MovieId = _movie.Id
}); });
} }
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.Extras.Others
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(1); results.Count.Should().Be(1);
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true); results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
} }
@@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.Extras.Others
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(1); results.Count.Should().Be(1);
} }
} }
} }
@@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(0); results.Count.Should().Be(0);
} }
[Test] [Test]
@@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(1); results.Count.Should().Be(1);
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true); results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
} }
@@ -110,7 +110,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(expectedOutputs.Length); results.Count.Should().Be(expectedOutputs.Length);
for (int i = 0; i < expectedOutputs.Length; i++) for (int i = 0; i < expectedOutputs.Length; i++)
{ {
@@ -139,7 +139,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, files, true).ToList();
results.Count().Should().Be(expectedOutputs.Length); results.Count.Should().Be(expectedOutputs.Length);
for (int i = 0; i < expectedOutputs.Length; i++) for (int i = 0; i < expectedOutputs.Length; i++)
{ {
@@ -169,7 +169,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var results = Subject.ImportFiles(_localMovie, _movieFile, new List<string> { subtitleFile }, true).ToList(); var results = Subject.ImportFiles(_localMovie, _movieFile, new List<string> { subtitleFile }, true).ToList();
results.Count().Should().Be(1); results.Count.Should().Be(1);
results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true); results[0].RelativePath.AsOsAgnostic().PathEquals(expectedOutputPath.AsOsAgnostic()).Should().Be(true);
File diff suppressed because it is too large Load Diff
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
public void should_return_warning_when_download_client_has_not_been_configured() public void should_return_warning_when_download_client_has_not_been_configured()
{ {
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients()) .Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(Array.Empty<IDownloadClient>()); .Returns(Array.Empty<IDownloadClient>());
Subject.Check().ShouldBeWarning(); Subject.Check().ShouldBeWarning();
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Throws<Exception>(); .Throws<Exception>();
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients()) .Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(new IDownloadClient[] { downloadClient.Object }); .Returns(new IDownloadClient[] { downloadClient.Object });
Subject.Check().ShouldBeError(); Subject.Check().ShouldBeError();
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Returns(new List<DownloadClientItem>()); .Returns(new List<DownloadClientItem>());
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients()) .Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(new IDownloadClient[] { downloadClient.Object }); .Returns(new IDownloadClient[] { downloadClient.Object });
Subject.Check().ShouldBeOk(); Subject.Check().ShouldBeOk();
@@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Returns(_clientStatus); .Returns(_clientStatus);
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients()) .Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(new IDownloadClient[] { _downloadClient.Object }); .Returns(new IDownloadClient[] { _downloadClient.Object });
Mocker.GetMock<IDiskProvider>() Mocker.GetMock<IDiskProvider>()
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Localization;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class DownloadClientFolderCheckFixture : CoreTest<DownloadClientSortingCheck>
{
private DownloadClientInfo _clientStatus;
private Mock<IDownloadClient> _downloadClient;
private static Exception[] DownloadClientExceptions =
{
new DownloadClientUnavailableException("error"),
new DownloadClientAuthenticationException("error"),
new DownloadClientException("error")
};
[SetUp]
public void Setup()
{
Mocker.GetMock<ILocalizationService>()
.Setup(s => s.GetLocalizedString(It.IsAny<string>()))
.Returns("Some Warning Message");
_clientStatus = new DownloadClientInfo
{
IsLocalhost = true,
SortingMode = null
};
_downloadClient = Mocker.GetMock<IDownloadClient>();
_downloadClient.Setup(s => s.Definition)
.Returns(new DownloadClientDefinition { Name = "Test" });
_downloadClient.Setup(s => s.GetStatus())
.Returns(_clientStatus);
Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(new IDownloadClient[] { _downloadClient.Object });
}
[Test]
public void should_return_ok_if_sorting_is_not_enabled()
{
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_warning_if_sorting_is_enabled()
{
_clientStatus.SortingMode = "TV";
Subject.Check().ShouldBeWarning();
}
[Test]
[TestCaseSource("DownloadClientExceptions")]
public void should_return_ok_if_client_throws_downloadclientexception(Exception ex)
{
_downloadClient.Setup(s => s.GetStatus())
.Throws(ex);
Subject.Check().ShouldBeOk();
ExceptionVerification.ExpectedErrors(0);
}
}
}
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Returns(_clientStatus); .Returns(_clientStatus);
Mocker.GetMock<IProvideDownloadClient>() Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClients()) .Setup(s => s.GetDownloadClients(It.IsAny<bool>()))
.Returns(new IDownloadClient[] { _downloadClient.Object }); .Returns(new IDownloadClient[] { _downloadClient.Object });
Mocker.GetMock<IConfigService>() Mocker.GetMock<IConfigService>()
@@ -0,0 +1,133 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Housekeeping.Housekeepers;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{
[TestFixture]
public class CleanupQualityProfileFormatItemsFixture : DbTest<CleanupQualityProfileFormatItems, Profile>
{
[SetUp]
public void Setup()
{
Mocker.SetConstant<IQualityProfileFormatItemsCleanupRepository>(
new QualityProfileFormatItemsCleanupRepository(Mocker.Resolve<IMainDatabase>(), Mocker.Resolve<IEventAggregator>()));
Mocker.SetConstant<ICustomFormatRepository>(
new CustomFormatRepository(Mocker.Resolve<IMainDatabase>(), Mocker.Resolve<IEventAggregator>()));
}
[Test]
public void should_remove_orphaned_custom_formats()
{
var qualityProfile = Builder<Profile>.CreateNew()
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
.With(h => h.MinFormatScore = 50)
.With(h => h.CutoffFormatScore = 100)
.With(h => h.FormatItems = new List<ProfileFormatItem>
{
Builder<ProfileFormatItem>.CreateNew()
.With(c => c.Format = new CustomFormat("My Custom Format") { Id = 0 })
.Build()
})
.BuildNew();
Db.Insert(qualityProfile);
Subject.Clean();
var result = AllStoredModels;
result.Should().HaveCount(1);
result.First().FormatItems.Should().BeEmpty();
result.First().MinFormatScore.Should().Be(0);
result.First().CutoffFormatScore.Should().Be(0);
}
[Test]
public void should_not_remove_unorphaned_custom_formats()
{
var minFormatScore = 50;
var cutoffFormatScore = 100;
var customFormat = Builder<CustomFormat>.CreateNew()
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
.BuildNew();
Db.Insert(customFormat);
var qualityProfile = Builder<Profile>.CreateNew()
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
.With(h => h.MinFormatScore = minFormatScore)
.With(h => h.CutoffFormatScore = cutoffFormatScore)
.With(h => h.FormatItems = new List<ProfileFormatItem>
{
Builder<ProfileFormatItem>.CreateNew()
.With(c => c.Format = customFormat)
.Build()
})
.BuildNew();
Db.Insert(qualityProfile);
Subject.Clean();
var result = AllStoredModels;
result.Should().HaveCount(1);
result.First().FormatItems.Should().HaveCount(1);
result.First().MinFormatScore.Should().Be(minFormatScore);
result.First().CutoffFormatScore.Should().Be(cutoffFormatScore);
}
[Test]
public void should_add_missing_custom_formats()
{
var minFormatScore = 50;
var cutoffFormatScore = 100;
var customFormat1 = Builder<CustomFormat>.CreateNew()
.With(h => h.Id = 1)
.With(h => h.Name = "Custom Format 1")
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
.BuildNew();
var customFormat2 = Builder<CustomFormat>.CreateNew()
.With(h => h.Id = 2)
.With(h => h.Name = "Custom Format 2")
.With(h => h.Specifications = new List<ICustomFormatSpecification>())
.BuildNew();
Db.Insert(customFormat1);
Db.Insert(customFormat2);
var qualityProfile = Builder<Profile>.CreateNew()
.With(h => h.Items = Qualities.QualityFixture.GetDefaultQualities())
.With(h => h.MinFormatScore = minFormatScore)
.With(h => h.CutoffFormatScore = cutoffFormatScore)
.With(h => h.FormatItems = new List<ProfileFormatItem>
{
Builder<ProfileFormatItem>.CreateNew()
.With(c => c.Format = customFormat1)
.Build()
})
.BuildNew();
Db.Insert(qualityProfile);
Subject.Clean();
var result = AllStoredModels;
result.Should().HaveCount(1);
result.First().FormatItems.Should().HaveCount(2);
result.First().MinFormatScore.Should().Be(minFormatScore);
result.First().CutoffFormatScore.Should().Be(cutoffFormatScore);
}
}
}
@@ -1,10 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.FileList;
using NzbDrone.Core.Indexers.Newznab; using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.Indexers.Omgwtfnzbs;
using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.IndexerTests
_indexers = new List<IIndexer>(); _indexers = new List<IIndexer>();
_indexers.Add(Mocker.Resolve<Newznab>()); _indexers.Add(Mocker.Resolve<Newznab>());
_indexers.Add(Mocker.Resolve<Omgwtfnzbs>()); _indexers.Add(Mocker.Resolve<FileList>());
Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers); Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers);
} }
@@ -62,13 +62,21 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
releaseInfo.Size.Should().Be(1183105773); releaseInfo.Size.Should().Be(1183105773);
} }
[Test] public void should_use_best_pagesize_reported_by_caps()
public void should_use_pagesize_reported_by_caps()
{ {
_caps.MaxPageSize = 30; _caps.MaxPageSize = 30;
_caps.DefaultPageSize = 25; _caps.DefaultPageSize = 25;
Subject.PageSize.Should().Be(25); Subject.PageSize.Should().Be(30);
}
[Test]
public void should_not_use_pagesize_over_100_even_if_reported_in_caps()
{
_caps.MaxPageSize = 250;
_caps.DefaultPageSize = 25;
Subject.PageSize.Should().Be(100);
} }
} }
} }
@@ -1,56 +0,0 @@
using System;
using System.Linq;
using System.Net.Http;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Omgwtfnzbs;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.IndexerTests.OmgwtfnzbsTests
{
[TestFixture]
public class OmgwtfnzbsFixture : CoreTest<Omgwtfnzbs>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "Omgwtfnzbs",
Settings = new OmgwtfnzbsSettings()
{
ApiKey = "xxx",
Username = "me@my.domain"
}
};
}
[Test]
public void should_parse_recent_feed_from_omgwtfnzbs()
{
var recentFeed = ReadAllText(@"Files/Indexers/Omgwtfnzbs/Omgwtfnzbs.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.Get)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(100);
var releaseInfo = releases.First();
releaseInfo.Title.Should().Be("Un.Petit.Boulot.2016.FRENCH.720p.BluRay.DTS.x264-LOST");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
releaseInfo.DownloadUrl.Should().Be("https://api.omgwtfnzbs.me/nzb/?id=8a2Bw&user=nzbdrone&api=nzbdrone");
releaseInfo.InfoUrl.Should().Be("https://omgwtfnzbs.me/details.php?id=8a2Bw");
releaseInfo.CommentUrl.Should().BeNullOrEmpty();
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2017/01/09 00:16:54"));
releaseInfo.Size.Should().Be(5354909355);
}
}
}
@@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using FluentAssertions; using FluentAssertions;
@@ -55,7 +56,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000"); first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000");
first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135"); first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135");
// first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones first.PublishDate.Should().Be(DateTime.Parse("2016-10-18T23:40:59+0000").ToUniversalTime());
first.Size.Should().Be(2466170624L); first.Size.Should().Be(2466170624L);
first.InfoHash.Should().BeNullOrEmpty(); first.InfoHash.Should().BeNullOrEmpty();
first.MagnetUrl.Should().BeNullOrEmpty(); first.MagnetUrl.Should().BeNullOrEmpty();
@@ -135,12 +135,21 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests
} }
[Test] [Test]
public void should_use_pagesize_reported_by_caps() public void should_use_best_pagesize_reported_by_caps()
{ {
_caps.MaxPageSize = 30; _caps.MaxPageSize = 30;
_caps.DefaultPageSize = 25; _caps.DefaultPageSize = 25;
Subject.PageSize.Should().Be(25); Subject.PageSize.Should().Be(30);
}
[Test]
public void should_not_use_pagesize_over_100_even_if_reported_in_caps()
{
_caps.MaxPageSize = 250;
_caps.DefaultPageSize = 25;
Subject.PageSize.Should().Be(100);
} }
[TestCase("http://localhost:9117/", "/api")] [TestCase("http://localhost:9117/", "/api")]
@@ -49,6 +49,14 @@ namespace NzbDrone.Core.Test.Languages
new object[] { 34, Language.Bengali }, new object[] { 34, Language.Bengali },
new object[] { 35, Language.Slovak }, new object[] { 35, Language.Slovak },
new object[] { 36, Language.Latvian }, new object[] { 36, Language.Latvian },
new object[] { 37, Language.SpanishLatino },
new object[] { 38, Language.Catalan },
new object[] { 39, Language.Croatian },
new object[] { 40, Language.Serbian },
new object[] { 41, Language.Bosnian },
new object[] { 42, Language.Estonian },
new object[] { 43, Language.Tamil },
new object[] { 44, Language.Indonesian }
}; };
public static object[] ToIntCases = public static object[] ToIntCases =
@@ -92,6 +100,14 @@ namespace NzbDrone.Core.Test.Languages
new object[] { Language.Bengali, 34 }, new object[] { Language.Bengali, 34 },
new object[] { Language.Slovak, 35 }, new object[] { Language.Slovak, 35 },
new object[] { Language.Latvian, 36 }, new object[] { Language.Latvian, 36 },
new object[] { Language.SpanishLatino, 37 },
new object[] { Language.Catalan, 38 },
new object[] { Language.Croatian, 39 },
new object[] { Language.Serbian, 40 },
new object[] { Language.Bosnian, 41 },
new object[] { Language.Estonian, 42 },
new object[] { Language.Tamil, 43 },
new object[] { Language.Indonesian, 44 }
}; };
[Test] [Test]
@@ -445,6 +445,58 @@ namespace NzbDrone.Core.Test.MediaFiles
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never()); .Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
} }
[Test]
public void should_return_rejection_if_nothing_imported_and_contains_rar_file()
{
GivenValidMovie();
var path = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]\[HorribleSubs] American Psycho (2000) [720p].mkv".AsOsAgnostic();
var imported = new List<ImportDecision>();
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedMovie>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
.Returns(new[] { _videoFiles.First().Replace(".ext", ".rar") });
var result = Subject.ProcessPath(path);
result.Count.Should().Be(1);
result.First().Result.Should().Be(ImportResultType.Rejected);
}
[Test]
public void should_return_rejection_if_nothing_imported_and_contains_executable_file()
{
GivenValidMovie();
var path = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] American Psycho (2000) [720p]\[HorribleSubs] American Psycho (2000) [720p].mkv".AsOsAgnostic();
var imported = new List<ImportDecision>();
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedMovie>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
.Returns(new[] { _videoFiles.First().Replace(".ext", ".exe") });
var result = Subject.ProcessPath(path);
result.Count.Should().Be(1);
result.First().Result.Should().Be(ImportResultType.Rejected);
}
private void VerifyNoImport() private void VerifyNoImport()
{ {
Mocker.GetMock<IImportApprovedMovie>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto), Mocker.GetMock<IImportApprovedMovie>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto),
@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaFileDeletionService
[TestFixture] [TestFixture]
public class DeleteMovieFileFixture : CoreTest<Core.MediaFiles.MediaFileDeletionService> public class DeleteMovieFileFixture : CoreTest<Core.MediaFiles.MediaFileDeletionService>
{ {
private static readonly string RootFolder = @"C:\Test\Movies"; private const string RootFolder = @"C:\Test\Movies";
private Movie _movie; private Movie _movie;
private MovieFile _movieFile; private MovieFile _movieFile;
@@ -25,6 +25,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
[TestCase("msmpeg4, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")] [TestCase("msmpeg4, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("msmpeg4v2, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")] [TestCase("msmpeg4v2, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("msmpeg4v3, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")] [TestCase("msmpeg4v3, DIV3", "Movie the Title (1976) 360p MPEG Audio.avi", "DivX")]
[TestCase("vp6f, 4", "Movie the Title (1976) 360p MPEG Audio.flv", "VP6")]
[TestCase("vp6, 4", "Top Gear - S12E01 - Lorries - SD TV.flv", "VP6")] [TestCase("vp6, 4", "Top Gear - S12E01 - Lorries - SD TV.flv", "VP6")]
[TestCase("vp7, VP70", "Movie the Title.avi", "VP7")] [TestCase("vp7, VP70", "Movie the Title.avi", "VP7")]
[TestCase("vp8, V_VP8", "Movie the Title.mkv", "VP8")] [TestCase("vp8, V_VP8", "Movie the Title.mkv", "VP8")]
@@ -35,7 +35,7 @@ namespace NzbDrone.Core.Test.MovieTests.MovieRepositoryTests
var profile = new Profile var profile = new Profile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p), Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
FormatItems = CustomFormatsFixture.GetDefaultFormatItems(), FormatItems = CustomFormatsTestHelpers.GetDefaultFormatItems(),
MinFormatScore = 0, MinFormatScore = 0,
Cutoff = Quality.Bluray1080p.Id, Cutoff = Quality.Bluray1080p.Id,
Name = "TestProfile" Name = "TestProfile"
@@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.NotificationTests.EmailTests
[TestCase("radarr.video")] [TestCase("radarr.video")]
public void should_not_be_valid_if_cc_is_invalid(string email) public void should_not_be_valid_if_cc_is_invalid(string email)
{ {
_emailSettings.CC = new string[] { email }; _emailSettings.Cc = new string[] { email };
_validator.Validate(_emailSettings).IsValid.Should().BeFalse(); _validator.Validate(_emailSettings).IsValid.Should().BeFalse();
} }
@@ -94,7 +94,7 @@ namespace NzbDrone.Core.Test.NotificationTests.EmailTests
public void should_not_be_valid_if_to_bcc_cc_are_all_empty() public void should_not_be_valid_if_to_bcc_cc_are_all_empty()
{ {
_emailSettings.To = Array.Empty<string>(); _emailSettings.To = Array.Empty<string>();
_emailSettings.CC = Array.Empty<string>(); _emailSettings.Cc = Array.Empty<string>();
_emailSettings.Bcc = Array.Empty<string>(); _emailSettings.Bcc = Array.Empty<string>();
_validator.Validate(_emailSettings).IsValid.Should().BeFalse(); _validator.Validate(_emailSettings).IsValid.Should().BeFalse();
@@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@@ -13,10 +14,10 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.NotificationTests namespace NzbDrone.Core.Test.NotificationTests
{ {
[TestFixture] [TestFixture]
public class TraktServiceFixture : CoreTest<TraktService> public class TraktServiceFixture : CoreTest<Trakt>
{ {
private DownloadMessage _downloadMessage; private DownloadMessage _downloadMessage;
private TraktSettings _traktSettings; private NotificationDefinition _traktDefinition;
[SetUp] [SetUp]
public void Setup() public void Setup()
@@ -34,11 +35,17 @@ namespace NzbDrone.Core.Test.NotificationTests
} }
}; };
_traktSettings = new TraktSettings _traktDefinition = new NotificationDefinition
{ {
AccessToken = "", Settings = new TraktSettings
RefreshToken = "" {
AccessToken = "",
RefreshToken = "",
Expires = DateTime.Now.AddDays(1)
}
}; };
Subject.Definition = _traktDefinition;
} }
private void GiventValidMediaInfo(Quality quality, string audioChannels, string audioFormat, string scanType) private void GiventValidMediaInfo(Quality quality, string audioChannels, string audioFormat, string scanType)
@@ -56,7 +63,7 @@ namespace NzbDrone.Core.Test.NotificationTests
[Test] [Test]
public void should_add_collection_movie_if_null_mediainfo() public void should_add_collection_movie_if_null_mediainfo()
{ {
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile); Subject.OnDownload(_downloadMessage);
Mocker.GetMock<ITraktProxy>() Mocker.GetMock<ITraktProxy>()
.Verify(v => v.AddToCollection(It.IsAny<TraktCollectMoviesResource>(), It.IsAny<string>()), Times.Once()); .Verify(v => v.AddToCollection(It.IsAny<TraktCollectMoviesResource>(), It.IsAny<string>()), Times.Once());
@@ -67,7 +74,7 @@ namespace NzbDrone.Core.Test.NotificationTests
{ {
GiventValidMediaInfo(Quality.Bluray1080p, "5.1", "DTS", "Progressive"); GiventValidMediaInfo(Quality.Bluray1080p, "5.1", "DTS", "Progressive");
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile); Subject.OnDownload(_downloadMessage);
Mocker.GetMock<ITraktProxy>() Mocker.GetMock<ITraktProxy>()
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t => .Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
@@ -83,7 +90,7 @@ namespace NzbDrone.Core.Test.NotificationTests
{ {
GiventValidMediaInfo(Quality.Bluray1080p, "2.0", "DTS", "Progressive"); GiventValidMediaInfo(Quality.Bluray1080p, "2.0", "DTS", "Progressive");
Subject.AddMovieToCollection(_traktSettings, _downloadMessage.Movie, _downloadMessage.MovieFile); Subject.OnDownload(_downloadMessage);
Mocker.GetMock<ITraktProxy>() Mocker.GetMock<ITraktProxy>()
.Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t => .Verify(v => v.AddToCollection(It.Is<TraktCollectMoviesResource>(t =>
@@ -10,6 +10,8 @@ namespace NzbDrone.Core.Test.OrganizerTests
{ {
[TestCase("Mission: Impossible - no [HDTV-720p]", [TestCase("Mission: Impossible - no [HDTV-720p]",
"Mission Impossible - no [HDTV-720p]")] "Mission Impossible - no [HDTV-720p]")]
[TestCase(".45 (2006)", "45 (2006)")]
[TestCase(" The Movie Title ", "The Movie Title")]
public void CleanFileName(string name, string expectedName) public void CleanFileName(string name, string expectedName)
{ {
FileNameBuilder.CleanFileName(name).Should().Be(expectedName); FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
@@ -562,19 +562,6 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.Should().Be(string.Format("HDTV-720p{0}South{0}Park", separator)); .Should().Be(string.Format("HDTV-720p{0}South{0}Park", separator));
} }
[Test]
public void should_be_able_to_use_original_filename()
{
_movie.Title = "30 Rock";
_namingConfig.StandardMovieFormat = "{Movie Title} - {Original Filename}";
_movieFile.SceneName = "30.Rock.S01E01.xvid-LOL";
_movieFile.RelativePath = "30 Rock - S01E01 - Test";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("30 Rock - 30 Rock - S01E01 - Test");
}
[TestCase("en-US")] [TestCase("en-US")]
[TestCase("fr-FR")] [TestCase("fr-FR")]
[TestCase("az")] [TestCase("az")]

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