1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-05 13:21:25 -05:00

Compare commits

..

128 Commits

Author SHA1 Message Date
Marcelo Castagna
85dd5f5754 Update Synology error codes
(cherry picked from commit a8cb7784f2a6f833bda9e24ca2146701df8da75c)
2022-02-27 11:57:59 -06:00
Robin Dadswell
7de270b212 Fixed: Remove pre-DB from frontend storage 2022-02-25 18:16:08 -06:00
Robin Dadswell
b1afd7aaaa Fixed: Removing multiple items from the queue wording 2022-02-23 13:31:15 +00:00
bakerboy448
894fafcad7 Fixed: Improve help text for download client Category
(cherry picked from commit d18751eff2c684a72e4c698a1e0f6c282c8da0da)
Closes #7056
2022-02-22 21:41:45 +00:00
bakerboy448
2cf62915b0 New: Update Cert Validation Help Text [common]
(cherry picked from commit 66be23a7c4ae717cf060f5e89b4df7a08bdff5ac)
Closes #7065
2022-02-22 21:41:45 +00:00
PearsonFlyer
d3743446da Fixed: Updated ruTorrent stopped state helptext
(cherry picked from commit 69ccb96a365b12ec57cfb642f52f7c6ab8c67262)
2022-02-21 19:51:41 -06:00
4toomany
b332fa55de fixed text box not being uniform to others 2022-02-21 19:47:28 -06:00
Zack Eckersley Pallett
36da57f87b New: Add backup size information
Closes #4830

(cherry picked from commit 78aeda1a2cc217c367c5c3c6fd281c101b28413c)
2022-02-21 22:53:47 +00:00
Robin Dadswell
07bb5e416b Fix swagger inCinema references 2022-02-21 22:53:39 +00:00
Mark McDowall
69207ba77b Fixed: Recycle bin log message
(cherry picked from commit 9e1b799fb74c341510d6da98f9f658d642b25c02)
2022-02-21 22:53:33 +00:00
bakerboy448
ff409d3661 Fix nzbdrone reference 2022-02-21 21:29:34 +00:00
bakerboy448
dfb8d2ea0f additional testcase obfuscation
closes #6850
2022-02-21 21:24:58 +00:00
Ajax
603db7c76b Fixed: IPv4 instead of IP4
(cherry picked from commit c7427f8df828733a81d83ea28393a18d10875769)
2022-02-21 15:08:06 -06:00
ta264
6fa0cdc9a8 Report runtime identifier to sentry
(cherry picked from commit 6d9413627388c2004c3a5dffdbe2269dadeef326)
2022-02-20 20:49:30 +00:00
ta264
c0cbbc7ed4 Update API URL 2022-02-18 12:39:46 -06:00
ta264
daa9ee30a2 Fixed: No longer require first run as admin on windows
(cherry picked from commit 8d9302da7761752189b2d2820915d7d13197ce47)
2022-02-18 11:42:31 +00:00
ta264
86102349c5 Build installer from build.sh
(cherry picked from commit 6db135877a8394244a95142347b99ea651e0cceb)

Closes #6958
2022-02-18 11:42:31 +00:00
ta264
c4d035f0ad Fixed: Enable response compression over https
(cherry picked from commit cb0ae3603309daae4d6b026de15f26cb4b59096d)
2022-02-16 19:06:37 +00:00
Qstick
95d44f968f Bump to 4.0.5 2022-01-30 21:25:25 -06:00
ta264
e7a8f6332c Fixed: Handle missing category when getting Qbittorrent download path
Fixes RADARR-7HC
Fixes RADARR-V49

(cherry picked from commit 6f97ca9a55471386454457ca52b93733e18e85e4)
Closes #6993
2022-01-25 20:10:52 -06:00
Qstick
b8c92d23f4 Fixed: Ignore case for DIVX VideoCodecID 2022-01-25 19:01:01 -06:00
bakerboy448
093e076db0 Fixed: Clarify Indexer Priority Helptext 2022-01-24 19:35:38 -06:00
Volodymyr Medvid
f6f949415c Fix Ukrainian language mappings 2022-01-24 19:23:12 -06:00
Qstick
ea2576a56c Bump to 4.0.4 2022-01-23 19:03:07 -06:00
Qstick
595acb696d Fixed: Bump FFMpegCore to avoid DivideByZero error 2022-01-23 18:24:28 -06:00
Qstick
38c9534eac Fixed: Webhook fails due to Frames/Analysis property serialization on MediaInfo 2022-01-23 18:24:28 -06:00
bakerboy448
9377ef7942 Fixed: Improved Indexer test failure message when no results are returned
(cherry picked from commit 05b1581b7dfa5bc8a2b38a60179e3472c8134f74)
2022-01-23 16:18:37 -06:00
bakerboy448
c2e5686bcf fixed sonarr ref in UTorrentSettings 2022-01-23 14:44:31 -06:00
Qstick
f08807daf6 Update donation links [common] 2022-01-23 12:12:16 -06:00
bakerboy448
72b3caa72d Fixed: Various Translations 2022-01-21 18:52:46 -06:00
Qstick
589368781b Fixed Incorrect placeholder width on search page
Co-Authored-By: nitsua <8321115+austinwbest@users.noreply.github.com>
2022-01-20 21:12:30 -06:00
Qstick
8fd6101121 New: Add AppName to system status response
Fixes #6952
2022-01-18 23:23:41 -06:00
Mark McDowall
ac9d6cbf0a Fixed: Jump bar on series page not showing when window is made wider
(cherry picked from commit 0cb8d93069d6310abd39ee2fe73219e17aa83fe6)
2022-01-17 11:30:47 -06:00
Qstick
6e0ed36e9f Fixed: Correct queue color for status bars 2022-01-17 08:58:07 -06:00
Qstick
fcb65055ef Bump to 4.0.3 2022-01-15 16:24:50 -06:00
bakerboy448
90456bbfed fixup 2022-01-15 14:51:11 -06:00
bakerboy448
2a74b7b2e1 Fixed: Parse HD.DVD as BluRay
Fixes #6925
2022-01-15 14:51:11 -06:00
Qstick
fc08c39fb8 Fixed: Revert manual import augmentation for unknown items 2022-01-15 14:24:51 -06:00
PearsonFlyer
76d65bf990 Fixed: Translation warning for search all 2022-01-15 07:27:58 -06:00
ta264
de243991dd Support for digest auth with HttpRequests
(cherry picked from commit 1e2d931f9a)
2022-01-13 19:23:30 -06:00
Qstick
4d1f251c1f Bump version 4.0.2 2022-01-10 19:59:16 -06:00
Qstick
ebb1e3131a Fixed: Use general settings cert validation for email 2022-01-10 09:17:54 -05:00
Qstick
6e502d63c2 Fixed: Handle wmapro and wmv3 codecs in formatter
Fixes RADARR-1G5R
Fixes RADARR-1G7V
2022-01-08 13:50:03 -06:00
Qstick
57e05b70da Remove unused variable from MovieHistoryRow 2022-01-08 01:09:02 -06:00
Qstick
59186adbfc Fixed: Mark as Failed from Movie Details page
Fixes #6483
2022-01-08 00:54:27 -06:00
Qstick
bc20e159ba Bump dotnet to 6.0.1
Security patch release
2022-01-07 21:33:48 -06:00
ta264
39b99341cd Fixed: Use our own HttpClient for Aria2 requests
[common]
2022-01-07 21:22:55 -06:00
ta264
b626c5bbf0 Fixed: Use our own HttpClient for rTorrent RPC requests
[common]
2022-01-07 21:22:55 -06:00
Robin Dadswell
a33b861cec Fixed: Download Client not sending on Import or Upgrade notifications (#6908)
* Fixed: Download client and ID for custom scripts

Based on Sonarr Commit eea3419849

* fixup! test

Co-authored-by: Qstick <qstick@gmail.com>
2022-01-06 22:04:10 -06:00
Qstick
3a48f07702 Fixed: Twitter connect not sending messages after http rework (#6901) [common] 2022-01-06 21:42:32 -06:00
Weblate
1aec0b7ee5 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 99.9% (1106 of 1107 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 99.0% (1096 of 1107 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.5% (1102 of 1107 strings)

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

Currently translated at 99.8% (1105 of 1107 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1106 of 1107 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 97.2% (1077 of 1107 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.4% (1097 of 1103 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1103 of 1103 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.6% (1088 of 1103 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Gian Klug <gian.klug@ict-scouts.ch>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Math <thimath62@live.fr>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: diemade <spamkill@posteo.ch>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
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/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2022-01-06 21:32:57 -06:00
nitsua
3e32161791 Fix broken headers on List Exclusion table 2022-01-05 20:03:50 -06:00
Qstick
fda1ad237b Fixed: Map DV Blu-ray to HDR10 compatibility 2022-01-04 23:46:36 -06:00
bakerboy448
52b6f39026 Fixed: Update indexer flag help link 2022-01-04 21:53:40 -06:00
Qstick
100fd95dd9 Fixed: Fix bad ratings objects in Migration 206 2022-01-03 20:20:16 -06:00
Mehul Vaghani
d571c7b75a Fixed: Updated link to Indexer Flags (#6893)
* Fixed: Updated link to Indexer Flags

* Fix: Updated link to Indexer Flags documentation

* Fix: Updated link to reflect right section
2022-01-03 18:15:32 -06:00
Qstick
8d7f48739b Bump version to 4.0.1 2022-01-03 14:20:47 -06:00
Mark McDowall
c061d7cec8 Fixed: Report certificate validation failures when configuring Plex Media Server connection
Closes #6797

(cherry picked from commit ec62884649f7af5f0a29346741754590e6de99ce)
2022-01-02 18:56:33 -06:00
Mark McDowall
91691205db Fixed: Download client name in history details
Closes #6838
2022-01-02 18:54:24 -06:00
Qstick
c1e07b30d7 Bump DSN for 4.0.0 2022-01-02 18:46:22 -06:00
Qstick
78a7770858 Fix CSS classes for Imdb and Tmdb ratings 2022-01-01 22:12:10 -06:00
Qstick
599f4907f4 New: Imdb Ratings 2022-01-01 20:18:18 -06:00
Weblate
ec9a7f5c8e Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 99.9% (1101 of 1102 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1101 of 1102 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 97.0% (1070 of 1102 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.8% (1089 of 1102 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.8% (1089 of 1102 strings)

Update translation files  [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: François-Xavier Payet <fx.payet@tfdn.cloud>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: diemade <spamkill@posteo.ch>
Co-authored-by: reloxx <reloxx@interia.pl>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2022-01-01 16:50:43 -06:00
Robin Dadswell
54c914d48f New: End Jackett 'all' endpoint support
[common]
2022-01-01 19:26:13 +00:00
Qstick
75270d8151 Fixed: Avoid ArgumentRangeException on FFProbe check when no sidedata frames
Fixes RADARR-1G5Q
2022-01-01 10:48:24 -06:00
Qstick
7a859f340b Fixed: Avoid download path check false positives for flood 2021-12-29 18:25:11 -06:00
bakerboy448
13e44ce19a New: Add {MediaInfo VideoDynamicRangeType} token for renaming
New: Detect HDR Type
New: Display HDR Type in File Media Info Modal

Based on Sonarr 7b694ea71d7f78bad5c03393c4cf6f7a28ada1cb

Closes #6789
Fixes #4844

Co-authored-by: ta264 <ta264@users.noreply.github.com>
Co-authored-by: Qstick <qstick@gmail.com>
2021-12-29 10:10:11 -06:00
Weblate
9e4c94592d Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translation: Servarr/Radarr
2021-12-28 17:06:21 -06:00
Weblate
9d2a59b7fd Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

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

Currently translated at 100.0% (1116 of 1116 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1115 of 1116 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2021-12-27 17:44:28 -06:00
bakerboy448
194e0f3d7f Fixed: Various Translations 2021-12-26 21:49:44 -06:00
Qstick
d1fa92bc6c Fixed: Manual Import language handling 2021-12-26 19:41:37 -06:00
Qstick
974e44ce48 New: Link indexer to specific download client 2021-12-26 19:07:22 -06:00
Taloth Saldono
de05be62d7 Added BDLight to quality parser
(cherry picked from commit 5c8f2518baa1b2d4a8b0507f9fafe12b2ecff1e5)
2021-12-26 19:05:11 -06:00
Qstick
cae5badee0 New: Support server notifications
(cherry picked from commit f5f0dd6fae5bc9f308506d56be42ac9a4be908e7)

Closes Radarr #5393

[common]
2021-12-26 15:48:28 -06:00
Qstick
45d8227654 Fixed: Handle MS variant MPEG4 files in video formatter 2021-12-25 18:24:30 -06:00
ta264
7bbd2246c4 Fix secondary ffprobe scan 2021-12-24 17:47:17 +00:00
ta264
59fed13442 MediaInfoModel initializer -> assignment for NRE tracking 2021-12-23 21:41:38 +00:00
Qstick
50b273acae Fixed: Ignore permissions issues on recycle bin files 2021-12-24 11:05:22 -06:00
Qstick
4278415fd7 Fixed: Default MinAvail to Released if not passed on add
Fixes #2117
2021-12-24 11:05:22 -06:00
Qstick
124b50288d Fix invalid PropType for sizeOnDisk in DeleteMovieModal 2021-12-24 11:05:22 -06:00
bakerboy448
3fcc395964 Fixed: Escape Characters as needed for *znab queries
Fixes #6799

[common]
2021-12-23 15:12:05 -06:00
Weblate
0ee9981cba Translated using Weblate (Arabic) [skip ci]
Currently translated at 95.7% (1069 of 1116 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 98.5% (1100 of 1116 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.7% (1113 of 1116 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.5% (1111 of 1116 strings)

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

Currently translated at 100.0% (1116 of 1116 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 10.1% (113 of 1114 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 10.0% (112 of 1113 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 98.0% (1091 of 1113 strings)

Added translation using Weblate (Ukrainian) [skip ci]

Added translation using Weblate (Persian) [skip ci]

Added translation using Weblate (Bengali) [skip ci]

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: htrex <hantarex@gmail.com>
Co-authored-by: rakan <rakaz30@hotmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ar/
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/it/
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/
Translation: Servarr/Radarr
2021-12-23 15:10:42 -06:00
Qstick
2848899206 Fixed: Calendar can show incorrect Release Types 2021-12-23 14:34:48 -06:00
Qstick
f1a00764cd New: Additional logging for InvalidModel BadRequest API calls
[common]
2021-12-23 14:22:09 -06:00
Qstick
346236764c Drop all Commands rows before running migration 204 2021-12-23 11:50:13 -06:00
Qstick
eecd4e4b7d New: Allow Import to update existing Custom Formats
Fixes #6178
2021-12-21 19:18:36 -06:00
Qstick
2838d8ca29 Add Ratings to Movie Index sort menu
Fixes #6741
2021-12-21 19:01:11 -06:00
bakerboy448
4ebcbc28aa fix applicationupdate filename typo
fix onapplicationupdate translate typo
2021-12-21 18:23:42 -06:00
Qstick
2c24f7ca04 Ensure Identity on Tables that have been modified 2021-12-21 18:09:05 -06:00
Qstick
ec86de78d2 Maintain PrimaryKey and AutoIncrement on some schemas
[common]
2021-12-21 17:45:00 -06:00
Qstick
4f5f9ff77e Update NotificationResource.cs 2021-12-21 16:07:25 -06:00
erikp9
465bb403a9 fixed hardsub detection 2021-12-21 07:58:13 -06:00
Qstick
9e175e28ef New: OnApplicationUpdate Notifications (#6854)
Fixes #4681
[common]
2021-12-20 23:12:12 -06:00
Qstick
4d2a311e40 Remove PreDB from MovieStatusType
Fixes #5002
2021-12-20 21:25:07 -06:00
Qstick
b2195148a2 Fixed: NullRef in SchemaBuilder when sending payload without optional Provider.Settings fields 2021-12-20 20:38:16 -06:00
Qstick
2ae7371d73 Update Deluge log statements 2021-12-20 20:35:38 -06:00
Mark McDowall
7b03a856c9 Fixed: Increase width and truncate long titles on Import List Exclusions
Closes #6779

(cherry picked from commit 2d0541c03b761a0ec5e10711d6bd577e07141517)
2021-12-20 20:16:22 -06:00
Qstick
48d1d47b67 Rename ImportExclusions to ImportListExclusions 2021-12-20 20:16:22 -06:00
Qstick
906b9bb92a Fixed: Use unmodified titles when searching Nyaa
Fixes #6642

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-12-20 20:16:22 -06:00
Mark McDowall
6fc14278e6 Fixed: Parsing of quality when release group contains Remux
Closes #6607
2021-12-20 19:58:47 -06:00
Mark McDowall
34b269086d Fixed: Get full path for download station instead of shared folder
Closes #6751
Fixes #6818

(cherry picked from commit b184e62fa7dd7ecd089619f176e6388c1c3be25d)
2021-12-20 19:55:09 -06:00
Qstick
6c40a27f2e Restore Parse API compatibility
Fixes #6852
2021-12-20 19:54:01 -06:00
Qstick
be158a09b4 Ensure new languages are in All collection 2021-12-20 19:44:35 -06:00
Robin Dadswell
eecd746f51 New: Health check for Discord notifications setup as Slack 2021-12-21 00:59:53 +00:00
Robin Dadswell
5ed034320e New: Migrate Discord from Slack to Discord notifications 2021-12-21 00:59:53 +00:00
bakerboy448
41dd678dfd Better wording of MissingFromDisk
closes #6834
2021-12-20 18:56:52 -06:00
Qstick
716eadc551 Add Multiple Languages
Closes #6385
Closes #6564
Closes #6694
Closes #6463

Co-Authored-By: siankatabg <siankatabg@users.noreply.github.com>
Co-Authored-By: tandy1000 <24867509+tandy-1000@users.noreply.github.com>
Co-Authored-By: Kristof Mattei <864376+kristof-mattei@users.noreply.github.com>
Co-Authored-By: Oleksandr Hulyi <4095184+pamidur@users.noreply.github.com>
2021-12-20 18:01:00 -06:00
bakerboy448
1cb31aa95c Fixed: Support movies with French in their title
Regression: Dropped Support for poorly named French Releases

Add language test case

Fixes #6821
2021-12-20 17:32:53 -06:00
Weblate
568dd2fbb2 Translated using Weblate (German) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 99.9% (1112 of 1113 strings)

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

Currently translated at 100.0% (1113 of 1113 strings)

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
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/ru/
Translation: Servarr/Radarr
2021-12-20 17:21:44 -06:00
Qstick
5d091e519e More Bluray UHD test cases
Fixes #6839
2021-12-19 22:57:06 -06:00
Qstick
faab78c00a Fixed: Improve WEBDL detection of Netflix Rips
Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2021-12-19 22:53:51 -06:00
Qstick
f1461056ce Fixed: Parsing of Ger.Dub releases as German
Fixes #6778

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2021-12-19 22:50:42 -06:00
ta264
2042ffce62 Fixed: Don't buffer update package to memory when downloading
[common]
2021-12-19 22:32:37 -06:00
ta264
c6ae6f7b1c Reinstate update tests on BSD
[common]
2021-12-19 22:32:37 -06:00
Weblate
8d7affae68 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2021-12-19 22:29:56 -06:00
Qstick
a418111245 remove removeHandler net6 serialization frontend hack 2021-12-19 20:39:45 -06:00
Qstick
6359ed5757 Bump RestSharp in test package to 106.15.0 2021-12-18 10:04:26 -06:00
Weblate
9a8c1d7d1b Translated using Weblate (Hungarian) [skip ci]
Currently translated at 100.0% (1113 of 1113 strings)

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

Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 97.2% (1082 of 1113 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Jessie <1355239678@qq.com>
Co-authored-by: Nuno Filipe de Vilhena Santos <nunovilhenasantos@msn.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2021-12-15 22:04:26 -06:00
bakerboy448
e89c2ee9f7 Fixed: Better wording of MissingFromDisk
[common]
2021-12-14 21:08:23 +00:00
Servarr
3d36f88939 Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci] (#6810)
Currently translated at 100.0% (1113 of 1113 strings)

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

Currently translated at 99.9% (1112 of 1113 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1113 of 1113 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.7% (1110 of 1113 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1113 of 1113 strings)

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: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 西行寺鬼鬼子 <zhang.yaowei@live.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
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

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 西行寺鬼鬼子 <zhang.yaowei@live.com>
2021-12-13 22:37:07 -05:00
Jacob Roeland
8e4320a93b Fix FAQ Link on Add New Movie page 2021-12-13 07:36:23 -06:00
Servarr
b095676010 Translations using Weblate [skip ci] 2021-12-12 11:28:24 -06:00
bakerboy448
41d69d8484 fix erroneous logging for windows service on non-windows
[common]
2021-12-11 22:20:16 -06:00
ta264
073e59e3db Fixed: Windows installer and adding/removing services
(cherry picked from commit 27e3b5e630f04b0774bd6693ffb1c79e7cab95d6)
2021-12-08 21:58:50 +00:00
ta264
588a0843a4 Fixed: Support older glibc in libMonoPosixHelper
(cherry picked from commit 9e7af8369e165c19a2f181071e63bef6961cd64e)
2021-12-08 16:04:51 -06:00
ta264
26cedfd47d Fixed: ffprobe on macOS 10.13 2021-12-07 21:11:35 +00:00
bakerboy448
16789e5b6b New: Display Unknown Items in Activity Queue by Default 2021-12-07 17:34:04 -06:00
Weblate
159edcde94 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 99.9% (1112 of 1113 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 98.6% (1098 of 1113 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.7% (1110 of 1113 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 96.8% (1078 of 1113 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: hidaba <nag@hidaba.com>
Co-authored-by: x-nemesis <fsedgy@outlook.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
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/
Translation: Servarr/Radarr
2021-12-07 17:33:52 -06:00
311 changed files with 3923 additions and 2386 deletions

View File

@@ -7,13 +7,14 @@ variables:
outputFolder: './_output'
artifactsFolder: './_artifacts'
testsFolder: './_tests'
majorVersion: '4.0.0'
majorVersion: '4.0.5'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.100'
dotnetVersion: '6.0.101'
innoVersion: '6.2.0'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
trigger:
@@ -200,16 +201,11 @@ stages:
artifactName: WindowsFrontend
targetPath: _output
displayName: Fetch Frontend
- bash: ./build.sh --packages
displayName: Create Packages
- bash: |
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x86
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
displayName: Create .NET Core Windows installer
- bash: |
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x64
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
displayName: Create .NET Core Windows installer
./build.sh --packages --installer
cp setup/output/Radarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
cp setup/output/Radarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
displayName: Create Installers
- publish: $(Build.ArtifactStagingDirectory)
artifact: 'WindowsInstaller'
displayName: Publish Installer

View File

@@ -233,6 +233,32 @@ Package()
esac
}
BuildInstaller()
{
local framework="$1"
local runtime="$2"
./_inno/ISCC.exe setup/radarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
}
InstallInno()
{
ProgressStart "Installing portable Inno Setup"
rm -rf _inno
curl -s --output innosetup.exe "https://files.jrsoftware.org/is/6/innosetup-${INNOVERSION:-6.2.0}.exe"
mkdir _inno
./innosetup.exe //portable=1 //silent //currentuser //dir=.\\_inno
rm innosetup.exe
ProgressEnd "Installed portable Inno Setup"
}
RemoveInno()
{
rm -rf _inno
}
PackageTests()
{
local framework="$1"
@@ -264,6 +290,7 @@ if [ $# -eq 0 ]; then
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
INSTALLER=NO
LINT=YES
ENABLE_BSD=NO
fi
@@ -299,6 +326,10 @@ case $key in
PACKAGES=YES
shift # past argument
;;
--installer)
INSTALLER=YES
shift # past argument
;;
--lint)
LINT=YES
shift # past argument
@@ -382,3 +413,11 @@ then
Package "$FRAMEWORK" "$RID"
fi
fi
if [ "$INSTALLER" = "YES" ];
then
InstallInno
BuildInstaller "net6.0" "win-x64"
BuildInstaller "net6.0" "win-x86"
RemoveInno
fi

View File

@@ -120,7 +120,7 @@ class Blocklist extends Component {
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Remove Selected"
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={!selectedIds.length}
isSpinning={isRemoving}

View File

@@ -25,6 +25,7 @@ function HistoryDetails(props) {
releaseGroup,
nzbInfoUrl,
downloadClient,
downloadClientName,
downloadId,
age,
ageHours,
@@ -32,6 +33,8 @@ function HistoryDetails(props) {
publishedDate
} = data;
const downloadClientNameInfo = downloadClientName ?? downloadClient;
return (
<DescriptionList>
<DescriptionListItem
@@ -71,11 +74,12 @@ function HistoryDetails(props) {
}
{
!!downloadClient &&
downloadClientNameInfo ?
<DescriptionListItem
title={translate('DownloadClient')}
data={downloadClient}
/>
data={downloadClientNameInfo}
/> :
null
}
{

View File

@@ -161,7 +161,7 @@ class AddNewMovie extends Component {
{translate('YouCanAlsoSearch')}
</div>
<div>
<Link to="https://wiki.servarr.com/radarr/faq#why-cant-i-add-a-new-movie-to-radarr">
<Link to="https://wiki.servarr.com/radarr/faq#why-can-i-not-add-a-new-movie-to-radarr">
{translate('CantFindMovie')}
</Link>
</div>

View File

@@ -86,6 +86,13 @@ class AddNewMovieSearchResult extends Component {
} = this.state;
const linkProps = isExistingMovie ? { to: `/movie/${titleSlug}` } : { onPress: this.onPress };
const posterWidth = 167;
const posterHeight = 250;
const elementStyle = {
width: `${posterWidth}px`,
height: `${posterHeight}px`
};
return (
<div className={styles.searchResult}>
@@ -102,6 +109,7 @@ class AddNewMovieSearchResult extends Component {
<div className={styles.posterContainer}>
<MoviePoster
className={styles.poster}
style={elementStyle}
images={images}
size={250}
overflow={true}
@@ -114,7 +122,7 @@ class AddNewMovieSearchResult extends Component {
monitored={monitored}
hasFile={hasFile}
status={status}
posterWidth={167}
posterWidth={posterWidth}
detailedProgressBar={true}
queueStatus={queueStatus}
queueState={queueState}
@@ -183,7 +191,7 @@ class AddNewMovieSearchResult extends Component {
<div>
<Label size={sizes.LARGE}>
<HeartRating
rating={ratings.value}
ratings={ratings}
iconSize={13}
/>
</Label>

View File

@@ -43,15 +43,15 @@ class CalendarEvent extends Component {
const link = `/movie/${titleSlug}`;
const eventType = [];
if (moment(date).isSame(moment(inCinemas), 'day')) {
if (inCinemas && moment(date).isSame(moment(inCinemas), 'day')) {
eventType.push('Cinemas');
}
if (moment(date).isSame(moment(physicalRelease), 'day')) {
if (physicalRelease && moment(date).isSame(moment(physicalRelease), 'day')) {
eventType.push('Physical');
}
if (moment(date).isSame(moment(digitalRelease), 'day')) {
if (digitalRelease && moment(date).isSame(moment(digitalRelease), 'day')) {
eventType.push('Digital');
}

View File

@@ -166,7 +166,9 @@ class FilterBuilderModalContent extends Component {
</div>
</div>
<div className={styles.label}>Filters</div>
<div className={styles.label}>
{translate('Filters')}
</div>
<div className={styles.rows}>
{

View File

@@ -6,8 +6,7 @@ import SelectInput from './SelectInput';
const availabilityOptions = [
{ key: 'announced', value: translate('Announced') },
{ key: 'inCinemas', value: translate('InCinemas') },
{ key: 'released', value: translate('Released') },
{ key: 'preDB', value: translate('PreDB') }
{ key: 'released', value: translate('Released') }
];
function AvailabilitySelectInput(props) {

View File

@@ -0,0 +1,100 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchDownloadClients } from 'Store/Actions/settingsActions';
import sortByName from 'Utilities/Array/sortByName';
import EnhancedSelectInput from './EnhancedSelectInput';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.downloadClients,
(state, { includeAny }) => includeAny,
(state, { protocol }) => protocol,
(downloadClients, includeAny, protocolFilter) => {
const {
isFetching,
isPopulated,
error,
items
} = downloadClients;
const filteredItems = items.filter((item) => item.protocol === protocolFilter);
const values = _.map(filteredItems.sort(sortByName), (downloadClient) => {
return {
key: downloadClient.id,
value: downloadClient.name
};
});
if (includeAny) {
values.unshift({
key: 0,
value: '(Any)'
});
}
return {
isFetching,
isPopulated,
error,
values
};
}
);
}
const mapDispatchToProps = {
dispatchFetchDownloadClients: fetchDownloadClients
};
class DownloadClientSelectInputConnector extends Component {
//
// Lifecycle
componentDidMount() {
if (!this.props.isPopulated) {
this.props.dispatchFetchDownloadClients();
}
}
//
// Listeners
onChange = ({ name, value }) => {
this.props.onChange({ name, value: parseInt(value) });
}
//
// Render
render() {
return (
<EnhancedSelectInput
{...this.props}
onChange={this.onChange}
/>
);
}
}
DownloadClientSelectInputConnector.propTypes = {
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired,
includeAny: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
dispatchFetchDownloadClients: PropTypes.func.isRequired
};
DownloadClientSelectInputConnector.defaultProps = {
includeAny: false,
protocol: 'torrent'
};
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientSelectInputConnector);

View File

@@ -8,6 +8,7 @@ import AvailabilitySelectInput from './AvailabilitySelectInput';
import CaptchaInputConnector from './CaptchaInputConnector';
import CheckInput from './CheckInput';
import DeviceInputConnector from './DeviceInputConnector';
import DownloadClientSelectInputConnector from './DownloadClientSelectInputConnector';
import EnhancedSelectInput from './EnhancedSelectInput';
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
import FormInputHelpText from './FormInputHelpText';
@@ -73,6 +74,9 @@ function getComponent(type) {
case inputTypes.INDEXER_FLAGS_SELECT:
return IndexerFlagsSelectInputConnector;
case inputTypes.DOWNLOAD_CLIENT_SELECT:
return DownloadClientSelectInputConnector;
case inputTypes.LANGUAGE_SELECT:
return LanguageSelectInputConnector;

View File

@@ -1,4 +1,5 @@
.heart {
.image {
align-content: center;
margin-right: 5px;
color: $themeRed;
vertical-align: -0.125em;
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
.image {
align-content: center;
margin-right: 5px;
vertical-align: -0.125em;
}

File diff suppressed because one or more lines are too long

View File

@@ -81,7 +81,7 @@ class PageHeader extends Component {
<IconButton
className={styles.donate}
name={icons.HEART}
to="https://opencollective.com/radarr"
to="https://radarr.video/donate"
size={14}
/>
<IconButton

View File

@@ -100,7 +100,9 @@ class PageJumpBar extends Component {
// Listeners
onMeasure = ({ height }) => {
this.setState({ height });
if (height > 0) {
this.setState({ height });
}
}
//

View File

@@ -0,0 +1,5 @@
.image {
align-content: center;
margin-right: 5px;
vertical-align: -0.125em;
}

View File

@@ -0,0 +1,58 @@
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import styles from './RottenTomatoRating.css';
class RottenTomatoRating extends PureComponent {
//
// Render
render() {
const {
ratings,
hideIcon,
iconSize
} = this.props;
const rtRotten = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ1LjE4NSA0NDQuNjg0Yy03OS4zNjkgNC4xNjctOTUuNTg3LTg2LjY1Mi0xMjYuNzI2LTg2LjAwNi0xMy4yNjguMjc5LTIzLjcyNiAxNC4xNTEtMTkuMTMzIDMwLjMyIDIuNTI1IDguODg4IDkuNTMgMjEuOTIzIDEzLjk0NCAzMC4wMTEgMTUuNTcgMjguNTQ0LTcuNDQ3IDYwLjg0NS0zNC4zODMgNjMuNTc3LTQ0Ljc2IDQuNTQtNjMuNDMzLTIxLjQyNi02Mi4yNzgtNDguMDA3IDEuMy0yOS44NCAyNi42LTYwLjMzMS42NS03My4zMDUtMjcuMTk0LTEzLjU5Ny00OS4zMDEgMzkuNTcyLTc1LjMyNSA1MS40MzktMjMuNTUzIDEwLjc0MS01Ni4yNDggMi40MTMtNjcuODcyLTIzLjc0MS04LjE2NC0xOC4zNzktNi42OC01My43NjggMjkuNjctNjcuMjcgMjIuNzA2LTguNDMzIDczLjMwNSAxMS4wMjkgNzUuOS0xMy42MjMgMi45OTItMjguNDE2LTUzLjE1NS0zMC44MTItNzAuMDYtMzcuNjI2LTI5LjkxMi0xMi4wNTUtNDcuNTY3LTM3Ljg1LTMzLjczNC02NS41MjIgMTAuMzc4LTIwLjc1NyA0MC45MTUtMjkuMjAzIDY0LjIyMy0yMC4xMSAyNy45MjIgMTAuODkyIDMyLjQwNCAzOS44NTMgNDYuNzEgNTEuODk3IDEyLjMyNCAxMC4zOCAyOS4xOSAxMS42OCA0MC4yMiA0LjU0MyA4LjEzNS01LjI2NSAxMC44NDMtMTYuODI4IDcuNzc0LTI3LjM5LTQuMDctMTQuMDIzLTE0Ljg3NS0yMi43NzMtMjUuNDE1LTMxLjM0Ni0xOC43NTgtMTUuMjQ5LTQ1LjI0LTI4LjM2LTI5LjIyMi02OS45ODMgMTMuMTMtMzQuMTEgNTEuNjQyLTM1LjM0IDUxLjY0Mi0zNS4zNCAxNS4zLTEuNzIgMjkuMDAyIDIuOSA0MC4xNjcgMTIuODc1IDE0LjkyNyAxMy4zMzUgMTcuODM0IDMxLjE2IDE1LjMzNiA1MC4xNzYtMi4yODMgMTcuMzU4LTguNDI2IDMyLjU2LTExLjYzIDQ5Ljc1OS0zLjcxNyAxOS45NjYgNi45NTQgNDAuMDg2IDI3LjI0OSA0MC44NjkgMjYuNjk0IDEuMDMxIDM0LjY5OC0xOS40ODYgMzcuOTY0LTMyLjQ5MiA0Ljc4Mi0xOS4wMjggMTEuMDU4LTM2LjY5NCAyOC43MTgtNDcuODIgMjUuMzQ2LTE1Ljk3IDYwLjU1Mi0xMi40NyA3Ni44ODYgMTguMjIyIDEyLjkyIDI0LjI4NCA4Ljc3MiA1Ny43MTUtMTEuMDQ3IDc1Ljk3LTguODkyIDguMTg4LTE5LjU4NCAxMS4wNzUtMzEuMTQ4IDExLjE1Ni0xNi41ODUuMTE3LTMzLjE2Mi0uMjktNDguNTU2IDcuNDcxLTEwLjQ4IDUuMjgxLTE1LjA0NyAxMy44ODgtMTUuMDQ1IDI1LjQyMyAwIDExLjI0MiA1Ljg1MyAxOC41ODUgMTUuMzM2IDIzLjM2MyAxNy44NiA5LjAwMyAzNy41NzcgMTAuODQzIDU2Ljg3MSAxNC4yMjIgMjcuOTggNC45IDUyLjU4MSAxNC43NTUgNjguMzc1IDQwLjcyLjE0Mi4yMjguMjguNDU4LjQxNS42OSAxOC4xMzkgMzAuNzQxLS44MzEgNzUuMDA1LTM2LjQ3NiA3Ni44NzgiIGZpbGw9IiMwQUM4NTUiLz48L3N2Zz4=';
const rtFresh = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNDc4LjI5IDI5Ni45OGMtMy45OS02My45NjYtMzYuNTItMTExLjgyLTg1LjQ2OC0xMzguNTggMC4yNzggMS41Ni0xLjEwOSAzLjUwOC0yLjY4OCAyLjgxOC0zMi4wMTYtMTQuMDA2LTg2LjMyOCAzMS4zMi0xMjQuMjggNy41ODQgMC4yODUgOC41MTktMS4zNzggNTAuMDcyLTU5LjkxNCA1Mi40ODMtMS4zODIgMC4wNTYtMi4xNDItMS4zNTUtMS4yNjgtMi4zNTQgNy44MjgtOC45MjkgMTUuNzMyLTMxLjUzNSA0LjM2Ny00My41ODYtMjQuMzM4IDIxLjgxLTM4LjQ3MiAzMC4wMTctODUuMTM4IDE5LjE4Ni0yOS44NzggMzEuMjQxLTQ2LjgwOSA3NC00My40ODUgMTI3LjI2IDYuNzggMTA4Ljc0IDEwOC42MyAxNzAuODkgMjExLjE5IDE2NC40OSAxMDIuNTYtNi4zOTUgMTkzLjQ3LTgwLjU3MiAxODYuNjgtMTg5LjMxIiBmaWxsPSIjRkEzMjBBIi8+PHBhdGggZD0iTTI5MS4zNzUgMTMyLjI5M2MyMS4wNzUtNS4wMjMgODEuNjkzLS40OSAxMDEuMTE0IDI1LjI3NCAxLjE2NiAxLjU0NS0uNDc1IDQuNDY4LTIuMzU1IDMuNjQ4LTMyLjAxNi0xNC4wMDYtODYuMzI4IDMxLjMyLTEyNC4yODIgNy41ODQuMjg1IDguNTE5LTEuMzc4IDUwLjA3Mi01OS45MTQgNTIuNDgzLTEuMzgyLjA1Ni0yLjE0Mi0xLjM1NS0xLjI2OC0yLjM1NCA3LjgyOC04LjkyOSAxNS43My0zMS41MzUgNC4zNjctNDMuNTg2LTI2LjUxMiAyMy43NTgtNDAuODg0IDMxLjM5Mi05OC40MjYgMTUuODM4LTEuODgzLS41MDgtMS4yNDEtMy41MzUuNzYyLTQuMjk4IDEwLjg3Ni00LjE1NyAzNS41MTUtMjIuMzYxIDU4LjgyNC0zMC4zODUgNC40MzgtMS41MjYgOC44NjItMi43MSAxMy4xOC0zLjQtMjUuNjY1LTIuMjkzLTM3LjIzNS01Ljg2Mi01My41NTktMy40LTEuNzg5LjI3LTMuMDA0LTEuODEzLTEuODk1LTMuMjQxIDIxLjk5NS0yOC4zMzIgNjIuNTEzLTM2Ljg4OCA4Ny41MTItMjEuODM3LTE1LjQxLTE5LjA5NC0yNy40OC0zNC4zMjEtMjcuNDgtMzQuMzIxbDI4LjYwMS0xNi4yNDZzMTEuODE3IDI2LjQgMjAuNDE0IDQ1LjYxNGMyMS4yNzUtMzEuNDM1IDYwLjg2LTM0LjMzNiA3Ny41ODUtMTIuMDMzLjk5MiAxLjMyNi0uMDQ1IDMuMjEtMS43MDIgMy4xNzEtMTMuNjEyLS4zMzEtMjEuMTA3IDEyLjA1LTIxLjY3NSAyMS40NjZsLjE5Ny4wMjMiIGZpbGw9IiMwMDkxMkQiLz48L3N2Zz4=';
const rating = ratings.rottenTomatoes;
let ratingString = '0%';
if (rating) {
ratingString = `${rating.value}%`;
}
return (
<span>
{
!hideIcon &&
<img
className={styles.image}
src={rating.value > 50 ? rtFresh : rtRotten}
style={{
height: `${iconSize}px`
}}
/>
}
{ratingString}
</span>
);
}
}
RottenTomatoRating.propTypes = {
ratings: PropTypes.object.isRequired,
iconSize: PropTypes.number.isRequired,
hideIcon: PropTypes.bool
};
RottenTomatoRating.defaultProps = {
iconSize: 14
};
export default RottenTomatoRating;

View File

@@ -0,0 +1,5 @@
.image {
align-content: center;
margin-right: 5px;
vertical-align: -0.125em;
}

View File

@@ -0,0 +1,57 @@
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import styles from './TmdbRating.css';
class TmdbRating extends PureComponent {
//
// Render
render() {
const {
ratings,
hideIcon,
iconSize
} = this.props;
const tmdbImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOTAuMjQgODEuNTIiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeTE9IjQwLjc2IiB4Mj0iMTkwLjI0IiB5Mj0iNDAuNzYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM5MGNlYTEiLz48c3RvcCBvZmZzZXQ9Ii41NiIgc3RvcC1jb2xvcj0iIzNjYmVjOSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzAwYjNlNSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGQ9Ik0xMDUuNjcgMzYuMDZoNjYuOWExNy42NyAxNy42NyAwIDAwMTcuNjctMTcuNjZBMTcuNjcgMTcuNjcgMCAwMDE3Mi41Ny43M2gtNjYuOUExNy42NyAxNy42NyAwIDAwODggMTguNGExNy42NyAxNy42NyAwIDAwMTcuNjcgMTcuNjZ6bS04OCA0NWg3Ni45YTE3LjY3IDE3LjY3IDAgMDAxNy42Ny0xNy42NiAxNy42NyAxNy42NyAwIDAwLTE3LjY3LTE3LjY3aC03Ni45QTE3LjY3IDE3LjY3IDAgMDAwIDYzLjRhMTcuNjcgMTcuNjcgMCAwMDE3LjY3IDE3LjY2em0tNy4yNi00NS42NGg3LjhWNi45MmgxMC4xVjBoLTI4djYuOWgxMC4xem0yOC4xIDBoNy44VjguMjVoLjFsOSAyNy4xNWg2bDkuMy0yNy4xNWguMVYzNS40aDcuOFYwSDY2Ljc2bC04LjIgMjMuMWgtLjFMNTAuMzEgMGgtMTEuOHptMTEzLjkyIDIwLjI1YTE1LjA3IDE1LjA3IDAgMDAtNC41Mi01LjUyIDE4LjU3IDE4LjU3IDAgMDAtNi42OC0zLjA4IDMzLjU0IDMzLjU0IDAgMDAtOC4wNy0xaC0xMS43djM1LjRoMTIuNzVhMjQuNTggMjQuNTggMCAwMDcuNTUtMS4xNSAxOS4zNCAxOS4zNCAwIDAwNi4zNS0zLjMyIDE2LjI3IDE2LjI3IDAgMDA0LjM3LTUuNSAxNi45MSAxNi45MSAwIDAwMS42My03LjU4IDE4LjUgMTguNSAwIDAwLTEuNjgtOC4yNXpNMTQ1IDY4LjZhOC44IDguOCAwIDAxLTIuNjQgMy40IDEwLjcgMTAuNyAwIDAxLTQgMS44MiAyMS41NyAyMS41NyAwIDAxLTUgLjU1aC00LjA1di0yMWg0LjZhMTcgMTcgMCAwMTQuNjcuNjMgMTEuNjYgMTEuNjYgMCAwMTMuODggMS44N0E5LjE0IDkuMTQgMCAwMTE0NSA1OWE5Ljg3IDkuODcgMCAwMTEgNC41MiAxMS44OSAxMS44OSAwIDAxLTEgNS4wOHptNDQuNjMtLjEzYTggOCAwIDAwLTEuNTgtMi42MiA4LjM4IDguMzggMCAwMC0yLjQyLTEuODUgMTAuMzEgMTAuMzEgMCAwMC0zLjE3LTF2LS4xYTkuMjIgOS4yMiAwIDAwNC40Mi0yLjgyIDcuNDMgNy40MyAwIDAwMS42OC01IDguNDIgOC40MiAwIDAwLTEuMTUtNC42NSA4LjA5IDguMDkgMCAwMC0zLTIuNzIgMTIuNTYgMTIuNTYgMCAwMC00LjE4LTEuMyAzMi44NCAzMi44NCAwIDAwLTQuNjItLjMzaC0xMy4ydjM1LjRoMTQuNWEyMi40MSAyMi40MSAwIDAwNC43Mi0uNSAxMy41MyAxMy41MyAwIDAwNC4yOC0xLjY1IDkuNDIgOS40MiAwIDAwMy4xLTMgOC41MiA4LjUyIDAgMDAxLjItNC42OCA5LjM5IDkuMzkgMCAwMC0uNTUtMy4xOHptLTE5LjQyLTE1Ljc1aDUuM2ExMCAxMCAwIDAxMS44NS4xOCA2LjE4IDYuMTggMCAwMTEuNy41NyAzLjM5IDMuMzkgMCAwMTEuMjIgMS4xMyAzLjIyIDMuMjIgMCAwMS40OCAxLjgyIDMuNjMgMy42MyAwIDAxLS40MyAxLjggMy40IDMuNCAwIDAxLTEuMTIgMS4yIDQuOTIgNC45MiAwIDAxLTEuNTguNjUgNy41MSA3LjUxIDAgMDEtMS43Ny4yaC01LjY1em0xMS43MiAyMGEzLjkgMy45IDAgMDEtMS4yMiAxLjMgNC42NCA0LjY0IDAgMDEtMS42OC43IDguMTggOC4xOCAwIDAxLTEuODIuMmgtN3YtOGg1LjlhMTUuMzUgMTUuMzUgMCAwMTIgLjE1IDguNDcgOC40NyAwIDAxMi4wNS41NSA0IDQgMCAwMTEuNTcgMS4xOCAzLjExIDMuMTEgMCAwMS42MyAyIDMuNzEgMy43MSAwIDAxLS40MyAxLjkyeiIgZmlsbD0idXJsKCNhKSIvPjwvc3ZnPg==';
const rating = ratings.tmdb;
let ratingString = '0%';
if (rating) {
ratingString = `${rating.value * 10}%`;
}
return (
<span title={`${rating.votes} votes`}>
{
!hideIcon &&
<img
className={styles.image}
src={tmdbImage}
style={{
height: `${iconSize}px`
}}
/>
}
{ratingString}
</span>
);
}
}
TmdbRating.propTypes = {
ratings: PropTypes.object.isRequired,
iconSize: PropTypes.number.isRequired,
hideIcon: PropTypes.bool
};
TmdbRating.defaultProps = {
iconSize: 14
};
export default TmdbRating;

View File

@@ -73,7 +73,7 @@ function getInfoRowProps(row, props) {
return {
title: translate('Ratings'),
iconName: icons.HEART,
label: `${props.ratings.value * 10}%`
label: `${props.ratings.tmdb.value * 10}%`
};
}

View File

@@ -112,7 +112,7 @@ function DiscoverMoviePosterInfo(props) {
return (
<div className={styles.info}>
<HeartRating
rating={ratings.value}
ratings={ratings}
/>
</div>
);
@@ -129,7 +129,7 @@ DiscoverMoviePosterInfo.propTypes = {
digitalRelease: PropTypes.string,
physicalRelease: PropTypes.string,
runtime: PropTypes.number,
ratings: PropTypes.object,
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
sortKey: PropTypes.string.isRequired,
showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,

View File

@@ -246,7 +246,7 @@ class DiscoverMovieRow extends Component {
className={styles[name]}
>
<HeartRating
rating={ratings.value}
ratings={ratings}
/>
</VirtualTableRowCell>
);
@@ -373,7 +373,7 @@ DiscoverMovieRow.propTypes = {
digitalRelease: PropTypes.string,
runtime: PropTypes.number,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
ratings: PropTypes.object.isRequired,
ratings: PropTypes.arrayOf(PropTypes.object).isRequired,
certification: PropTypes.string,
collection: PropTypes.object,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@@ -13,6 +13,7 @@ export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
export const LANGUAGE_SELECT = 'languageSelect';
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
export const SELECT = 'select';
export const DYNAMIC_SELECT = 'dynamicSelect';
export const TAG = 'tag';
@@ -35,6 +36,7 @@ export const all = [
PASSWORD,
PATH,
QUALITY_PROFILE_SELECT,
DOWNLOAD_CLIENT_SELECT,
ROOT_FOLDER_SELECT,
INDEXER_FLAGS_SELECT,
LANGUAGE_SELECT,

View File

@@ -19,6 +19,7 @@ import { align, icons, kinds, scrollDirections } from 'Helpers/Props';
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
@@ -40,6 +41,11 @@ const columns = [
isSortable: true,
isVisible: true
},
{
name: 'releaseGroup',
label: translate('ReleaseGroup'),
isVisible: true
},
{
name: 'quality',
label: translate('Quality'),
@@ -83,6 +89,7 @@ const SELECT = 'select';
const MOVIE = 'movie';
const LANGUAGE = 'language';
const QUALITY = 'quality';
const RELEASE_GROUP = 'releaseGroup';
class InteractiveImportModalContent extends Component {
@@ -202,10 +209,11 @@ class InteractiveImportModalContent extends Component {
const errorMessage = getErrorMessage(error, translate('UnableToLoadManualImportItems'));
const bulkSelectOptions = [
{
key: SELECT, value: translate('SelectDotDot'), disabled: true },
{ key: SELECT, value: translate('SelectDotDot'), disabled: true },
{ key: LANGUAGE, value: translate('SelectLanguage') },
{ key: QUALITY, value: translate('SelectQuality') }];
{ key: QUALITY, value: translate('SelectQuality') },
{ key: RELEASE_GROUP, value: translate('SelectReleaseGroup') }
];
if (allowMovieChange) {
bulkSelectOptions.splice(1, 0, {
@@ -372,6 +380,13 @@ class InteractiveImportModalContent extends Component {
real={false}
onModalClose={this.onSelectModalClose}
/>
<SelectReleaseGroupModal
isOpen={selectModalOpen === RELEASE_GROUP}
ids={selectedIds}
releaseGroup=""
onModalClose={this.onSelectModalClose}
/>
</ModalContent>
);
}

View File

@@ -110,7 +110,8 @@ class InteractiveImportModalContentConnector extends Component {
const {
movie,
quality,
languages
languages,
releaseGroup
} = item;
if (!movie) {
@@ -132,6 +133,7 @@ class InteractiveImportModalContentConnector extends Component {
path: item.path,
folderName: item.folderName,
movieId: movie.id,
releaseGroup,
quality,
languages,
downloadId: this.props.downloadId

View File

@@ -11,6 +11,7 @@ import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality';
import formatBytes from 'Utilities/Number/formatBytes';
@@ -28,6 +29,7 @@ class InteractiveImportRow extends Component {
this.state = {
isSelectMovieModalOpen: false,
isSelectReleaseGroupModalOpen: false,
isSelectQualityModalOpen: false,
isSelectLanguageModalOpen: false
};
@@ -103,6 +105,10 @@ class InteractiveImportRow extends Component {
this.setState({ isSelectMovieModalOpen: true });
}
onSelectReleaseGroupPress = () => {
this.setState({ isSelectReleaseGroupModalOpen: true });
}
onSelectQualityPress = () => {
this.setState({ isSelectQualityModalOpen: true });
}
@@ -116,6 +122,11 @@ class InteractiveImportRow extends Component {
this.selectRowAfterChange(changed);
}
onSelectReleaseGroupModalClose = (changed) => {
this.setState({ isSelectReleaseGroupModalOpen: false });
this.selectRowAfterChange(changed);
}
onSelectQualityModalClose = (changed) => {
this.setState({ isSelectQualityModalOpen: false });
this.selectRowAfterChange(changed);
@@ -137,6 +148,7 @@ class InteractiveImportRow extends Component {
movie,
quality,
languages,
releaseGroup,
size,
rejections,
isReprocessing,
@@ -147,7 +159,8 @@ class InteractiveImportRow extends Component {
const {
isSelectMovieModalOpen,
isSelectQualityModalOpen,
isSelectLanguageModalOpen
isSelectLanguageModalOpen,
isSelectReleaseGroupModalOpen
} = this.state;
const movieTitle = movie ? movie.title + ( movie.year > 0 ? ` (${movie.year})` : '') : '';
@@ -155,6 +168,7 @@ class InteractiveImportRow extends Component {
const showMoviePlaceholder = isSelected && !movie;
const showQualityPlaceholder = isSelected && !quality;
const showLanguagePlaceholder = isSelected && !languages && !isReprocessing;
const showReleaseGroupPlaceholder = isSelected && !releaseGroup;
return (
<TableRow>
@@ -181,6 +195,17 @@ class InteractiveImportRow extends Component {
}
</TableRowCellButton>
<TableRowCellButton
title={translate('ClickToChangeReleaseGroup')}
onPress={this.onSelectReleaseGroupPress}
>
{
showReleaseGroupPlaceholder ?
<InteractiveImportRowCellPlaceholder /> :
releaseGroup
}
</TableRowCellButton>
<TableRowCellButton
className={styles.quality}
title={translate('ClickToChangeQuality')}
@@ -268,6 +293,13 @@ class InteractiveImportRow extends Component {
onModalClose={this.onSelectMovieModalClose}
/>
<SelectReleaseGroupModal
isOpen={isSelectReleaseGroupModalOpen}
ids={[id]}
releaseGroup={releaseGroup ?? ''}
onModalClose={this.onSelectReleaseGroupModalClose}
/>
<SelectQualityModal
isOpen={isSelectQualityModalOpen}
ids={[id]}
@@ -296,6 +328,7 @@ InteractiveImportRow.propTypes = {
movie: PropTypes.object,
quality: PropTypes.object,
languages: PropTypes.arrayOf(PropTypes.object),
releaseGroup: PropTypes.string,
size: PropTypes.number.isRequired,
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
isReprocessing: PropTypes.bool,

View File

@@ -128,7 +128,7 @@ class SelectLanguageModalContent extends Component {
kind={kinds.SUCCESS}
onPress={this.onLanguageSelect}
>
{translate('SelectLanguges')}
{translate('SelectLanguages')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -0,0 +1,37 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Modal from 'Components/Modal/Modal';
import SelectReleaseGroupModalContentConnector from './SelectReleaseGroupModalContentConnector';
class SelectReleaseGroupModal extends Component {
//
// Render
render() {
const {
isOpen,
onModalClose,
...otherProps
} = this.props;
return (
<Modal
isOpen={isOpen}
onModalClose={onModalClose}
>
<SelectReleaseGroupModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
}
SelectReleaseGroupModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectReleaseGroupModal;

View File

@@ -0,0 +1,99 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class SelectReleaseGroupModalContent extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
const {
releaseGroup
} = props;
this.state = {
releaseGroup
};
}
//
// Listeners
onReleaseGroupChange = ({ value }) => {
this.setState({ releaseGroup: value });
}
onReleaseGroupSelect = () => {
this.props.onReleaseGroupSelect(this.state);
}
//
// Render
render() {
const {
onModalClose
} = this.props;
const {
releaseGroup
} = this.state;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('ManualImportSetReleaseGroup')}
</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<FormLabel>{translate('ReleaseGroup')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="releaseGroup"
value={releaseGroup}
onChange={this.onReleaseGroupChange}
/>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>
{translate('Cancel')}
</Button>
<Button
kind={kinds.SUCCESS}
onPress={this.onReleaseGroupSelect}
>
{translate('SetReleaseGroup')}
</Button>
</ModalFooter>
</ModalContent>
);
}
}
SelectReleaseGroupModalContent.propTypes = {
releaseGroup: PropTypes.string.isRequired,
onReleaseGroupSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default SelectReleaseGroupModalContent;

View File

@@ -0,0 +1,54 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reprocessInteractiveImportItems, updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions';
import SelectReleaseGroupModalContent from './SelectReleaseGroupModalContent';
const mapDispatchToProps = {
dispatchUpdateInteractiveImportItems: updateInteractiveImportItems,
dispatchReprocessInteractiveImportItems: reprocessInteractiveImportItems
};
class SelectReleaseGroupModalContentConnector extends Component {
//
// Listeners
onReleaseGroupSelect = ({ releaseGroup }) => {
const {
ids,
dispatchUpdateInteractiveImportItems,
dispatchReprocessInteractiveImportItems
} = this.props;
dispatchUpdateInteractiveImportItems({
ids,
releaseGroup
});
dispatchReprocessInteractiveImportItems({ ids });
this.props.onModalClose(true);
}
//
// Render
render() {
return (
<SelectReleaseGroupModalContent
{...this.props}
onReleaseGroupSelect={this.onReleaseGroupSelect}
/>
);
}
}
SelectReleaseGroupModalContentConnector.propTypes = {
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired,
dispatchReprocessInteractiveImportItems: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(null, mapDispatchToProps)(SelectReleaseGroupModalContentConnector);

View File

@@ -155,7 +155,7 @@ DeleteMovieModalContent.propTypes = {
title: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
hasFile: PropTypes.bool.isRequired,
sizeOnDisk: PropTypes.string.isRequired,
sizeOnDisk: PropTypes.number.isRequired,
onDeletePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};

View File

@@ -5,7 +5,7 @@
.header {
position: relative;
width: 100%;
height: 350px;
height: 375px;
}
.errorMessage {
@@ -41,8 +41,8 @@
.poster {
flex-shrink: 0;
margin-right: 35px;
width: 200px;
height: 294px;
width: 217px;
height: 319px;
}
.info {

View File

@@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import TextTruncate from 'react-text-truncate';
import HeartRating from 'Components/HeartRating';
import Icon from 'Components/Icon';
import ImdbRating from 'Components/ImdbRating';
import InfoLabel from 'Components/InfoLabel';
import IconButton from 'Components/Link/IconButton';
import Marquee from 'Components/Marquee';
@@ -16,6 +16,8 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import RottenTomatoRating from 'Components/RottenTomatoRating';
import TmdbRating from 'Components/TmdbRating';
import Popover from 'Components/Tooltip/Popover';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
@@ -449,17 +451,6 @@ class MovieDetails extends Component {
</span>
}
{
!!ratings &&
<span className={styles.rating}>
<HeartRating
rating={ratings.value}
iconSize={20}
hideHeart={isSmallScreen}
/>
</span>
}
{
<span className={styles.links}>
<Tooltip
@@ -501,6 +492,36 @@ class MovieDetails extends Component {
</div>
</div>
<div className={styles.details}>
{
!!ratings.tmdb &&
<span className={styles.rating}>
<TmdbRating
ratings={ratings}
iconSize={20}
/>
</span>
}
{
!!ratings.imdb &&
<span className={styles.rating}>
<ImdbRating
ratings={ratings}
iconSize={20}
/>
</span>
}
{
!!ratings.rottenTomatoes &&
<span className={styles.rating}>
<RottenTomatoRating
ratings={ratings}
iconSize={20}
/>
</span>
}
</div>
<div className={styles.detailsLabels}>
<InfoLabel
className={styles.detailsInfoLabel}

View File

@@ -67,8 +67,7 @@ class MovieHistoryRow extends Component {
data,
isMarkingAsFailed,
shortDateFormat,
timeFormat,
onMarkAsFailedPress
timeFormat
} = this.props;
const {
@@ -143,7 +142,7 @@ class MovieHistoryRow extends Component {
isMarkingAsFailed={isMarkingAsFailed}
shortDateFormat={shortDateFormat}
timeFormat={timeFormat}
onMarkAsFailedPress={onMarkAsFailedPress}
onMarkAsFailedPress={this.onMarkAsFailedPress}
onModalClose={this.onDetailsModalClose}
/>
</TableRow>

View File

@@ -101,6 +101,15 @@ function MovieIndexSortMenu(props) {
{translate('DigitalRelease')}
</SortMenuItem>
<SortMenuItem
name="ratings"
sortKey={sortKey}
sortDirection={sortDirection}
onPress={onSortSelect}
>
{translate('Ratings')}
</SortMenuItem>
<SortMenuItem
name="path"
sortKey={sortKey}

View File

@@ -332,7 +332,7 @@ class MovieIndexRow extends Component {
className={styles[name]}
>
<HeartRating
rating={ratings.value}
ratings={ratings}
/>
</VirtualTableRowCell>
);

View File

@@ -6,7 +6,7 @@ export function getMovieStatusDetails(status) {
let statusDetails = {
icon: icons.ANNOUNCED,
title: translate('Announced'),
message: translate('AnnoucedMsg')
message: translate('AnnouncedMsg')
};
if (status === 'deleted') {

View File

@@ -4,6 +4,11 @@
margin-right: auto;
}
.rightButtons {
justify-content: flex-end;
margin-right: auto;
}
.addSpecification {
composes: customFormat from '~./CustomFormat.css';

View File

@@ -198,26 +198,25 @@ class EditCustomFormatModalContent extends Component {
</div>
</ModalBody>
<ModalFooter>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteCustomFormatPress}
>
{translate('Delete')}
</Button>
}
<div className={styles.rightButtons}>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteCustomFormatPress}
>
{translate('Delete')}
</Button>
}
{
!id &&
<Button
className={styles.deleteButton}
onPress={this.onImportPress}
>
{translate('Import')}
</Button>
}
<Button
className={styles.deleteButton}
onPress={this.onImportPress}
>
{translate('Import')}
</Button>
</div>
<Button
onPress={onModalClose}

View File

@@ -51,9 +51,15 @@ class RemotePathMappings extends Component {
{...otherProps}
>
<div className={styles.remotePathMappingsHeader}>
<div className={styles.host}>Host</div>
<div className={styles.path}>Remote Path</div>
<div className={styles.path}>Local Path</div>
<div className={styles.host}>
{translate('Host')}
</div>
<div className={styles.path}>
{translate('RemotePath')}
</div>
<div className={styles.path}>
{translate('LocalPath')}
</div>
</div>
<div>

View File

@@ -2,16 +2,16 @@ import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import EditImportExclusionModalContentConnector from './EditImportExclusionModalContentConnector';
import EditImportListExclusionModalContentConnector from './EditImportListExclusionModalContentConnector';
function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
function EditImportListExclusionModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditImportExclusionModalContentConnector
<EditImportListExclusionModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
@@ -19,9 +19,9 @@ function EditImportExclusionModal({ isOpen, onModalClose, ...otherProps }) {
);
}
EditImportExclusionModal.propTypes = {
EditImportListExclusionModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditImportExclusionModal;
export default EditImportListExclusionModal;

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditImportExclusionModal from './EditImportExclusionModal';
import EditImportListExclusionModal from './EditImportListExclusionModal';
function mapStateToProps() {
return {};
@@ -12,7 +12,7 @@ const mapDispatchToProps = {
clearPendingChanges
};
class EditImportExclusionModalConnector extends Component {
class EditImportListExclusionModalConnector extends Component {
//
// Listeners
@@ -27,7 +27,7 @@ class EditImportExclusionModalConnector extends Component {
render() {
return (
<EditImportExclusionModal
<EditImportListExclusionModal
{...this.props}
onModalClose={this.onModalClose}
/>
@@ -35,9 +35,9 @@ class EditImportExclusionModalConnector extends Component {
}
}
EditImportExclusionModalConnector.propTypes = {
EditImportListExclusionModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditImportExclusionModalConnector);
export default connect(mapStateToProps, mapDispatchToProps)(EditImportListExclusionModalConnector);

View File

@@ -13,9 +13,9 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './EditImportExclusionModalContent.css';
import styles from './EditImportListExclusionModalContent.css';
function EditImportExclusionModalContent(props) {
function EditImportListExclusionModalContent(props) {
const {
id,
isFetching,
@@ -130,7 +130,7 @@ function EditImportExclusionModalContent(props) {
);
}
EditImportExclusionModalContent.propTypes = {
EditImportListExclusionModalContent.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
@@ -143,4 +143,4 @@ EditImportExclusionModalContent.propTypes = {
onDeleteImportExclusionPress: PropTypes.func
};
export default EditImportExclusionModalContent;
export default EditImportListExclusionModalContent;

View File

@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveImportExclusion, setImportExclusionValue } from 'Store/Actions/settingsActions';
import selectSettings from 'Store/Selectors/selectSettings';
import EditImportExclusionModalContent from './EditImportExclusionModalContent';
import EditImportListExclusionModalContent from './EditImportListExclusionModalContent';
const newImportExclusion = {
movieTitle: '',
@@ -97,7 +97,7 @@ class EditImportExclusionModalContentConnector extends Component {
render() {
return (
<EditImportExclusionModalContent
<EditImportListExclusionModalContent
{...this.props}
onSavePress={this.onSavePress}
onInputChange={this.onInputChange}

View File

@@ -8,12 +8,14 @@
}
.movieTitle {
flex: 0 0 400px;
@add-mixin truncate;
flex: 0 0 600px;
}
.tmdbId,
.movieYear {
flex: 0 0 200px;
flex: 0 0 70px;
}
.actions {

View File

@@ -6,10 +6,10 @@ import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
import styles from './ImportExclusion.css';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import styles from './ImportListExclusion.css';
class ImportExclusion extends Component {
class ImportListExclusion extends Component {
//
// Lifecycle
@@ -78,7 +78,7 @@ class ImportExclusion extends Component {
</Link>
</div>
<EditImportExclusionModalConnector
<EditImportListExclusionModalConnector
id={id}
isOpen={this.state.isEditImportExclusionModalOpen}
onModalClose={this.onEditImportExclusionModalClose}
@@ -99,7 +99,7 @@ class ImportExclusion extends Component {
}
}
ImportExclusion.propTypes = {
ImportListExclusion.propTypes = {
id: PropTypes.number.isRequired,
movieTitle: PropTypes.string.isRequired,
tmdbId: PropTypes.number.isRequired,
@@ -107,9 +107,9 @@ ImportExclusion.propTypes = {
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
};
ImportExclusion.defaultProps = {
ImportListExclusion.defaultProps = {
// The drag preview will not connect the drag handle.
connectDragSource: (node) => node
};
export default ImportExclusion;
export default ImportListExclusion;

View File

@@ -1,16 +1,16 @@
.importExclusionsHeader {
.importListExclusionsHeader {
display: flex;
margin-bottom: 10px;
font-weight: bold;
}
.title {
flex: 0 0 400px;
flex: 0 0 600px;
}
.tmdbId,
.movieYear {
flex: 0 0 200px;
flex: 0 0 70px;
}
.addImportExclusion {

View File

@@ -6,11 +6,11 @@ import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportExclusionModalConnector from './EditImportExclusionModalConnector';
import ImportExclusion from './ImportExclusion';
import styles from './ImportExclusions.css';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import ImportListExclusion from './ImportListExclusion';
import styles from './ImportListExclusions.css';
class ImportExclusions extends Component {
class ImportListExclusions extends Component {
//
// Lifecycle
@@ -50,17 +50,23 @@ class ImportExclusions extends Component {
errorMessage={translate('UnableToLoadListExclusions')}
{...otherProps}
>
<div className={styles.importExclusionsHeader}>
<div className={styles.tmdbId}>TMDB Id</div>
<div className={styles.title}>Title</div>
<div className={styles.movieYear}>Year</div>
<div className={styles.importListExclusionsHeader}>
<div className={styles.tmdbId}>
TMDb Id
</div>
<div className={styles.title}>
{translate('Title')}
</div>
<div className={styles.movieYear}>
{translate('Year')}
</div>
</div>
<div>
{
items.map((item, index) => {
return (
<ImportExclusion
<ImportListExclusion
key={item.id}
{...item}
{...otherProps}
@@ -81,7 +87,7 @@ class ImportExclusions extends Component {
</Link>
</div>
<EditImportExclusionModalConnector
<EditImportListExclusionModalConnector
isOpen={this.state.isAddImportExclusionModalOpen}
onModalClose={this.onModalClose}
/>
@@ -92,11 +98,11 @@ class ImportExclusions extends Component {
}
}
ImportExclusions.propTypes = {
ImportListExclusions.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteImportExclusion: PropTypes.func.isRequired
};
export default ImportExclusions;
export default ImportListExclusions;

View File

@@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteImportExclusion, fetchImportExclusions } from 'Store/Actions/settingsActions';
import ImportExclusions from './ImportExclusions';
import ImportListExclusions from './ImportListExclusions';
function createMapStateToProps() {
return createSelector(
@@ -42,7 +42,7 @@ class ImportExclusionsConnector extends Component {
render() {
return (
<ImportExclusions
<ImportListExclusions
{...this.state}
{...this.props}
onConfirmDeleteImportExclusion={this.onConfirmDeleteImportExclusion}

View File

@@ -7,7 +7,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import ImportExclusionsConnector from './ImportExclusions/ImportExclusionsConnector';
import ImportListExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
import ImportListsConnector from './ImportLists/ImportListsConnector';
import ImportListOptionsConnector from './Options/ImportListOptionsConnector';
@@ -86,7 +86,7 @@ class ImportListSettings extends Component {
onChildStateChange={this.onChildStateChange}
/>
<ImportExclusionsConnector />
<ImportListExclusionsConnector />
</PageContentBody>
</PageContent>

View File

@@ -45,7 +45,9 @@ function EditIndexerModalContent(props) {
supportsSearch,
tags,
fields,
priority
priority,
protocol,
downloadClientId
} = item;
return (
@@ -154,8 +156,25 @@ function EditIndexerModalContent(props) {
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('DownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.DOWNLOAD_CLIENT_SELECT}
name="downloadClientId"
helpText={translate('IndexerDownloadClientHelpText')}
{...downloadClientId}
includeAny={true}
protocol={protocol.value}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}

View File

@@ -85,7 +85,7 @@ function IndexerOptions(props) {
type={inputTypes.CHECK}
name="preferIndexerFlags"
helpText={translate('PreferIndexerFlagsHelpText')}
helpLink="https://wiki.servarr.com/Definitions#Indexer_Flags"
helpLink="https://wiki.servarr.com/radarr/settings#indexer-flags"
onChange={onInputChange}
{...settings.preferIndexerFlags}
/>
@@ -97,7 +97,7 @@ function IndexerOptions(props) {
<FormInputGroup
type={inputTypes.NUMBER}
name="availabilityDelay"
unit="Days"
unit="days"
helpText={translate('AvailabilityDelayHelpText')}
onChange={onInputChange}
{...settings.availabilityDelay}

View File

@@ -147,7 +147,8 @@ class NamingModal extends Component {
{ token: '{MediaInfo VideoCodec}', example: 'x264' },
{ token: '{MediaInfo VideoBitDepth}', example: '10' },
{ token: '{MediaInfo VideoDynamicRange}', example: 'HDR' }
{ token: '{MediaInfo VideoDynamicRange}', example: 'HDR' },
{ token: '{MediaInfo VideoDynamicRangeType}', example: 'DV HDR10' }
];
const releaseGroupTokens = [

View File

@@ -63,6 +63,7 @@ class Notification extends Component {
onMovieFileDelete,
onMovieFileDeleteForUpgrade,
onHealthIssue,
onApplicationUpdate,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
@@ -70,7 +71,8 @@ class Notification extends Component {
supportsOnMovieDelete,
supportsOnMovieFileDelete,
supportsOnMovieFileDeleteForUpgrade,
supportsOnHealthIssue
supportsOnHealthIssue,
supportsOnApplicationUpdate
} = this.props;
return (
@@ -123,6 +125,14 @@ class Notification extends Component {
null
}
{
supportsOnApplicationUpdate && onApplicationUpdate ?
<Label kind={kinds.SUCCESS}>
{translate('OnApplicationUpdate')}
</Label> :
null
}
{
supportsOnMovieDelete && onMovieDelete ?
<Label kind={kinds.SUCCESS}>
@@ -148,7 +158,7 @@ class Notification extends Component {
}
{
!onGrab && !onDownload && !onRename && !onHealthIssue && !onMovieDelete && !onMovieFileDelete ?
!onGrab && !onDownload && !onRename && !onHealthIssue && !onApplicationUpdate && !onMovieDelete && !onMovieFileDelete ?
<Label
kind={kinds.DISABLED}
outline={true}
@@ -190,6 +200,7 @@ Notification.propTypes = {
onMovieFileDelete: PropTypes.bool.isRequired,
onMovieFileDeleteForUpgrade: PropTypes.bool.isRequired,
onHealthIssue: PropTypes.bool.isRequired,
onApplicationUpdate: PropTypes.bool.isRequired,
supportsOnGrab: PropTypes.bool.isRequired,
supportsOnDownload: PropTypes.bool.isRequired,
supportsOnMovieDelete: PropTypes.bool.isRequired,
@@ -198,6 +209,7 @@ Notification.propTypes = {
supportsOnUpgrade: PropTypes.bool.isRequired,
supportsOnRename: PropTypes.bool.isRequired,
supportsOnHealthIssue: PropTypes.bool.isRequired,
supportsOnApplicationUpdate: PropTypes.bool.isRequired,
onConfirmDeleteNotification: PropTypes.func.isRequired
};

View File

@@ -23,6 +23,7 @@ function NotificationEventItems(props) {
onMovieFileDelete,
onMovieFileDeleteForUpgrade,
onHealthIssue,
onApplicationUpdate,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
@@ -30,6 +31,7 @@ function NotificationEventItems(props) {
supportsOnMovieDelete,
supportsOnMovieFileDelete,
supportsOnMovieFileDeleteForUpgrade,
supportsOnApplicationUpdate,
supportsOnHealthIssue,
includeHealthWarnings
} = item;
@@ -150,6 +152,17 @@ function NotificationEventItems(props) {
/>
</div>
}
<div>
<FormInputGroup
type={inputTypes.CHECK}
name="onApplicationUpdate"
helpText={translate('OnApplicationUpdateHelpText')}
isDisabled={!supportsOnApplicationUpdate.value}
{...onApplicationUpdate}
onChange={onInputChange}
/>
</div>
</div>
</div>
</FormGroup>

View File

@@ -82,10 +82,18 @@ class DelayProfiles extends Component {
>
<div>
<div className={styles.delayProfilesHeader}>
<div className={styles.column}>Protocol</div>
<div className={styles.column}>Usenet Delay</div>
<div className={styles.column}>Torrent Delay</div>
<div className={styles.tags}>Tags</div>
<div className={styles.column}>
{translate('Protocol')}
</div>
<div className={styles.column}>
{translate('UsenetDelay')}
</div>
<div className={styles.column}>
{translate('TorrentDelay')}
</div>
<div className={styles.tags}>
{translate('Tags')}
</div>
</div>
<div className={styles.delayProfiles}>

View File

@@ -25,9 +25,15 @@ class QualityDefinitions extends Component {
{...otherProps}
>
<div className={styles.header}>
<div className={styles.quality}>Quality</div>
<div className={styles.title}>Title</div>
<div className={styles.sizeLimit}>Size Limit</div>
<div className={styles.quality}>
{translate('Quality')}
</div>
<div className={styles.title}>
{translate('Title')}
</div>
<div className={styles.sizeLimit}>
{translate('SizeLimit')}
</div>
{
advancedSettings ?

View File

@@ -152,7 +152,7 @@ function TagDetailsModalContent(props) {
{
indexers.length ?
<FieldSet legend="Indexers">
<FieldSet legend={translate('Indexers')}>
{
indexers.map((item) => {
return (

View File

@@ -14,7 +14,6 @@ function createRemoveItemHandler(section, url) {
const ajaxOptions = {
url: `${url}/${id}?${$.param(queryParams, true)}`,
dataType: 'text',
method: 'DELETE'
};

View File

@@ -109,6 +109,7 @@ export default {
selectedSchema.onMovieDelete = selectedSchema.supportsOnMovieDelete;
selectedSchema.onMovieFileDelete = selectedSchema.supportsOnMovieFileDelete;
selectedSchema.onMovieFileDeleteForUpgrade = selectedSchema.supportsOnMovieFileDeleteForUpgrade;
selectedSchema.onApplicationUpdate = selectedSchema.supportsOnApplicationUpdate;
return selectedSchema;
});

View File

@@ -200,7 +200,7 @@ export const defaultState = {
ratings: function(item) {
const { ratings = {} } = item;
return ratings.value;
return ratings.tmdb? ratings.tmdb.value : 0;
}
},
@@ -330,8 +330,23 @@ export const defaultState = {
valueType: filterBuilderValueTypes.MINIMUM_AVAILABILITY
},
{
name: 'ratings',
label: 'Rating',
name: 'tmdbRating',
label: translate('TmdbRating'),
type: filterBuilderTypes.NUMBER
},
{
name: 'tmdbVotes',
label: translate('TmdbVotes'),
type: filterBuilderTypes.NUMBER
},
{
name: 'imdbRating',
label: translate('ImdbRating'),
type: filterBuilderTypes.NUMBER
},
{
name: 'imdbVotes',
label: translate('ImdbVotes'),
type: filterBuilderTypes.NUMBER
},
{

View File

@@ -148,9 +148,10 @@ export const actionHandlers = handleThunks({
return {
id,
path: item.path,
movieId: item.movie.id,
movieId: item.movie ? item.movie.id : undefined,
quality: item.quality,
languages: item.languages,
releaseGroup: item.releaseGroup,
downloadId: item.downloadId
};
});

View File

@@ -131,10 +131,38 @@ export const filterPredicates = {
return dateFilterPredicate(item.digitalRelease, filterValue, type);
},
ratings: function(item, filterValue, type) {
tmdbRating: function(item, filterValue, type) {
const predicate = filterTypePredicates[type];
return predicate(item.ratings.value * 10, filterValue);
const rating = item.ratings.tmdb ? item.ratings.tmdb.value : 0;
return predicate(rating * 10, filterValue);
},
tmdbVotes: function(item, filterValue, type) {
const predicate = filterTypePredicates[type];
const rating = item.ratings.tmdb ? item.ratings.tmdb.votes : 0;
return predicate(rating, filterValue);
},
imdbRating: function(item, filterValue, type) {
const predicate = filterTypePredicates[type];
console.log(item.ratings);
const rating = item.ratings.imdb ? item.ratings.imdb.value : 0;
return predicate(rating, filterValue);
},
imdbVotes: function(item, filterValue, type) {
const predicate = filterTypePredicates[type];
const rating = item.ratings.imdb ? item.ratings.imdb.votes : 0;
return predicate(rating, filterValue);
},
qualityCutoffNotMet: function(item) {

View File

@@ -209,7 +209,7 @@ export const defaultState = {
ratings: function(item) {
const { ratings = {} } = item;
return ratings.value;
return ratings.tmdb? ratings.tmdb.value : 0;
}
},
@@ -357,8 +357,23 @@ export const defaultState = {
}
},
{
name: 'ratings',
label: translate('Ratings'),
name: 'tmdbRating',
label: translate('TmdbRating'),
type: filterBuilderTypes.NUMBER
},
{
name: 'tmdbVotes',
label: translate('TmdbVotes'),
type: filterBuilderTypes.NUMBER
},
{
name: 'imdbRating',
label: translate('ImdbRating'),
type: filterBuilderTypes.NUMBER
},
{
name: 'imdbVotes',
label: translate('ImdbVotes'),
type: filterBuilderTypes.NUMBER
},
{

View File

@@ -27,7 +27,7 @@ const paged = `${section}.paged`;
export const defaultState = {
options: {
includeUnknownMovieItems: false
includeUnknownMovieItems: true
},
status: {

View File

@@ -100,7 +100,7 @@ export default function createSentryMiddleware() {
return;
}
const dsn = isProduction ? 'https://b0fb75c38ef4487dbf742f79c4ba62d2@sentry.servarr.com/12' :
const dsn = isProduction ? 'https://7794f2858478485ea337fb5535624fbd@sentry.servarr.com/12' :
'https://da610619280249f891ec3ee306906793@sentry.servarr.com/13';
sentry.init({

View File

@@ -1,5 +1,7 @@
import migrateBlacklistToBlocklist from './migrateBlacklistToBlocklist';
import migratePreDbToReleased from './migratePreDbToReleased';
export default function migrate(persistedState) {
migrateBlacklistToBlocklist(persistedState);
migratePreDbToReleased(persistedState);
}

View File

@@ -0,0 +1,18 @@
import get from 'lodash';
export default function migratePreDbToReleased(persistedState) {
const addMovie = get(persistedState, 'addMovie.defaults.minimumAvailability');
const discoverMovie = get(persistedState, 'discoverMovie.defaults.minimumAvailability');
if (!addMovie && !discoverMovie) {
return;
}
if (addMovie === 'preDB') {
persistedState.addMovie.defaults.minimumAvailability = 'released';
}
if (discoverMovie === 'preDB') {
persistedState.discoverMovie.defaults.minimumAvailability = 'released';
}
}

View File

@@ -8,6 +8,7 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import { icons, kinds } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes';
import translate from 'Utilities/String/translate';
import RestoreBackupModalConnector from './RestoreBackupModalConnector';
import styles from './BackupRow.css';
@@ -65,6 +66,7 @@ class BackupRow extends Component {
type,
name,
path,
size,
time
} = this.props;
@@ -104,6 +106,10 @@ class BackupRow extends Component {
</Link>
</TableRowCell>
<TableRowCell>
{formatBytes(size)}
</TableRowCell>
<RelativeDateCellConnector
date={time}
/>
@@ -147,6 +153,7 @@ BackupRow.propTypes = {
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
time: PropTypes.string.isRequired,
onDeleteBackupPress: PropTypes.func.isRequired
};

View File

@@ -23,6 +23,11 @@ const columns = [
label: translate('Name'),
isVisible: true
},
{
name: 'size',
label: 'Size',
isVisible: true
},
{
name: 'time',
label: translate('Time'),
@@ -127,6 +132,7 @@ class Backups extends Component {
type,
name,
path,
size,
time
} = item;
@@ -137,6 +143,7 @@ class Backups extends Component {
type={type}
name={name}
path={path}
size={size}
time={time}
onDeleteBackupPress={onDeleteBackupPress}
/>

View File

@@ -13,7 +13,7 @@ class Donations extends Component {
return (
<FieldSet legend={translate('Donations')}>
<div className={styles.logoContainer} title="Radarr">
<Link to="https://opencollective.com/radarr">
<Link to="https://radarr.video/donate">
<img
className={styles.logo}
src={`${window.Radarr.urlBase}/Content/Images/Icons/logo-radarr.png`}
@@ -21,7 +21,7 @@ class Donations extends Component {
</Link>
</div>
<div className={styles.logoContainer} title="Lidarr">
<Link to="https://opencollective.com/lidarr">
<Link to="https://lidarr.audio/donate">
<img
className={styles.logo}
src={`${window.Radarr.urlBase}/Content/Images/Icons/logo-lidarr.png`}
@@ -29,7 +29,7 @@ class Donations extends Component {
</Link>
</div>
<div className={styles.logoContainer} title="Readarr">
<Link to="https://opencollective.com/readarr">
<Link to="https://readarr.com/donate">
<img
className={styles.logo}
src={`${window.Radarr.urlBase}/Content/Images/Icons/logo-readarr.png`}
@@ -37,7 +37,7 @@ class Donations extends Component {
</Link>
</div>
<div className={styles.logoContainer} title="Prowlarr">
<Link to="https://opencollective.com/prowlarr">
<Link to="https://prowlarr.com/donate">
<img
className={styles.logo}
src={`${window.Radarr.urlBase}/Content/Images/Icons/logo-prowlarr.png`}
@@ -45,7 +45,7 @@ class Donations extends Component {
</Link>
</div>
<div className={styles.logoContainer} title="Sonarr">
<Link to="https://opencollective.com/sonarr">
<Link to="https://sonarr.tv/donate">
<img
className={styles.logo}
src={`${window.Radarr.urlBase}/Content/Images/Icons/logo-sonarr.png`}

View File

@@ -19,6 +19,7 @@ function getInternalLink(source) {
case 'IndexerRssCheck':
case 'IndexerSearchCheck':
case 'IndexerStatusCheck':
case 'IndexerJackettAllCheck':
case 'IndexerLongTermStatusCheck':
return (
<IconButton

View File

@@ -200,7 +200,7 @@ class QueuedTaskRow extends Component {
{
clientUserAgent ?
<span className={styles.userAgent} title={translate('TaskUserAgentTooltip')}>
{translate('from')}: {clientUserAgent}
{translate('From')}: {clientUserAgent}
</span> :
null
}

View File

@@ -2,7 +2,7 @@ import { kinds } from 'Helpers/Props';
function getStatusStyle(status, monitored, hasFile, isAvailable, returnType, queue = false) {
if (queue) {
return returnType === 'kinds' ? kinds.SUCCESS : 'queue';
return returnType === 'kinds' ? kinds.QUEUE : 'queue';
}
if (hasFile && monitored) {

View File

@@ -30,7 +30,7 @@
"@fortawesome/free-regular-svg-icons": "5.15.3",
"@fortawesome/free-solid-svg-icons": "5.15.3",
"@fortawesome/react-fontawesome": "0.1.14",
"@microsoft/signalr": "6.0.0",
"@microsoft/signalr": "6.0.1",
"@sentry/browser": "6.13.2",
"@sentry/integrations": "6.13.2",
"classnames": "2.3.1",

View File

@@ -1,3 +0,0 @@
#SET BUILD_NUMBER=1
#SET branch=develop
inno\ISCC.exe radarr.iss

View File

@@ -1,336 +0,0 @@
; *** Inno Setup version 5.5.3+ English messages ***
;
; To download user-contributed translations of this file, go to:
; http://www.jrsoftware.org/files/istrans/
;
; Note: When translating this text, do not add periods (.) to the end of
; messages that didn't have them already, because on those messages Inno
; Setup adds the periods automatically (appending a period would result in
; two periods being displayed).
[LangOptions]
; The following three entries are very important. Be sure to read and
; understand the '[LangOptions] section' topic in the help file.
LanguageName=English
LanguageID=$0409
LanguageCodePage=0
; If the language you are translating to requires special font faces or
; sizes, uncomment any of the following entries and change them accordingly.
;DialogFontName=
;DialogFontSize=8
;WelcomeFontName=Verdana
;WelcomeFontSize=12
;TitleFontName=Arial
;TitleFontSize=29
;CopyrightFontName=Arial
;CopyrightFontSize=8
[Messages]
; *** Application titles
SetupAppTitle=Setup
SetupWindowTitle=Setup - %1
UninstallAppTitle=Uninstall
UninstallAppFullTitle=%1 Uninstall
; *** Misc. common
InformationTitle=Information
ConfirmTitle=Confirm
ErrorTitle=Error
; *** SetupLdr messages
SetupLdrStartupMessage=This will install %1. Do you wish to continue?
LdrCannotCreateTemp=Unable to create a temporary file. Setup aborted
LdrCannotExecTemp=Unable to execute file in the temporary directory. Setup aborted
; *** Startup error messages
LastErrorMessage=%1.%n%nError %2: %3
SetupFileMissing=The file %1 is missing from the installation directory. Please correct the problem or obtain a new copy of the program.
SetupFileCorrupt=The setup files are corrupted. Please obtain a new copy of the program.
SetupFileCorruptOrWrongVer=The setup files are corrupted, or are incompatible with this version of Setup. Please correct the problem or obtain a new copy of the program.
InvalidParameter=An invalid parameter was passed on the command line:%n%n%1
SetupAlreadyRunning=Setup is already running.
WindowsVersionNotSupported=This program does not support the version of Windows your computer is running.
WindowsServicePackRequired=This program requires %1 Service Pack %2 or later.
NotOnThisPlatform=This program will not run on %1.
OnlyOnThisPlatform=This program must be run on %1.
OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1
MissingWOW64APIs=The version of Windows you are running does not include functionality required by Setup to perform a 64-bit installation. To correct this problem, please install Service Pack %1.
WinVersionTooLowError=This program requires %1 version %2 or later.
WinVersionTooHighError=This program cannot be installed on %1 version %2 or later.
AdminPrivilegesRequired=You must be logged in as an administrator when installing this program.
PowerUserPrivilegesRequired=You must be logged in as an administrator or as a member of the Power Users group when installing this program.
SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.
UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit.
; *** Misc. errors
ErrorCreatingDir=Setup was unable to create the directory "%1"
ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files
; *** Setup common messages
ExitSetupTitle=Exit Setup
ExitSetupMessage=Setup is not complete. If you exit now, the program will not be installed.%n%nYou may run Setup again at another time to complete the installation.%n%nExit Setup?
AboutSetupMenuItem=&About Setup...
AboutSetupTitle=About Setup
AboutSetupMessage=%1 version %2%n%3%n%n%1 home page:%n%4
AboutSetupNote=
TranslatorNote=
; *** Buttons
ButtonBack=< &Back
ButtonNext=&Next >
ButtonInstall=&Install
ButtonOK=OK
ButtonCancel=Cancel
ButtonYes=&Yes
ButtonYesToAll=Yes to &All
ButtonNo=&No
ButtonNoToAll=N&o to All
ButtonFinish=&Finish
ButtonBrowse=&Browse...
ButtonWizardBrowse=B&rowse...
ButtonNewFolder=&Make New Folder
; *** "Select Language" dialog messages
SelectLanguageTitle=Select Setup Language
SelectLanguageLabel=Select the language to use during the installation:
; *** Common wizard text
ClickNext=Click Next to continue, or Cancel to exit Setup.
BeveledLabel=
BrowseDialogTitle=Browse For Folder
BrowseDialogLabel=Select a folder in the list below, then click OK.
NewFolderName=New Folder
; *** "Welcome" wizard page
WelcomeLabel1=Welcome to the [name] Setup Wizard
WelcomeLabel2=This will install [name/ver] on your computer.%n%nIt is recommended that you close all other applications before continuing.
; *** "Password" wizard page
WizardPassword=Password
PasswordLabel1=This installation is password protected.
PasswordLabel3=Please provide the password, then click Next to continue. Passwords are case-sensitive.
PasswordEditLabel=&Password:
IncorrectPassword=The password you entered is not correct. Please try again.
; *** "License Agreement" wizard page
WizardLicense=License Agreement
LicenseLabel=Please read the following important information before continuing.
LicenseLabel3=Please read the following License Agreement. You must accept the terms of this agreement before continuing with the installation.
LicenseAccepted=I &accept the agreement
LicenseNotAccepted=I &do not accept the agreement
; *** "Information" wizard pages
WizardInfoBefore=Information
InfoBeforeLabel=Please read the following important information before continuing.
InfoBeforeClickLabel=When you are ready to continue with Setup, click Next.
WizardInfoAfter=Information
InfoAfterLabel=Please read the following important information before continuing.
InfoAfterClickLabel=When you are ready to continue with Setup, click Next.
; *** "User Information" wizard page
WizardUserInfo=User Information
UserInfoDesc=Please enter your information.
UserInfoName=&User Name:
UserInfoOrg=&Organization:
UserInfoSerial=&Serial Number:
UserInfoNameRequired=You must enter a name.
; *** "Select Destination Location" wizard page
WizardSelectDir=Select Destination Location
SelectDirDesc=Where should [name] be installed?
SelectDirLabel3=Setup will install [name] into the following folder.
SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.
DiskSpaceMBLabel=At least [mb] MB of free disk space is required.
CannotInstallToNetworkDrive=Setup cannot install to a network drive.
CannotInstallToUNCPath=Setup cannot install to a UNC path.
InvalidPath=You must enter a full path with drive letter; for example:%n%nC:\APP%n%nor a UNC path in the form:%n%n\\server\share
InvalidDrive=The drive or UNC share you selected does not exist or is not accessible. Please select another.
DiskSpaceWarningTitle=Not Enough Disk Space
DiskSpaceWarning=Setup requires at least %1 KB of free space to install, but the selected drive only has %2 KB available.%n%nDo you want to continue anyway?
DirNameTooLong=The folder name or path is too long.
InvalidDirName=The folder name is not valid.
BadDirName32=Folder names cannot include any of the following characters:%n%n%1
DirExistsTitle=Folder Exists
DirExists=The folder:%n%n%1%n%nalready exists. Would you like to install to that folder anyway?
DirDoesntExistTitle=Folder Does Not Exist
DirDoesntExist=The folder:%n%n%1%n%ndoes not exist. Would you like the folder to be created?
; *** "Select Components" wizard page
WizardSelectComponents=Select Components
SelectComponentsDesc=Which components should be installed?
SelectComponentsLabel2=Select the components you want to install; clear the components you do not want to install. Click Next when you are ready to continue.
FullInstallation=Full installation
; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language)
CompactInstallation=Compact installation
CustomInstallation=Custom installation
NoUninstallWarningTitle=Components Exist
NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway?
ComponentSize1=%1 KB
ComponentSize2=%1 MB
ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space.
; *** "Select Additional Tasks" wizard page
WizardSelectTasks=Select Additional Tasks
SelectTasksDesc=Which additional tasks should be performed?
SelectTasksLabel2=Select the additional tasks you would like Setup to perform while installing [name], then click Next.
; *** "Select Start Menu Folder" wizard page
WizardSelectProgramGroup=Select Start Menu Folder
SelectStartMenuFolderDesc=Where should Setup place the program's shortcuts?
SelectStartMenuFolderLabel3=Setup will create the program's shortcuts in the following Start Menu folder.
SelectStartMenuFolderBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse.
MustEnterGroupName=You must enter a folder name.
GroupNameTooLong=The folder name or path is too long.
InvalidGroupName=The folder name is not valid.
BadGroupName=The folder name cannot include any of the following characters:%n%n%1
NoProgramGroupCheck2=&Don't create a Start Menu folder
; *** "Ready to Install" wizard page
WizardReady=Ready to Install
ReadyLabel1=Setup is now ready to begin installing [name] on your computer.
ReadyLabel2a=Click Install to continue with the installation, or click Back if you want to review or change any settings.
ReadyLabel2b=Click Install to continue with the installation.
ReadyMemoUserInfo=User information:
ReadyMemoDir=Destination location:
ReadyMemoType=Setup type:
ReadyMemoComponents=Selected components:
ReadyMemoGroup=Start Menu folder:
ReadyMemoTasks=Additional tasks:
; *** "Preparing to Install" wizard page
WizardPreparing=Preparing to Install
PreparingDesc=Setup is preparing to install [name] on your computer.
PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name].
CannotContinue=Setup cannot continue. Please click Cancel to exit.
ApplicationsFound=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications.
ApplicationsFound2=The following applications are using files that need to be updated by Setup. It is recommended that you allow Setup to automatically close these applications. After the installation has completed, Setup will attempt to restart the applications.
CloseApplications=&Automatically close the applications
DontCloseApplications=&Do not close the applications
ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing.
; *** "Installing" wizard page
WizardInstalling=Installing
InstallingLabel=Please wait while Setup installs [name] on your computer.
; *** "Setup Completed" wizard page
FinishedHeadingLabel=Completing the [name] Setup Wizard
FinishedLabelNoIcons=Setup has finished installing [name] on your computer.
FinishedLabel=Setup has finished installing [name] on your computer. The application may be launched by selecting the installed icons.
ClickFinish=Click Finish to exit Setup.
FinishedRestartLabel=To complete the installation of [name], Setup must restart your computer. Would you like to restart now?
FinishedRestartMessage=To complete the installation of [name], Setup must restart your computer.%n%nWould you like to restart now?
ShowReadmeCheck=Yes, I would like to view the README file
YesRadio=&Yes, restart the computer now
NoRadio=&No, I will restart the computer later
; used for example as 'Run MyProg.exe'
RunEntryExec=Run %1
; used for example as 'View Readme.txt'
RunEntryShellExec=View %1
; *** "Setup Needs the Next Disk" stuff
ChangeDiskTitle=Setup Needs the Next Disk
SelectDiskLabel2=Please insert Disk %1 and click OK.%n%nIf the files on this disk can be found in a folder other than the one displayed below, enter the correct path or click Browse.
PathLabel=&Path:
FileNotInDir2=The file "%1" could not be located in "%2". Please insert the correct disk or select another folder.
SelectDirectoryLabel=Please specify the location of the next disk.
; *** Installation phase messages
SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again.
EntryAbortRetryIgnore=Click Retry to try again, Ignore to proceed anyway, or Abort to cancel installation.
; *** Installation status messages
StatusClosingApplications=Closing applications...
StatusCreateDirs=Creating directories...
StatusExtractFiles=Extracting files...
StatusCreateIcons=Creating shortcuts...
StatusCreateIniEntries=Creating INI entries...
StatusCreateRegistryEntries=Creating registry entries...
StatusRegisterFiles=Registering files...
StatusSavingUninstall=Saving uninstall information...
StatusRunProgram=Finishing installation...
StatusRestartingApplications=Restarting applications...
StatusRollback=Rolling back changes...
; *** Misc. errors
ErrorInternal2=Internal error: %1
ErrorFunctionFailedNoCode=%1 failed
ErrorFunctionFailed=%1 failed; code %2
ErrorFunctionFailedWithMessage=%1 failed; code %2.%n%3
ErrorExecutingProgram=Unable to execute file:%n%1
; *** Registry errors
ErrorRegOpenKey=Error opening registry key:%n%1\%2
ErrorRegCreateKey=Error creating registry key:%n%1\%2
ErrorRegWriteKey=Error writing to registry key:%n%1\%2
; *** INI errors
ErrorIniEntry=Error creating INI entry in file "%1".
; *** File copying errors
FileAbortRetryIgnore=Click Retry to try again, Ignore to skip this file (not recommended), or Abort to cancel installation.
FileAbortRetryIgnore2=Click Retry to try again, Ignore to proceed anyway (not recommended), or Abort to cancel installation.
SourceIsCorrupted=The source file is corrupted
SourceDoesntExist=The source file "%1" does not exist
ExistingFileReadOnly=The existing file is marked as read-only.%n%nClick Retry to remove the read-only attribute and try again, Ignore to skip this file, or Abort to cancel installation.
ErrorReadingExistingDest=An error occurred while trying to read the existing file:
FileExists=The file already exists.%n%nWould you like Setup to overwrite it?
ExistingFileNewer=The existing file is newer than the one Setup is trying to install. It is recommended that you keep the existing file.%n%nDo you want to keep the existing file?
ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file:
ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory:
ErrorReadingSource=An error occurred while trying to read the source file:
ErrorCopying=An error occurred while trying to copy a file:
ErrorReplacingExistingFile=An error occurred while trying to replace the existing file:
ErrorRestartReplace=RestartReplace failed:
ErrorRenamingTemp=An error occurred while trying to rename a file in the destination directory:
ErrorRegisterServer=Unable to register the DLL/OCX: %1
ErrorRegSvr32Failed=RegSvr32 failed with exit code %1
ErrorRegisterTypeLib=Unable to register the type library: %1
; *** Post-installation errors
ErrorOpeningReadme=An error occurred while trying to open the README file.
ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually.
; *** Uninstaller messages
UninstallNotFound=File "%1" does not exist. Cannot uninstall.
UninstallOpenError=File "%1" could not be opened. Cannot uninstall
UninstallUnsupportedVer=The uninstall log file "%1" is in a format not recognized by this version of the uninstaller. Cannot uninstall
UninstallUnknownEntry=An unknown entry (%1) was encountered in the uninstall log
ConfirmUninstall=Are you sure you want to completely remove %1 and all of its components?
UninstallOnlyOnWin64=This installation can only be uninstalled on 64-bit Windows.
OnlyAdminCanUninstall=This installation can only be uninstalled by a user with administrative privileges.
UninstallStatusLabel=Please wait while %1 is removed from your computer.
UninstalledAll=%1 was successfully removed from your computer.
UninstalledMost=%1 uninstall complete.%n%nSome elements could not be removed. These can be removed manually.
UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now?
UninstallDataCorrupted="%1" file is corrupted. Cannot uninstall
; *** Uninstallation phase messages
ConfirmDeleteSharedFileTitle=Remove Shared File?
ConfirmDeleteSharedFile2=The system indicates that the following shared file is no longer in use by any programs. Would you like for Uninstall to remove this shared file?%n%nIf any programs are still using this file and it is removed, those programs may not function properly. If you are unsure, choose No. Leaving the file on your system will not cause any harm.
SharedFileNameLabel=File name:
SharedFileLocationLabel=Location:
WizardUninstalling=Uninstall Status
StatusUninstalling=Uninstalling %1...
; *** Shutdown block reasons
ShutdownBlockReasonInstallingApp=Installing %1.
ShutdownBlockReasonUninstallingApp=Uninstalling %1.
; The custom messages below aren't used by Setup itself, but if you make
; use of them in your scripts, you'll want to translate them.
[CustomMessages]
NameAndVersion=%1 version %2
AdditionalIcons=Additional icons:
CreateDesktopIcon=Create a &desktop icon
CreateQuickLaunchIcon=Create a &Quick Launch icon
ProgramOnTheWeb=%1 on the Web
UninstallProgram=Uninstall %1
LaunchProgram=Launch %1
AssocFileExtension=&Associate %1 with the %2 file extension
AssocingFileExtension=Associating %1 with the %2 file extension...
AutoStartProgramGroupDescription=Startup:
AutoStartProgram=Automatically start %1
AddonHostProgramNotFound=%1 could not be located in the folder you selected.%n%nDo you want to continue anyway?

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

View File

@@ -4,12 +4,11 @@
#define AppName "Radarr"
#define AppPublisher "Team Radarr"
#define AppURL "https://radarr.video/"
#define ForumsURL "https://forums.radarr.video/"
#define ForumsURL "https://radarr.video/discord"
#define AppExeName "Radarr.exe"
#define BaseVersion GetEnv('MAJORVERSION')
#define BuildNumber GetEnv('MINORVERSION')
#define BuildVersion GetEnv('RADARRVERSION')
#define BranchName GetEnv('BUILD_SOURCEBRANCHNAME')
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
@@ -22,15 +21,15 @@ AppPublisher={#AppPublisher}
AppPublisherURL={#AppURL}
AppSupportURL={#ForumsURL}
AppUpdatesURL={#AppURL}
DefaultDirName={commonappdata}\Radarr\bin
DefaultDirName={commonappdata}\Radarr
DisableDirPage=yes
DefaultGroupName={#AppName}
DisableProgramGroupPage=yes
OutputBaseFilename=Radarr.{#BranchName}.{#BuildVersion}.windows.{#Framework}
OutputBaseFilename=Radarr.{#BuildVersion}.{#Runtime}
SolidCompression=yes
AppCopyright=Creative Commons 3.0 License
AllowUNCPath=False
UninstallDisplayIcon={app}\Radarr.exe
UninstallDisplayIcon={app}\bin\Radarr.exe
DisableReadyPage=True
CompressionThreads=2
Compression=lzma2/normal
@@ -38,6 +37,7 @@ AppContact={#ForumsURL}
VersionInfoVersion={#BaseVersion}.{#BuildNumber}
SetupLogging=yes
OutputDir=output
WizardStyle=modern
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -48,28 +48,31 @@ Name: "windowsService"; Description: "Install Windows Service (Starts when the c
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
[Dirs]
Name: "{app}"; Permissions: users-modify
[Files]
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\Radarr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\*"; Excludes: "Radarr.Update"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\Radarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\*"; Excludes: "Radarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon
Name: "{userstartup}\{#AppName}"; Filename: "{app}\Radarr.exe"; WorkingDir: "{app}"; Tasks: startupShortcut
Name: "{group}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon"
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\bin\{#AppExeName}"; Parameters: "/icon"; Tasks: desktopIcon
Name: "{userstartup}\{#AppName}"; Filename: "{app}\bin\Radarr.exe"; WorkingDir: "{app}\bin"; Tasks: startupShortcut
[InstallDelete]
Name: "{app}"; Type: filesandordirs
Name: "{app}\bin"; Type: filesandordirs
[Run]
Filename: "{app}\Radarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated;
Filename: "{app}\Radarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none;
Filename: "{app}\Radarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService
Filename: "{app}\Radarr.exe"; Description: "Open Radarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService;
Filename: "{app}\Radarr.exe"; Description: "Start Radarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
Filename: "{app}\bin\Radarr.Console.exe"; StatusMsg: "Removing previous Windows Service"; Parameters: "/u /exitimmediately"; Flags: runhidden waituntilterminated;
Filename: "{app}\bin\Radarr.Console.exe"; Description: "Enable Access from Other Devices"; StatusMsg: "Enabling Remote access"; Parameters: "/registerurl /exitimmediately"; Flags: postinstall runascurrentuser runhidden waituntilterminated; Tasks: startupShortcut none;
Filename: "{app}\bin\Radarr.Console.exe"; StatusMsg: "Installing Windows Service"; Parameters: "/i /exitimmediately"; Flags: runhidden waituntilterminated; Tasks: windowsService
Filename: "{app}\bin\Radarr.exe"; Description: "Open Radarr Web UI"; Flags: postinstall skipifsilent nowait; Tasks: windowsService;
Filename: "{app}\bin\Radarr.exe"; Description: "Start Radarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
[UninstallRun]
Filename: "{app}\radarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
Filename: "{app}\bin\radarr.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
[Code]
function PrepareToInstall(var NeedsRestart: Boolean): String;

View File

@@ -146,7 +146,7 @@ namespace NzbDrone.Common.Test.Http
var request = new HttpRequest($"https://expired.badssl.com");
Assert.Throws<HttpRequestException>(() => Subject.Execute(request));
ExceptionVerification.ExpectedErrors(2);
ExceptionVerification.ExpectedErrors(1);
}
[Test]

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Common.Cloud
.SetHeader("Authorization", $"Bearer {AuthToken}")
.CreateFactory();
RadarrMetadata = new HttpRequestBuilder("https://radarrapi.servarr.com/v1/{route}")
RadarrMetadata = new HttpRequestBuilder("https://api.radarr.video/v1/{route}")
.CreateFactory();
}

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Common.EnvironmentInfo
private readonly Logger _logger;
private readonly DateTime _startTime = DateTime.UtcNow;
public RuntimeInfo(IHostLifetime hostLifetime, Logger logger)
public RuntimeInfo(Logger logger, IHostLifetime hostLifetime = null)
{
_logger = logger;

View File

@@ -171,5 +171,26 @@ namespace NzbDrone.Common.Extensions
{
return source.Contains(value, StringComparer.InvariantCultureIgnoreCase);
}
public static string EncodeRFC3986(this string value)
{
// From Twitterizer http://www.twitterizer.net/
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
var encoded = Uri.EscapeDataString(value);
return Regex
.Replace(encoded, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper())
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("$", "%24")
.Replace("!", "%21")
.Replace("*", "%2A")
.Replace("'", "%27")
.Replace("%7E", "~");
}
}
}

View File

@@ -0,0 +1,12 @@
using System.Net;
namespace NzbDrone.Common.Http
{
public class BasicNetworkCredential : NetworkCredential
{
public BasicNetworkCredential(string user, string pass)
: base(user, pass)
{
}
}
}

View File

@@ -4,9 +4,9 @@ using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http.Proxy;
@@ -26,22 +26,21 @@ namespace NzbDrone.Common.Http.Dispatchers
private readonly ICertificateValidationService _certificateValidationService;
private readonly IUserAgentBuilder _userAgentBuilder;
private readonly ICached<System.Net.Http.HttpClient> _httpClientCache;
private readonly Logger _logger;
private readonly ICached<CredentialCache> _credentialCache;
public ManagedHttpDispatcher(IHttpProxySettingsProvider proxySettingsProvider,
ICreateManagedWebProxy createManagedWebProxy,
ICertificateValidationService certificateValidationService,
IUserAgentBuilder userAgentBuilder,
ICacheManager cacheManager,
Logger logger)
ICacheManager cacheManager)
{
_proxySettingsProvider = proxySettingsProvider;
_createManagedWebProxy = createManagedWebProxy;
_certificateValidationService = certificateValidationService;
_userAgentBuilder = userAgentBuilder;
_logger = logger;
_httpClientCache = cacheManager.GetCache<System.Net.Http.HttpClient>(typeof(ManagedHttpDispatcher));
_credentialCache = cacheManager.GetCache<CredentialCache>(typeof(ManagedHttpDispatcher), "credentialcache");
}
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
@@ -67,6 +66,26 @@ namespace NzbDrone.Common.Http.Dispatchers
cts.CancelAfter(TimeSpan.FromSeconds(100));
}
if (request.Credentials != null)
{
if (request.Credentials is BasicNetworkCredential bc)
{
// Manually set header to avoid initial challenge response
var authInfo = bc.UserName + ":" + bc.Password;
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
requestMessage.Headers.Add("Authorization", "Basic " + authInfo);
}
else if (request.Credentials is NetworkCredential nc)
{
var creds = GetCredentialCache();
foreach (var authtype in new[] { "Basic", "Digest" })
{
creds.Remove((Uri)request.Url, authtype);
creds.Add((Uri)request.Url, authtype, nc);
}
}
}
if (request.ContentData != null)
{
requestMessage.Content = new ByteArrayContent(request.ContentData);
@@ -79,49 +98,32 @@ namespace NzbDrone.Common.Http.Dispatchers
var httpClient = GetClient(request.Url);
HttpResponseMessage responseMessage;
try
using var responseMessage = httpClient.Send(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token);
{
responseMessage = httpClient.Send(requestMessage, cts.Token);
}
catch (HttpRequestException e)
{
_logger.Error(e, "HttpClient error");
throw;
}
byte[] data = null;
byte[] data = null;
using (var responseStream = responseMessage.Content.ReadAsStream())
{
if (responseStream != null && responseStream != Stream.Null)
try
{
try
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
{
if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK)
{
// A target ResponseStream was specified, write to that instead.
// But only on the OK status code, since we don't want to write failures and redirects.
responseStream.CopyTo(request.ResponseStream);
}
else
{
data = responseStream.ToBytes();
}
responseMessage.Content.CopyTo(request.ResponseStream, null, cts.Token);
}
catch (Exception ex)
else
{
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
data = responseMessage.Content.ReadAsByteArrayAsync(cts.Token).GetAwaiter().GetResult();
}
}
catch (Exception ex)
{
throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode);
}
var headers = responseMessage.Headers.ToNameValueCollection();
headers.Add(responseMessage.Content.Headers.ToNameValueCollection());
return new HttpResponse(request, new HttpHeader(headers), data, responseMessage.StatusCode);
}
protected virtual System.Net.Http.HttpClient GetClient(HttpUri uri)
@@ -140,6 +142,8 @@ namespace NzbDrone.Common.Http.Dispatchers
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Brotli,
UseCookies = false, // sic - we don't want to use a shared cookie container
AllowAutoRedirect = false,
Credentials = GetCredentialCache(),
PreAuthenticate = true,
MaxConnectionsPerServer = 12,
ConnectCallback = onConnect,
SslOptions = new SslClientAuthenticationOptions
@@ -224,6 +228,11 @@ namespace NzbDrone.Common.Http.Dispatchers
headers.Add(header, value);
}
private CredentialCache GetCredentialCache()
{
return _credentialCache.Get("credentialCache", () => new CredentialCache());
}
private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
{
// Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way.

View File

@@ -38,6 +38,7 @@ namespace NzbDrone.Common.Http
public HttpHeader Headers { get; set; }
public byte[] ContentData { get; set; }
public string ContentSummary { get; set; }
public ICredentials Credentials { get; set; }
public bool SuppressHttpError { get; set; }
public IEnumerable<HttpStatusCode> SuppressHttpErrorStatusCodes { get; set; }
public bool UseSimplifiedUserAgent { get; set; }
@@ -89,12 +90,5 @@ namespace NzbDrone.Common.Http
var encoding = HttpHeader.GetEncodingFromContentType(Headers.ContentType);
ContentData = encoding.GetBytes(data);
}
public void AddBasicAuthentication(string username, string password)
{
var authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes($"{username}:{password}"));
Headers.Set("Authorization", "Basic " + authInfo);
}
}
}

View File

@@ -26,10 +26,9 @@ namespace NzbDrone.Common.Http
public bool ConnectionKeepAlive { get; set; }
public TimeSpan RateLimit { get; set; }
public bool LogResponseContent { get; set; }
public NetworkCredential NetworkCredential { get; set; }
public ICredentials NetworkCredential { get; set; }
public Dictionary<string, string> Cookies { get; private set; }
public List<HttpFormData> FormData { get; private set; }
public Action<HttpRequest> PostProcess { get; set; }
public HttpRequestBuilder(string baseUrl)
@@ -109,13 +108,7 @@ namespace NzbDrone.Common.Http
request.ConnectionKeepAlive = ConnectionKeepAlive;
request.RateLimit = RateLimit;
request.LogResponseContent = LogResponseContent;
if (NetworkCredential != null)
{
var authInfo = NetworkCredential.UserName + ":" + NetworkCredential.Password;
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
request.Headers.Set("Authorization", "Basic " + authInfo);
}
request.Credentials = NetworkCredential;
foreach (var header in Headers)
{

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Common.Http
{
public class XmlRpcRequestBuilder : HttpRequestBuilder
{
public static string XmlRpcContentType = "text/xml";
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(XmlRpcRequestBuilder));
public string XmlMethod { get; private set; }
public List<object> XmlParameters { get; private set; }
public XmlRpcRequestBuilder(string baseUrl)
: base(baseUrl)
{
Method = HttpMethod.Post;
XmlParameters = new List<object>();
}
public XmlRpcRequestBuilder(bool useHttps, string host, int port, string urlBase = null)
: this(BuildBaseUrl(useHttps, host, port, urlBase))
{
}
public override HttpRequestBuilder Clone()
{
var clone = base.Clone() as XmlRpcRequestBuilder;
clone.XmlParameters = new List<object>(XmlParameters);
return clone;
}
public XmlRpcRequestBuilder Call(string method, params object[] parameters)
{
var clone = Clone() as XmlRpcRequestBuilder;
clone.XmlMethod = method;
clone.XmlParameters = parameters.ToList();
return clone;
}
protected override void Apply(HttpRequest request)
{
base.Apply(request);
request.Headers.ContentType = XmlRpcContentType;
var methodCallElements = new List<XElement> { new XElement("methodName", XmlMethod) };
if (XmlParameters.Any())
{
var argElements = XmlParameters.Select(x => new XElement("param", ConvertParameter(x))).ToList();
var paramsElement = new XElement("params", argElements);
methodCallElements.Add(paramsElement);
}
var message = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("methodCall", methodCallElements));
var body = message.ToString();
Logger.Debug($"Executing remote method: {XmlMethod}");
Logger.Trace($"methodCall {XmlMethod} body:\n{body}");
request.SetContent(body);
}
private static XElement ConvertParameter(object value)
{
XElement data;
if (value is string s)
{
data = new XElement("string", s);
}
else if (value is List<string> l)
{
data = new XElement("array", new XElement("data", l.Select(x => new XElement("value", new XElement("string", x)))));
}
else if (value is int i)
{
data = new XElement("int", i);
}
else if (value is byte[] bytes)
{
data = new XElement("base64", Convert.ToBase64String(bytes));
}
else
{
throw new InvalidOperationException($"Unhandled argument type {value.GetType().Name}");
}
return new XElement("value", data);
}
}
}

View File

@@ -71,7 +71,7 @@ namespace NzbDrone.Common.Instrumentation
else
{
dsn = RuntimeInfo.IsProduction
? "https://39b572f7f3f04899b2c3254c7ac126d0@sentry.servarr.com/9"
? "https://26668106d708406b9ddf5a2bda34fcbb@sentry.servarr.com/9"
: "https://998b4673d4c849ccb5277b5966ed5bc2@sentry.servarr.com/10";
}

View File

@@ -136,6 +136,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
scope.SetTag("culture", Thread.CurrentThread.CurrentCulture.Name);
scope.SetTag("branch", BuildInfo.Branch);
scope.SetTag("runtime_identifier", System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier);
});
}

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