1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-17 21:26:13 -04:00

Compare commits

...

317 Commits

Author SHA1 Message Date
Bogdan
d9b771ab0b Fixed: Error sending Manual Interaction Required when series is unknown 2024-05-31 20:11:31 -04:00
Mark McDowall
6b08e849b8 Search for raw and clean titles for Newznab/Torznab indexers that support raw title searching 2024-05-31 17:10:32 -07:00
Mark McDowall
9c1f48ebc9 Fixed: Include full series title in episode search 2024-05-31 17:10:32 -07:00
Mark McDowall
fd3dd1ab7d New: Genres and Images for Webhooks and Notifiarr
Closes #6822
2024-05-31 17:10:13 -07:00
yammes08
11e5c5a11b Fixed: SDR Files Being Parsed As HLG 2024-05-31 20:09:53 -04:00
Weblate
48f0291884 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ano10 <arnaudthommeray+github@ik.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: r0bertreh <Robert.reh@live.de>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translation: Servarr/Sonarr
2024-05-31 17:09:11 -07:00
Mark McDowall
af0e55aef4 Bump version to 4.0.5 2024-05-29 16:23:16 -07:00
Weblate
39a439eb4c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Bao Trinh <servarr@baodtrinh.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: mm519897405 <baiya@vip.qq.com>
Co-authored-by: thegamingcat13 <sandervanbeek2004@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-05-29 16:23:04 -07:00
Weblate
66940b283b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: mm519897405 <baiya@vip.qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-05-24 06:21:13 -07:00
Mark McDowall
2a662afaef Fixed: Time for episodes airing today being blank 2024-05-24 06:19:38 -07:00
Weblate
62a9c2519b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: mm519897405 <baiya@vip.qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-05-22 20:09:18 -07:00
Mark McDowall
ca372bee25 Fixed: Queue and Calendar not loading 2024-05-22 20:07:31 -07:00
Sonarr
0904a0737e Automated API Docs update
ignore-downstream
2024-05-21 17:09:20 -07:00
Bogdan
70bc26dc19 Disable workflows on forks
ignore-downstream
2024-05-21 17:06:44 -07:00
Bogdan
a2e0002a08 Replace multiple occurrences in branch env variable
ignore-downstream
2024-05-21 17:06:44 -07:00
Bogdan
d7ceb11a64 Fixed: Trimming slashes from UrlBase when using environment variable 2024-05-21 17:06:44 -07:00
Bogdan
cc5b5463f2 Ignore Grabbed with STJson 2024-05-21 17:06:36 -07:00
Bogdan
9b4ff657af Update the wanted section for missing and cutoff unmet 2024-05-21 17:06:36 -07:00
Bogdan
aea50fa47e Bump Npgsql to 7.0.7
ignore-downstream
2024-05-21 17:06:28 -07:00
Mark McDowall
05edd44ed6 New: Include time for episode/season/series history 2024-05-21 17:06:18 -07:00
Bogdan
4440aa3cac New: Root folder exists validation for import lists 2024-05-21 17:06:09 -07:00
Bogdan
084fcc2295 Implement equality checks for providers 2024-05-21 17:05:48 -07:00
Weblate
536ff142c3 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Ransack6086 <servarr.jubilant150@slmail.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Yi Cao <caoyi06@qq.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: topnew <sznetim@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-05-21 17:05:34 -07:00
Mark McDowall
627b2a4289 New: Parse 480i Bluray/Remux as Bluray 480p
Closes #6801
2024-05-09 22:04:18 -07:00
Bogdan
9734c2d144 Fixed: Notifications with only On Rename enabled
ignore-downstream
2024-05-09 22:04:12 -07:00
Bogdan
c7c1e3ac9e Refactor PasswordInput to use type password 2024-05-09 22:04:04 -07:00
Bogdan
429444d085 Fixed: Text color for inputs on login page 2024-05-09 22:03:56 -07:00
Mark McDowall
5cb649e9d8 Fixed: Attempt to parse and reject ambiguous dates
Closes #6799
2024-05-09 22:03:44 -07:00
Mark McDowall
cac7d239ea Fixed: Parsing of partial season pack 2024-05-09 22:03:44 -07:00
Sonarr
3940059ea3 Automated API Docs update
ignore-downstream
2024-05-09 22:03:31 -07:00
Weblate
20d00fe88c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Michael5564445 <michaelvelosk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/uk/
Translation: Servarr/Sonarr
2024-05-09 22:03:24 -07:00
Mark McDowall
b4d05214ae Fixed: Ignore invalid movie tags when writing XBMC metadata
Co-authored-by: Bogdan <mynameisbogdan@users.noreply.github.com>
2024-05-08 18:45:19 -07:00
Mark McDowall
cc0a284660 New: Add series tags to Webhook and Notifiarr events 2024-05-08 18:45:19 -07:00
Mark McDowall
f50a263f4f New: Add Custom Format Score to file in Episode Details 2024-05-08 18:45:03 -07:00
Mark McDowall
29176c8367 New: Has Unmonitored Season filter for Series 2024-05-08 18:44:52 -07:00
Bogdan
1eddf3a152 Use number input for seed ratio 2024-05-08 18:44:36 -07:00
Bogdan
8360dd7a7b Fixed: Parsing long downloading/seeding values from Transmission 2024-05-08 18:44:27 -07:00
Bogdan
7e8d8500f2 Fixed: Next/previous/last air dates with Postgres DB
Closes #6790
2024-05-08 18:43:51 -07:00
Mark McDowall
cae134ec7b New: Dark theme for login screen
Closes #6751
2024-05-08 18:42:54 -07:00
Stevie Robinson
f81bb3ec19 New: Blocklist Custom Filters
Closes #6763
2024-05-08 18:42:41 -07:00
Bogdan
128309068d Fixed: Initialize databases after app folder migrations
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-05-08 18:42:15 -07:00
Mickaël Thomas
73a4bdea52 New: Support stoppedUP and stoppedDL states from qBittorrent 2024-05-08 18:41:59 -07:00
Bogdan
47ba002806 Fixed: Indexer flags for torrent release pushes 2024-05-04 18:56:52 -07:00
Mark McDowall
ba88185dea New: Treat batch releases with total episode count as full season release
Closes #6757
2024-05-04 18:56:15 -07:00
Mark McDowall
e24ce40eb8 Fixed: History with unknown episode
Closes #6782
2024-05-04 18:55:56 -07:00
Stevie Robinson
8be8c7f89c Add missing translation key 2024-05-04 18:55:44 -07:00
Bogdan
7166a6c019 Parameter binding for API requests 2024-05-04 18:55:12 -07:00
Mark McDowall
3fbe436138 Forward X-Forwarded-Host header
Closes #6764
2024-05-04 18:54:55 -07:00
Jared
92eab4b2e2 New: Config file setting to disable log database
Closes #6743
2024-05-04 18:54:42 -07:00
Mika
23c741fd00 Add file-count for Transmission RPC 2024-05-04 18:53:47 -07:00
Weblate
8ddf46113b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translation: Servarr/Sonarr
2024-05-04 18:53:15 -07:00
Bogdan
c81ae65461 Fixed: Limit titles in task name to 10 series 2024-04-27 18:09:08 -07:00
Bogdan
efb3fa93e4 Fixed: Retrying download for pushed releases
ignore-downstream
#6752
2024-04-27 21:08:40 -04:00
Stevie Robinson
04bd535cfc New: Don't initially select 0 byte files in Interactive Import
Closes #6686
2024-04-27 21:07:41 -04:00
Bogdan
9738101042 Treat CorruptDatabaseException as a startup failure
ignore-downstream
2024-04-27 18:06:49 -07:00
Bogdan
1df7cdc65e New: Add KRaLiMaRKo and BluDragon to release group parsing exceptions
ignore-downstream
2024-04-27 18:06:38 -07:00
Jared
d051dac12c New: Optionally use Environment Variables for settings in config.xml
Closes #6744
2024-04-27 21:06:26 -04:00
Bogdan
5d01ecd30e Bump frontend dependencies
ignore-downstream
2024-04-27 18:05:16 -07:00
Mark McDowall
316b5cbf75 New: Validate that folders in paths don't start or end with a space
Closes #6709
2024-04-27 21:04:50 -04:00
Bogdan
2440672179 Bump SixLabors.ImageSharp to 3.1.4
ignore-downstream
2024-04-27 18:04:35 -07:00
Mark McDowall
a97fbcc40a Fixed: Improve paths longer than 256 on Windows failing to hardlink 2024-04-27 18:04:26 -07:00
Christopher
d738035fed New: Remove qBitorrent torrents that reach inactive seeding time 2024-04-27 21:04:16 -04:00
Mark McDowall
dc3e932102 macOS tests now run on arm64 2024-04-27 18:03:12 -07:00
Weblate
aded9d95f7 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Ano10 <arnaudthommeray+github@ik.me>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Mailme Dashite <mailmedashite@protonmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: aghus <aghus.m@outlook.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: maodun96 <435795439@qq.com>
Co-authored-by: toeiazarothis <patrickdealmeida89000@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-04-27 18:03:03 -07:00
Mark McDowall
b81c3ee4a8 Fix labeling config 2024-04-15 21:14:49 -07:00
Mark McDowall
cf6748a80c Fix merge conflict labeling 2024-04-15 21:14:49 -07:00
Sonarr
ef6cc7fa3a Automated API Docs update
ignore-downstream
2024-04-15 20:35:29 -07:00
Mark McDowall
f9b013a8bf New: Parse releases with multiple Ukranian audio tracks
Closes #6714
2024-04-15 20:25:41 -07:00
Bogdan
e966254462 Fixed: Re-testing edited providers will forcibly test them 2024-04-15 20:25:31 -07:00
Gauvino
016c4b353b Add merge conflict labeler 2024-04-15 23:25:13 -04:00
Uruk
d71c619f1a Update CI dependencies 2024-04-15 20:24:20 -07:00
Gauthier
6c232b062c New: Multi Language selection per indexer
Closes #2854
2024-04-15 23:24:05 -04:00
Josh McKinney
d6278fced4 Add dev container workspace
Allows the linting and style settings for the frontend to be applied even when you load the main repo as a workspace
2024-04-15 20:23:13 -07:00
Weblate
317ce39aa2 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Fonkio <maxime.fabre10@gmail.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Jacopo Luca Maria Latrofa <jacopo.latrofa@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translation: Servarr/Sonarr
2024-04-15 20:23:04 -07:00
Mark McDowall
941985f65b Bump version to 4.0.4 2024-04-13 10:05:01 -07:00
Mark McDowall
10daf97d81 Improve build step dependencies 2024-04-12 16:00:46 -07:00
Mark McDowall
6b08117d7d Improve release notes for main releases 2024-04-12 16:00:46 -07:00
Weblate
9afe1c4b3f Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: YSLG <1451164040@qq.com>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-04-12 16:00:37 -07:00
Mark McDowall
0fdbbd018c New: Parse absolute episode numbers within square brackets
Closes #6694
2024-04-12 16:00:16 -07:00
Sonarr
8a7b67c593 Automated API Docs update
ignore-downstream
2024-04-09 16:17:48 -07:00
Weblate
4b8afe3d33 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: myrad2267 <myrad2267@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-04-09 16:16:11 -07:00
Bogdan
476e7a7b94 Fixed: Changing Release Type in Manage Episodes
Closes #6706
2024-04-09 19:14:56 -04:00
Bogdan
1fcd2b492c Prevent multiple enumerations in Custom Formats token 2024-04-09 16:14:33 -07:00
Bogdan
1aef91041e New: Detect shfs mounts in disk space 2024-04-09 16:14:16 -07:00
Bogdan
fc06e51352 Fixed: Renaming episodes for a series
Closes #6640
2024-04-09 19:13:59 -04:00
Mark McDowall
f4c19a384b New: Auto tag series based on tags present/absent on series
Closes #6236
2024-04-09 16:13:30 -07:00
Josh McKinney
5061dc4b5e Add DevContainer, VSCode config and extensions.json 2024-04-09 19:12:58 -04:00
Mark McDowall
37863a8deb New: Option to prefix app name on Telegram notification titles 2024-04-09 19:12:20 -04:00
Mark McDowall
5c42935eb3 Fixed: Improve AniList testing with Media filters 2024-04-09 16:12:05 -07:00
Weblate
dac69445e4 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: Michael5564445 <michaelvelosk@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/uk/
Translation: Servarr/Sonarr
2024-04-05 23:13:02 -07:00
Qstick
aca10f6f4f Fixed: Skip move when source and destination are the same
ignore-downstream

Co-Authored-By: Colin Hebert <makkhdyn@gmail.com>
(cherry picked from commit 7a5ae56a96700f401726ac80b3031a25207d8f75)
2024-04-05 23:11:37 -07:00
Mark McDowall
74cdf01e49 New: Set 'Release Type' during Manual Import
Closes #6681
2024-04-06 02:11:17 -04:00
Mark McDowall
a169ebff2a Fixed: Sending ntfy.sh notifications with unicode characters
Closes #6679
2024-04-06 02:11:03 -04:00
fireph
7fc3bebc91 New: Footnote to indicate some renaming tokens support truncation 2024-04-06 02:10:42 -04:00
Till Krüss
e672996dbb Improve text for file deleted through UI/API 2024-04-06 02:09:55 -04:00
Stevie Robinson
238ba85f0a New: Informational text on Custom Formats modal 2024-04-06 02:08:57 -04:00
Cuki
1562d3bae3 Fixed: Use widely supported display mode for PWA 2024-04-06 02:08:08 -04:00
Jendrik Weise
7776ec9955 Reimport files imported prematurely during script import 2024-04-05 23:07:38 -07:00
Jendrik Weise
af5a681ab7 Fix ignoring title based on pre-rename episodefile 2024-04-05 23:07:38 -07:00
Jendrik Weise
0a7f3a12c2 Do not remove all extras when script importing 2024-04-05 23:07:38 -07:00
Jendrik Weise
2ef46e5b90 Fix incorrect subtitle copy regex 2024-04-05 23:07:38 -07:00
Mark McDowall
6003ca1696 Fixed: Deleted episodes not being unmonitored when series folder has been deleted
Closes #6678
2024-04-05 23:07:07 -07:00
Mark McDowall
0937ee6fef Fixed: Path parsing incorrectly treating series title as episode number 2024-04-05 23:06:56 -07:00
Mark McDowall
60ee7cc716 Fixed: Cleanse BHD RSS key in log files
Closes #6666
2024-04-06 02:06:35 -04:00
Mark McDowall
4e83820511 Bump version to 4.0.3 2024-03-31 21:52:19 -07:00
Sonarr
5a66b949cf Automated API Docs update
ignore-downstream
2024-03-31 21:43:33 -07:00
Weblate
f010f56290 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: 王锋 <17611382361@163.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-03-31 21:43:09 -07:00
Louis R
060b789bc6 Fixed: Exceptions when checking for routable IPv4 addresses 2024-03-28 01:31:28 -04:00
Bogdan
7353fe479d New: Allow HEAD requests to ping endpoint
Closes #6656
2024-03-28 01:30:45 -04:00
Alex Cortelyou
1ec1ce58e9 New: Add additional fields to Webhook Manual Interaction Required events 2024-03-28 01:30:21 -04:00
Stevie Robinson
35d0e6a6f8 Fixed: Handling torrents with relative path in rTorrent 2024-03-28 01:29:15 -04:00
Carlos Gustavo Sarmiento
588372fd95 Fixed: qBittorrent not correctly handling retention during testing 2024-03-28 01:28:41 -04:00
Bogdan
13c925b341 New: Advanced settings toggle in import list, notification and download client modals 2024-03-27 22:27:51 -07:00
iceypotato
1335efd487 New: My Anime List import list
Closes #5148
2024-03-27 22:27:34 -07:00
Mark McDowall
d338425951 Fixed: Use custom formats from import during rename 2024-03-27 22:27:25 -07:00
Mark McDowall
fc6494c569 Fixed: Task with removed series causing error 2024-03-27 22:27:14 -07:00
Weblate
c403b2cdd5 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Altair <villagermd@outlook.com>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Stanislav <prekop3@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translation: Servarr/Sonarr
2024-03-27 22:27:07 -07:00
Weblate
cf3d51bab2 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Casselluu <jack10193@163.com>
Co-authored-by: Gianmarco Novelli <rinogaetano94@live.it>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: MadaxDeLuXe <madaxdeluxe@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: infoaitek24 <info@aitekph.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: shimmyx <shimmygodx@gmail.com>
Co-authored-by: vfaergestad <vgf@hotmail.no>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-03-21 21:21:30 -07:00
Mark McDowall
dec3fc6889 Fixed: Don't add series from import list with no matched TVDB ID 2024-03-22 00:21:04 -04:00
Mark McDowall
40bac23698 New: Support parsing season number from season folder when importing
Closes #903
2024-03-21 21:20:49 -07:00
Mark McDowall
88de927435 Fixed: Plex Watchlist import list 2024-03-21 21:20:27 -07:00
Mark McDowall
29204c93a3 New: Parsing multi-episode file with two and three digit episode numbers
Closes #6631
2024-03-21 21:20:13 -07:00
Mark McDowall
c641733781 Fixed: Task progress messages in the UI
Closes #6632
2024-03-21 21:20:08 -07:00
Weblate
58de0310fd Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Gianmarco Novelli <rinogaetano94@live.it>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: MadaxDeLuXe <madaxdeluxe@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: infoaitek24 <info@aitekph.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: vfaergestad <vgf@hotmail.no>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translation: Servarr/Sonarr
2024-03-21 21:20:01 -07:00
Bogdan
172b1a82d1 Sort series by title in task name 2024-03-21 21:19:23 -07:00
Bogdan
e14568adef Ensure not allowed cursor is shown for disabled select inputs 2024-03-21 21:19:23 -07:00
Weblate
381ce61aef Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dennis Langthjem <dennis@langthjem.dk>
Co-authored-by: DimitriDR <dimitridroeck@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ihor Mudryi <mudryy33@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/uk/
Translation: Servarr/Sonarr
2024-03-13 21:49:22 -07:00
Mark McDowall
9f705e4161 Fixed: Release push with only Magnet URL
Closes #6622
2024-03-13 21:47:50 -07:00
Mark McDowall
063dba22a8 Fixed: Disabled select option still selectable 2024-03-13 21:47:33 -07:00
Mark McDowall
6d552f2a60 New: Show Series title and season number after task name when applicable
Closes #6601
2024-03-13 21:47:22 -07:00
Mark McDowall
4d4d63921b Add notification for build success/failures 2024-03-14 00:47:01 -04:00
Alan Collins
6584d95331 New: Update Custom Format renaming token to allow excluding specific formats
Closes #6615
2024-03-14 00:46:33 -04:00
Bogdan
86034beccd Bump ImageSharp, Polly, DryIoc, STJson, WindowsServices 2024-03-13 21:44:23 -07:00
Mark McDowall
4aa56e3f91 Fixed: Parsing of some French and Spanish anime releases 2024-03-13 21:44:07 -07:00
Stevie Robinson
2ec071a5ec Update release profile download client warning 2024-03-09 23:54:21 -05:00
Alan Collins
d86aeb7472 New: Release Hash renaming token
Closes #6570
2024-03-09 23:54:06 -05:00
Alan Collins
48cb5d2271 New: 'Custom Format: Format Name' rename token 2024-03-09 23:53:02 -05:00
bakerboy448
a0329adeba Improve single file detected as full season messaging 2024-03-09 23:51:29 -05:00
Bogdan
89bef4af99 New: Wider modal for Interactive Search and Manual Import 2024-03-09 23:50:45 -05:00
Mark McDowall
a12cdb34bc Fixed: Error sending Manual Interaction Required notification 2024-03-07 18:11:36 -08:00
Bogdan
13e29bd257 Prevent NullRef in naming when truncating a null Release Group 2024-03-07 18:11:28 -08:00
Sonarr
61a7515041 Automated API Docs update
ignore-downstream
2024-03-07 17:34:04 -08:00
Weblate
2c25245860 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jason54 <jason54700.jg@gmail.com>
Co-authored-by: Mark Martines <mark-martines@hotmail.com>
Co-authored-by: Maxence Winandy <maxence.winandy@gmail.com>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: linkin931 <931linkin@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-03-07 17:30:56 -08:00
Bogdan
18aadb544e Fixed: Maintain release type for items in Manual Import 2024-03-07 20:30:20 -05:00
Helvio Pedreschi
c7dd7abf89 Fixed: WebApp functionality on Apple devices 2024-03-07 20:29:50 -05:00
CheAle14
d0e9504af0 Fix import list exclusion props 2024-03-07 17:26:29 -08:00
Bogdan
e81bb3b993 Persist page size for Import List Exclusions 2024-03-07 17:25:27 -08:00
Bogdan
f211433b77 Remove debugger from metadata source and rearrange some imports 2024-03-07 17:25:19 -08:00
Bogdan
2068c5393e Fixed: URL Base setting for Kodi connections 2024-03-07 17:25:19 -08:00
Mark McDowall
0183812cc5 Fixed: Overly aggressive exception release group parsing
Closes #6591
2024-03-07 17:25:10 -08:00
Bogdan
7f09903a06 New: Episode Requested filter for Interactive Search 2024-03-02 21:26:23 -08:00
Mark McDowall
fa4c11a943 New: Do not automatically unmonitor episodes renamed outside of Sonarr
Closes #6584
2024-03-02 21:23:27 -08:00
Sonarr
653963a247 Automated API Docs update
ignore-downstream
2024-03-02 21:22:27 -08:00
Mark McDowall
32c32e2f88 Fixed: Issue extracting subtitle information for unknown episodes 2024-03-02 21:22:15 -08:00
nopoz
07bd159436 New: Add download directory & move completed for Deluge
Closes #4575
2024-03-03 00:22:03 -05:00
Mark McDowall
20273b07ad Properly type validation errors/warnings 2024-03-02 21:21:24 -08:00
bakerboy448
e5f19f01fa Update AddSeries Messaging and Logging 2024-03-03 00:21:16 -05:00
Louis R
13af6f5779 Fixed: Don't disable IPv6 in IPv6-only Environment
Closes #6545
2024-03-03 00:20:36 -05:00
Mark McDowall
71c2c0570b Renamed SeasonPackSpecification to ReleaseTypeSpecification 2024-03-03 00:19:44 -05:00
Mark McDowall
64c6a8879b Queue Manual Import commands at high priority 2024-03-02 21:19:26 -08:00
Weblate
7f061a9583 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: GkhnGRBZ <gkhn.gurbuz@hotmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Nicolò Castagnola <nipica@outlook.it>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translation: Servarr/Sonarr
2024-03-02 21:19:17 -08:00
The Dark
4285691064 New: Import list exclusion pagination
Closes #6079
2024-03-03 00:19:02 -05:00
Sonarr
de9899c60e Automated API Docs update
ignore-downstream
2024-03-01 17:33:41 -08:00
Weblate
6c8758c27a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translation: Servarr/Sonarr
2024-03-01 17:32:55 -08:00
Mark McDowall
086d3b5afa Increase migration timeout to 5 minutes 2024-03-01 17:26:26 -08:00
Mark McDowall
f8a0751775 New: Release Type (Single/Multi episode and Season Pack) for Custom Formats
Closes #3562
2024-03-01 17:26:26 -08:00
Mark McDowall
c99d81e79b New: Bypass archived history for failed downloads in SABnzbd 2024-03-01 17:26:10 -08:00
Mark McDowall
9fd193d2a8 New: URL Base setting for Media Server connections
Closes #4416
2024-03-01 17:24:52 -08:00
Bogdan
64f4365fe9 Update caniuse-lite 2024-03-01 17:24:41 -08:00
Bogdan
2773f77e1c New: Options button for Missing/Cutoff Unmet 2024-03-01 17:24:41 -08:00
Weblate
0a84b4a8e9 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-03-01 17:24:35 -08:00
Weblate
236d8e4c50 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-02-27 20:44:11 -08:00
Mark McDowall
16d3827dbd Fixed: Processing updated episodes in series after refresh
Closes #6560
2024-02-27 20:42:27 -08:00
Bogdan
fa600e62e0 Fixed: Error when download client information is unavailable for Manual Interaction Required event
Closes #6558
(cherry picked from commit 173b1d6a4c0f2125c4413c0c09b269d87a1f1ee8)

Co-authored-by: Qstick <qstick@gmail.com>
2024-02-27 23:42:08 -05:00
Mark McDowall
fb6fc568c5 Fixed: Don't store seasons from import list items in database
Closes #6555
2024-02-27 20:40:39 -08:00
Bogdan
1f97679868 Fixed: Selection of last added custom filter
Plus some translations and typos
2024-02-27 20:40:33 -08:00
Mark McDowall
b34e0f8259 Fixed: Ignore language in split episode title 2024-02-27 00:33:07 -05:00
Mark McDowall
4c170d0452 New: Update anime episodes by season/episode number instead of absolute episode number
Closes #6547
2024-02-26 21:32:46 -08:00
Mark McDowall
6dc0a88004 New: Search for recently aired anime episodes with added absolute episode number
Closes #2044
2024-02-26 21:32:46 -08:00
Mark McDowall
33b44a8a53 New: Option to sync season monitoring state when importing from another Sonarr instance
Closes #6542
2024-02-26 21:32:39 -08:00
Mark McDowall
cb72e752f9 Fixed: Parsing of subtitle languages separated by dash
Closes #6494
2024-02-27 00:32:31 -05:00
Weblate
a11ee7bc11 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: EDUYO <eduardoestabiel@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Sadi A. Nogueira <contato@sadi.eti.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Xupix <colinaubert25@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-02-26 21:32:04 -08:00
Stevie Robinson
98d60e1a8e Replace URLs in translations with tokens 2024-02-27 00:30:58 -05:00
Bruno Garcia
6377c688fc Update Sentry SDK add features
Co-authored-by: Stefan Jandl <reg@bitfox.at>
2024-02-27 00:30:32 -05:00
Mark McDowall
7a37f130f9 Bump version to 4.0.2 2024-02-26 20:54:08 -08:00
Mark McDowall
724dd7e733 Clean branch name to remove slashes 2024-02-20 21:23:52 -08:00
Weblate
e1be3b20e9 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: 闫锦彪 <yanjinbiaohere@163.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-02-20 20:20:43 -08:00
Sonarr
2f041f9ec1 Automated API Docs update
ignore-downstream
2024-02-20 20:20:28 -08:00
Mark McDowall
f10ccf587d Don't fail fast for integration tests 2024-02-20 20:12:57 -08:00
Mark McDowall
0242b40eda Use GitHubActionsTestLogger for test reporting 2024-02-20 20:12:57 -08:00
Bogdan
7a768b5d0f New: Indexer flags
Closes #2782
2024-02-20 23:12:45 -05:00
Mark McDowall
a57254640f Upgrade actions/setup-dotnet to v4 2024-02-20 20:10:36 -08:00
Mark McDowall
1a6f45bafd Upgrade actions/checkout to v4 2024-02-20 20:10:36 -08:00
Mark McDowall
c6071f6d81 Upgrade node to 20.11.1 2024-02-20 20:10:36 -08:00
Bogdan
2a47a237d4 Fix typo in log message matching by TVRage ID 2024-02-20 20:10:30 -08:00
Mark McDowall
a7607ac7d6 Fixed: Only match via TV Rage ID if TheTVDB ID is not available
Closes #6517
2024-02-20 20:10:17 -08:00
Mark McDowall
43797b326d New: Parse releases with season and episode numbers separated by a period
Closes #6492
2024-02-20 20:10:09 -08:00
Mark McDowall
5c4f829993 Fixed: Multi-word genres in Auto Tags
Fixed #6488
2024-02-20 20:10:02 -08:00
Bogdan
8dd8c95f36 Fixed: Avoid upgrades for custom formats cut-off already met 2024-02-20 20:09:52 -08:00
Weblate
6f6036a199 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Chaoshuai Lü <lcs@meta.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: wgwqd <wgwqd@163.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-02-20 20:08:04 -08:00
Mark McDowall
625e500132 Use 'paths-ignore' instead of 'path' with only negative matches 2024-02-17 22:39:18 -08:00
Weblate
39575b1248 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: David13467 <davidnow00@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Hicabi Erdem <bilgi@hicabierdem.com>
Co-authored-by: Lucas <sixagag973@fkcod.com>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Steve Hansen <steve@hansenconsultancy.be>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: aghus <aghus.m@outlook.com>
Co-authored-by: bai0012 <baicongrui@gmail.com>
Co-authored-by: bogdan-rgb <b.hmelniczky@yandex.ru>
Co-authored-by: savin-msk <ns@a77.io>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-02-13 16:56:10 -08:00
abcasada
f1d343218c Hints for week column and short dates in UI settings
(cherry picked from commit 4558f552820b52bb1f9cd97fdabe03654ce9924a)
2024-02-13 16:47:48 -08:00
Qstick
b0829d5537 Fixed: Correctly persist calendar custom filter selection
ignore-downstream
2024-02-13 16:47:41 -08:00
Bogdan
965e7c22d9 Fixed: Reprocessing multi-language file in Manage Episodes 2024-02-13 16:47:31 -08:00
Bogdan
75535e61d9 Fixed: Reprocessing custom formats for file in Manual Import 2024-02-13 16:47:31 -08:00
Bogdan
c0b17d9345 Show download client ID as hint in select options 2024-02-13 16:46:55 -08:00
Bogdan
84e657482d Improve messaging on indexer specified download client is not available 2024-02-13 16:46:55 -08:00
Bogdan
ed27bcf213 Fixed: Refresh tags state to clear removed tags by housekeeping
(cherry picked from commit 2510f44c25bee6fede27d9fa2b9614176d12cb55)
2024-02-13 16:46:46 -08:00
Bogdan
9ee2fe6f5c Fix typo 2024-02-13 16:46:38 -08:00
Bogdan
d5e19b8c3c Prevent useless builds 2024-02-13 16:46:38 -08:00
Sonarr
2957b40512 Automated API Docs update
ignore-downstream
2024-02-13 16:46:26 -08:00
Bogdan
9f46fc923d Fix typo for Downloaded Episodes Scan command name 2024-02-13 16:46:02 -08:00
Bogdan
7dc1e47504 Fix translation token for DL client directory help text 2024-02-13 16:46:02 -08:00
Bogdan
d15c116f13 Fix translation keys for indexer validation 2024-02-13 16:46:02 -08:00
Bogdan
dd704579df Improve add/loading error notices 2024-02-13 16:46:02 -08:00
Bogdan
bd9d4b484c Update Custom Format Deletion confirmation message
Consistency with the rest of the Delete*MessageText
2024-02-13 16:46:02 -08:00
Qstick
913b845faa Fixed: Prevent anime search with ep/season if not supported 2024-02-09 21:30:08 -05:00
Stas Panasiuk
6e81517d51 New: Parsing titles with multiple translated titles 2024-02-06 23:03:36 -05:00
Mark McDowall
34e74eecd7 Fixed: Don't attempt to import from list with title only (#6477)
Closes #6474
2024-02-06 23:02:26 -05:00
Mark McDowall
895eccebc5 New: Parse and reject split episode releases and files 2024-02-06 23:02:03 -05:00
Mark McDowall
f722d49b3a Fixed: Don't use sub folder to check for free disk space for update
Closes #6478
2024-02-06 20:01:30 -08:00
bakerboy448
cac97c057f Improve Custom Format rejection messaging 2024-02-06 23:01:07 -05:00
jab416171
63e132d257 Wrapped fields on series details page in div
This allows you to triple click to select the path for instance, similar
to the details page in radarr.
2024-02-06 19:59:02 -08:00
Mark McDowall
6ab1d8e16b New: Log database engine version on startup 2024-02-06 22:58:49 -05:00
Stevie Robinson
80630bf97f Fixed: Wrapping of naming tokens with alternate separators 2024-02-06 22:58:09 -05:00
Bogdan
904285045b Fixed: Naming validation when using max token length 2024-02-06 19:57:44 -08:00
Stevie Robinson
1006ec6b52 really fix translation key 2024-02-06 19:57:33 -08:00
Mark McDowall
4cb1100704 Fixed: Remove old naming config from v3 API responses
Closes #6460
2024-02-06 19:57:25 -08:00
Mark McDowall
745b92daf4 Fixed: Redirecting after login
Closes #6454
2024-02-06 19:57:17 -08:00
Weblate
9eafdbd1af Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ole Nørby <ole@olenoerby.dk>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: aghus <aghus.m@outlook.com>
Co-authored-by: gr0sz <joshuatg727@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-02-06 19:57:09 -08:00
Weblate
200396ef7a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-01-31 19:39:13 -08:00
Stevie Robinson
c5a724f14e New: Send 'On Manual Interaction Required' notifications in more cases
Closes #6448
2024-01-31 19:38:51 -08:00
Mark McDowall
42b11528b4 New: Improve multi-language negate Custom Format
Closes #6408
2024-01-31 19:37:44 -08:00
Alex Herbig
e2210228b3 New: Add RZeroX to release group parsing exceptions 2024-01-31 19:36:39 -08:00
Bogdan
ded7c3c6e2 Only bind shortcut for pending changes confirmation when it's shown 2024-01-31 19:36:21 -08:00
Stevie Robinson
e1c6722aad New: Ignore 'Other' subfolder when scanning disk
Closes #6437
2024-01-31 19:35:21 -08:00
Bogdan
e17655c26a Fixed: Notifications with only On Series Add enabled being labeled as disabled 2024-01-31 19:34:51 -08:00
Stevie Robinson
e66c628241 Update some translation keys 2024-01-31 19:34:17 -08:00
Mark McDowall
8f0514a91d Fixed: Grouped calendar events not correctly showing as downloading
Closes #6441
2024-01-31 19:33:46 -08:00
bakerboy448
d7aea82e45 Improve Release Grabbing & Failure Logging 2024-01-31 19:33:38 -08:00
Mark McDowall
19db75b36b Add max token length (including ellipsis) for some tokens
New: Accept ':##' on renaming tokens to allow specifying a maximum length for series, episode titles and release group
Closes #6416
2024-01-31 19:33:21 -08:00
Weblate
11a18b534a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Crocmou <slaanesh8854@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lars <lars.erik.heloe@gmail.com>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Stas Panasiuk <temnyip@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: resi23 <x-resistant-x@gmx.de>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/uk/
Translation: Servarr/Sonarr
2024-01-31 19:33:13 -08:00
Sonarr
70807a9dcf Automated API Docs update
ignore-downstream
2024-01-26 22:09:26 -08:00
Weblate
350600607d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Alexander <a.burdun@gmail.com>
Co-authored-by: Crocmou <slaanesh8854@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: diaverso <alexito_perez.95@hotmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: zichichi <sollami@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/uk/
Translation: Servarr/Sonarr
2024-01-26 22:09:16 -08:00
Mark McDowall
e9f0c96249 Fixed: Specials not allowing multi-episode select in Manual Import
Closes #6429
2024-01-26 22:01:04 -08:00
ta264
d9acbf5682 Fixed: FolderWritable check for CIFS shares mounted in Unix
This reverts commit 8c892a732ed57af9bb1f39743e0c16361f41b50f.

(cherry picked from commit 96384521c59233dab5bd8289e7c84043f75b84a2)
2024-01-26 22:00:50 -08:00
Stevie Robinson
07cbd7c8d2 Fixed: Validating DownloadStation output path
Closes #6421
2024-01-27 00:59:43 -05:00
Mark McDowall
0ea189d03c Fixed: History retention for Newsbin 2024-01-26 21:56:13 -08:00
Bogdan
9e3f9f9618 Fixed: Testing for disabled Notifications 2024-01-26 21:56:05 -08:00
The Dark
68c326ae27 New: Import list clean library option
Closes #5201
2024-01-27 00:55:52 -05:00
Weblate
46367d2023 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: wilfriedarma <wilfriedarma.collet@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-01-26 21:54:57 -08:00
Sonarr
b64c52a846 Automated API Docs update
ignore-downstream
2024-01-22 20:59:24 -08:00
Mark McDowall
345854d0fe New: Optionally remove from queue by changing category to 'Post-Import Category' when configured
Closes #6023
2024-01-22 23:56:35 -05:00
Bogdan
31baed4b2c Fixed: Sorting by name in Manage Indexer and Download Client modals 2024-01-22 20:56:01 -08:00
Bogdan
7d0d503a5e New: Display database migration version in Status 2024-01-22 20:55:53 -08:00
Stevie Robinson
9f50166fa6 Fixed: Regular Expression Custom Format translation 2024-01-22 23:55:33 -05:00
Bogdan
3c1ca6ea4e New: Expand seasons with all episodes having missing air dates 2024-01-22 20:54:35 -08:00
Mark McDowall
3cd4c67ba1 New: Add download client name to pending items waiting for a specific client
Closes #6274
2024-01-22 20:52:01 -08:00
Mark McDowall
fc3a2e9ab2 New: Added some extra pixels to grouped calendar events
Closes #6395
2024-01-22 20:51:53 -08:00
Mark McDowall
a71d40edba New: Add recycle bin path for deleted episodes to webhook/custom script
Closes #6114
2024-01-22 20:51:38 -08:00
Mark McDowall
9ba5850fca Fixed: Parsing Hungarian anime releases
Closes #6275
2024-01-22 20:51:27 -08:00
Mark McDowall
0d06418194 New: Add size to more history events
Closes #6234
2024-01-22 20:51:19 -08:00
Mark McDowall
f95dd00b51 Fixed: Migrating subtitle files with unexpectedly large number at end
Closes #6409
2024-01-22 20:50:43 -08:00
Bogdan
271266b10a Fix possible NullRef in Email Encryption migration 2024-01-22 20:50:34 -08:00
Mark McDowall
cab93249ec Fixed: Number only hashes getting substituted incorrectly 2024-01-20 16:44:12 -08:00
Mark McDowall
8921c5d7a0 Fixed: Subtitle title migration when original title is null 2024-01-20 16:43:53 -08:00
Weblate
dbbf1a7f58 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2024-01-20 16:43:40 -08:00
Jendrik Weise
69f99373e5 New: Parse subtitle titles
Closes #5955
2024-01-20 15:19:33 -08:00
Mark McDowall
7be5732a3a New: Option to disable Email encryption
Closes #6380
2024-01-20 15:18:26 -08:00
Mark McDowall
e66ba84fc0 New: Log warning if less than 1 GB free space during update
Closes #6385
2024-01-20 15:18:06 -08:00
Mark McDowall
c0b30a5028 Fixed: Series poster view on mobile devices
Closes #6387
2024-01-20 15:17:55 -08:00
Bogdan
3cf4d2907e Transpile logical assignment operators with babel 2024-01-20 15:17:42 -08:00
Weblate
ae96ebca57 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Bastián Quezada <baskezada@gmail.com>
Co-authored-by: Blair Noctis <fqmxz5hyfba7ft85@neon.casa>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Deleted User <noreply+2593@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Julian Baquero <julian-baquero@upc.edu.co>
Co-authored-by: Koch Norbert <kochnorbert@icloud.com>
Co-authored-by: MaddionMax <kovacs.tamas@ius.hu>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: brn <barantsenkul@gmail.com>
Co-authored-by: resi23 <x-resistant-x@gmx.de>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-01-20 15:17:33 -08:00
Mark McDowall
d336aaf3f0 Fixed: Don't clone indexer API Key
Closes #6265
2024-01-19 21:30:34 -08:00
bakerboy448
ec40bc6eea Improve Release Title Custom Format debugging
Towards #5598
2024-01-19 21:30:24 -08:00
Mark McDowall
75bb34afaa Bump version to 4.0.1 2024-01-19 19:26:38 -08:00
Stevie Robinson
de1cc25c90 Translate backend: Autotagging + CF specs, Metadata + ImportLists
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-18 21:47:03 -08:00
Mark McDowall
9884f6f282 Fixed: Icons on full color calendar events
Closes #6331
2024-01-19 00:43:51 -05:00
Qstick
e792db4d33 New: Improve All Series call by using dictionary for stats iteration 2024-01-18 21:43:34 -08:00
Bogdan
2dbf5b5a71 Check Content-Type in FileList parser 2024-01-18 21:43:17 -08:00
Stevie Robinson
c6bb6ad878 Round off the seeded ratio when checking for removal candidates
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-18 21:43:07 -08:00
Bogdan
bfd24da2d9 Fixed: Importing Plex RSS lists with invalid items (#6374) 2024-01-19 00:42:51 -05:00
Stevie Robinson
8dd3b45c90 New: Drop commands table content before postgres migration
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-19 00:42:31 -05:00
Stevie Robinson
0b0f21d0ac Update install.sh to not prompt for package installation
Script will exit without input if a prereq package is missing
2024-01-18 21:41:38 -08:00
Sonarr
738f5c58ad Automated API Docs update
ignore-downstream
2024-01-18 21:41:30 -08:00
Weblate
9a7b5bf14e Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Blair Noctis <fqmxz5hyfba7ft85@neon.casa>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Petr Vojar <vojar.petr@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: crayon3shawn <crayon3shawn@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_TW/
Translation: Servarr/Sonarr
2024-01-18 21:41:14 -08:00
Mark McDowall
e1260d504e Re-enable deploy 2024-01-15 21:55:35 -08:00
Sonarr
736651324f Automated API Docs update
ignore-downstream
2024-01-15 21:55:22 -08:00
Bogdan
489f03441b Fixed: Filter history by multiple event types 2024-01-16 00:54:27 -05:00
Stevie Robinson
e4b5d559df Sort Custom Filters
Closes #6334
2024-01-16 00:53:21 -05:00
Stevie Robinson
07fbb0d1f4 Add missing translation keys from Indexer Settings
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-16 00:52:55 -05:00
Stevie Robinson
666455f9b1 New: Add 'zhtw' and 'yue' language codes as Chinese language
Closes #6363
2024-01-16 00:52:40 -05:00
Bogdan
091449d9bf Throw download as failed for invalid magnet links 2024-01-15 21:51:17 -08:00
Qstick
f87a66fcba Improved http timeout handling 2024-01-15 21:51:02 -08:00
Blair Noctis
1bba7e177b Fixed: Improve help text for download client priority
Closes #6270
2024-01-16 00:50:25 -05:00
Rubicj
57445bbe57 New: Added column in Queue
Closes #6270
2024-01-16 00:28:28 -05:00
Qstick
ec91142c85 Fixed: Only use frames for Primary video stream for analysis
(cherry picked from commit 581828b0dcfcd4aa1ae581b899f812071457c9ca)
2024-01-15 23:03:46 -06:00
Mark McDowall
0685896ed8 Fixed: Prevent selecting season or episode in Manual Import if series or episode is not selected
Closes #6354
2024-01-14 12:37:33 -08:00
Mark McDowall
ee0048c768 Fixed: Reprocessing multi-language file in Manual Import 2024-01-14 12:37:33 -08:00
bakerboy448
16e5ffa467 Update logging to indicate a hardlink is being attempted 2024-01-14 15:16:53 -05:00
Mark McDowall
431c66c7c1 Update PR Template
[skip ci]
2024-01-14 12:12:30 -08:00
Mark McDowall
57bd6539c8 Update bug_report.yml
[skip ci]
2024-01-14 12:44:37 -05:00
Mark McDowall
637cb1711d Update PR template
[skip ci]
2024-01-14 12:43:14 -05:00
Weblate
7e011df2b2 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Daniele Prevedello <dprevedello86@gmail.com>
Co-authored-by: DimitriDR <dimitridroeck@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Watashi <drazy24@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: hansaudun <hans@n5.no>
Co-authored-by: hcharbonnier <hugues.charbonnier@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-01-13 17:07:06 -08:00
Stevie Robinson
79907c881c Add: New icon for deleted episodes with status missing from disk
Signed-off-by: Stevie Robinson <stevie.robinson@gmail.com>
2024-01-13 16:35:13 -08:00
Mark McDowall
db6a627983 Don't write global.json while updating API docs 2024-01-13 16:33:17 -08:00
Weblate
d76a489be6 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Watashi <drazy24@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2024-01-13 16:33:01 -08:00
Mark McDowall
fd17df0dd0 New: Optional directory setting for Aria2
Closes #6343
2024-01-13 16:32:09 -08:00
Mark McDowall
53cf530893 Fixed: Series posters flickering when width changes repeatedly
Closes #6311
2024-01-13 16:31:58 -08:00
Mark McDowall
91f33c670e Fix post-build test reporting and report summary 2024-01-13 11:32:01 -08:00
Mark McDowall
d322619733 Temporarily disable deploy 2024-01-12 17:45:32 -08:00
Mark McDowall
1182798929 Actually run Windows integration tests 2024-01-12 17:45:32 -08:00
Mark McDowall
ad0249c7db Use publish-unit-test-result-action for test result reporting 2024-01-12 17:45:32 -08:00
Mark McDowall
3259e6dc10 Download artifacts for Publish Test Results workflow 2024-01-12 17:45:32 -08:00
Mark McDowall
541d3307e1 Don't use TestCase for single test 2024-01-12 17:45:32 -08:00
Mark McDowall
ad60352bae Ignore CA1825 2024-01-12 17:45:32 -08:00
728 changed files with 20132 additions and 6332 deletions

View File

@@ -0,0 +1,13 @@
// This file is used to open the backend and frontend in the same workspace, which is necessary as
// the frontend has vscode settings that are distinct from the backend
{
"folders": [
{
"path": ".."
},
{
"path": "../frontend"
}
],
"settings": {}
}

View File

@@ -0,0 +1,19 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet
{
"name": "Sonarr",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-6.0",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "16",
"nvmVersion": "latest"
}
},
"forwardPorts": [8989],
"customizations": {
"vscode": {
"extensions": ["esbenp.prettier-vscode"]
}
}
}

View File

@@ -203,6 +203,7 @@ dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA1825.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion

View File

@@ -1,5 +1,5 @@
name: Bug Report
description: 'Support Requests will be closed immediately, if you are not 100% certain this is a bug please go to our Reddit, Discord, Forums, or IRC first. Only bug reports for v4 will be accepted, older versions are EOL & unsupported.'
description: 'Only bug reports for v4 will be accepted, older versions are no longer receiving bug fixes and support issues will be closed immediately.'
labels: ['needs-triage']
body:
- type: checkboxes

View File

@@ -1,14 +1,15 @@
#### Database Migration
YES | NO
#### Description
A few sentences describing the overall goals of the pull request's commits.
#### Todos
- [ ] Tests
- [ ] Wiki Updates
<!-- Remove any of the following sections if they are not used -->
#### Screenshots for UI Changes
#### Database Migration
YES - ###
#### Issues Fixed or Closed by this PR
* Closes #
*

View File

@@ -27,7 +27,7 @@ runs:
using: 'composite'
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
- name: Setup Postgres
if: ${{ inputs.use_postgres }}
@@ -77,11 +77,11 @@ runs:
- name: Run tests
shell: bash
run: dotnet test ./_tests/Sonarr.*.Test.dll --filter "${{ inputs.filter }}" --logger trx --results-directory "${{ env.RESULTS_NAME }}"
run: dotnet test ./_tests/Sonarr.*.Test.dll --filter "${{ inputs.filter }}" --logger "trx;LogFileName=${{ env.RESULTS_NAME }}.trx" --logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
- name: Upload Test Results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: results-${{ env.RESULTS_NAME }}
path: ${{ env.RESULTS_NAME }}/*.trx
path: TestResults/*.trx

12
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot
version: 2
updates:
- package-ecosystem: "devcontainers"
directory: "/"
schedule:
interval: weekly

18
.github/labeler.yml vendored
View File

@@ -1,17 +1,23 @@
'connection':
- src/NzbDrone.Core/Notifications/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Notifications/**/*
'db-migration':
- src/NzbDrone.Core/Datastore/Migration/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Datastore/Migration/*
'download-client':
- src/NzbDrone.Core/Download/Clients/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Download/Clients/**/*
'indexer':
- src/NzbDrone.Core/Indexers/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Indexers/**/*
'parsing':
- src/NzbDrone.Core/Parser/**/*
- changed-files:
- any-glob-to-any-file: src/NzbDrone.Core/Parser/**/*
'ui-only':
- all: ['frontend/**/*']
- changed-files:
- any-glob-to-all-files: frontend/**/*

View File

@@ -26,17 +26,11 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
id: setup-dotnet
with:
dotnet-version: '6.0.x'
- name: Create temporary global.json
run: |
echo '{"sdk":{"version": "${{ steps.setup-dotnet.outputs.dotnet-version }}" } }' > ./global.json
- name: Create openapi.json
run: ./docs.sh Linux

View File

@@ -5,9 +5,14 @@ on:
branches:
- develop
- main
paths-ignore:
- 'src/Sonarr.Api.*/openapi.json'
pull_request:
branches:
- develop
paths-ignore:
- 'src/NzbDrone.Core/Localization/Core/**'
- 'src/Sonarr.Api.*/openapi.json'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -15,9 +20,9 @@ concurrency:
env:
FRAMEWORK: net6.0
BRANCH: ${{ github.head_ref || github.ref_name }}
RAW_BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
SONARR_MAJOR_VERSION: 4
VERSION: 4.0.0
VERSION: 4.0.5
jobs:
backend:
@@ -28,10 +33,10 @@ jobs:
version: ${{ steps.variables.outputs.version }}
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
- name: Setup Environment Variables
id: variables
@@ -43,6 +48,8 @@ jobs:
echo "SDK_PATH=${{ env.DOTNET_ROOT }}/sdk/${DOTNET_VERSION}" >> "$GITHUB_ENV"
echo "SONARR_VERSION=$SONARR_VERSION" >> "$GITHUB_ENV"
echo "BRANCH=${RAW_BRANCH_NAME//\//-}" >> "$GITHUB_ENV"
echo "framework=${{ env.FRAMEWORK }}" >> "$GITHUB_OUTPUT"
echo "major_version=${{ env.SONARR_MAJOR_VERSION }}" >> "$GITHUB_OUTPUT"
echo "version=$SONARR_VERSION" >> "$GITHUB_OUTPUT"
@@ -69,11 +76,11 @@ jobs:
framework: ${{ env.FRAMEWORK }}
runtime: linux-x64
- name: Publish osx-x64 Test Artifact
- name: Publish osx-arm64 Test Artifact
uses: ./.github/actions/publish-test-artifact
with:
framework: ${{ env.FRAMEWORK }}
runtime: osx-x64
runtime: osx-arm64
# Build Artifacts (grouped by OS)
@@ -102,19 +109,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Volta
uses: volta-cli/action@v4
- name: Yarn Intsall
- name: Yarn Install
run: yarn install
- name: Lint
run: yarn lint
- name: Stylelint
run: yarn stylelint
run: yarn stylelint -f github
- name: Build
run: yarn build --env production
@@ -136,7 +143,7 @@ jobs:
artifact: tests-linux-x64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
- os: macos-latest
artifact: tests-osx-x64
artifact: tests-osx-arm64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory!=IntegrationTest&TestCategory!=AutomationTest
- os: windows-latest
artifact: tests-win-x64
@@ -144,7 +151,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
@@ -159,7 +166,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
@@ -173,6 +180,7 @@ jobs:
integration_test:
needs: backend
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
include:
@@ -182,19 +190,19 @@ jobs:
binary_artifact: build_linux
binary_path: linux-x64/${{ needs.backend.outputs.framework }}/Sonarr
- os: macos-latest
artifact: tests-osx-x64
artifact: tests-osx-arm64
filter: TestCategory!=ManualTest&TestCategory!=WINDOWS&TestCategory=IntegrationTest
binary_artifact: build_macos
binary_path: osx-x64/${{ needs.backend.outputs.framework }}/Sonarr
binary_path: osx-arm64/${{ needs.backend.outputs.framework }}/Sonarr
- os: windows-latest
artifact: tests-win-x64
filter: TestCategory!=ManualTest&TestCategory=WINDOWS&TestCategory=IntegrationTest
filter: TestCategory!=ManualTest&TestCategory!=LINUX&TestCategory=IntegrationTest
binary_artifact: build_windows
binary_path: win-x64/${{ needs.backend.outputs.framework }}/Sonarr
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Test
uses: ./.github/actions/test
@@ -209,7 +217,7 @@ jobs:
deploy:
if: ${{ github.ref_name == 'develop' || github.ref_name == 'main' }}
needs: [backend, unit_test, unit_test_postgres, integration_test]
needs: [backend, frontend, unit_test, unit_test_postgres, integration_test]
secrets: inherit
uses: ./.github/workflows/deploy.yml
with:
@@ -217,3 +225,25 @@ jobs:
branch: ${{ github.ref_name }}
major_version: ${{ needs.backend.outputs.major_version }}
version: ${{ needs.backend.outputs.version }}
notify:
name: Discord Notification
needs: [backend, frontend, unit_test, unit_test_postgres, integration_test, deploy]
if: ${{ !cancelled() && (github.ref_name == 'develop' || github.ref_name == 'main') }}
env:
STATUS: ${{ contains(needs.*.result, 'failure') && 'failure' || 'success' }}
runs-on: ubuntu-latest
steps:
- name: Notify
uses: tsickert/discord-webhook@v6.0.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
username: 'GitHub Actions'
avatar-url: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png'
embed-title: "${{ github.workflow }}: ${{ env.STATUS == 'success' && 'Success' || 'Failure' }}"
embed-url: 'https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}'
embed-description: |
**Branch** ${{ github.ref }}
**Build** ${{ needs.backend.outputs.version }}
embed-color: ${{ env.STATUS == 'success' && '3066993' || '15158332' }}

26
.github/workflows/conflict_labeler.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Merge Conflict Labeler
on:
push:
branches:
- develop
pull_request_target:
branches:
- develop
types: [synchronize]
jobs:
label:
name: Labeling
runs-on: ubuntu-latest
if: ${{ github.repository == 'Sonarr/Sonarr' }}
permissions:
contents: read
pull-requests: write
steps:
- name: Apply label
uses: eps1lon/actions-label-merge-conflict@v3
with:
dirtyLabel: 'merge-conflict'
repoToken: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -41,7 +41,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Package
uses: ./.github/actions/package
@@ -60,7 +60,7 @@ jobs:
contents: write
steps:
- name: Check out
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Download release artifacts
uses: actions/download-artifact@v4
@@ -69,12 +69,38 @@ jobs:
pattern: release_*
merge-multiple: true
- name: Get Previous Release
id: previous-release
uses: cardinalby/git-get-release-action@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
latest: true
prerelease: ${{ inputs.branch != 'main' }}
- name: Generate Release Notes
id: generate-release-notes
uses: actions/github-script@v7
with:
github-token: ${{ github.token }}
result-encoding: string
script: |
const { data } = await github.rest.repos.generateReleaseNotes({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: 'v${{ inputs.version }}',
target_commitish: '${{ github.sha }}',
previous_tag_name: '${{ steps.previous-release.outputs.tag_name }}',
})
return data.body
- name: Create release
uses: ncipollo/release-action@v1
with:
artifacts: _artifacts/Sonarr.*
commit: ${{ github.sha }}
generateReleaseNotes: true
generateReleaseNotes: false
body: ${{ steps.generate-release-notes.outputs.result }}
name: ${{ inputs.version }}
prerelease: ${{ inputs.branch != 'main' }}
skipIfReleaseExists: true

View File

@@ -8,5 +8,6 @@ jobs:
contents: read
pull-requests: write
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v5

View File

@@ -8,14 +8,15 @@ on:
jobs:
lock:
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
steps:
- uses: dessant/lock-threads@v2
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '90'
issue-exclude-created-before: ''
issue-exclude-labels: 'one-day-maybe'
issue-lock-labels: ''
issue-lock-comment: ''
issue-inactive-days: '90'
exclude-issue-created-before: ''
exclude-any-issue-labels: 'one-day-maybe'
add-issue-labels: ''
issue-comment: ''
issue-lock-reason: 'resolved'
process-only: ''

View File

@@ -1,24 +0,0 @@
name: Publish Test Results
on:
workflow_run:
workflows: ['Build']
types:
- completed
permissions:
contents: read
actions: read
checks: write
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Publish Test Results
uses: phoenix-actions/test-reporting@v12
with:
artifact: /results-(.*)/
name: '$1'
path: '*.trx'
reporter: dotnet-trx

1
.gitignore vendored
View File

@@ -127,6 +127,7 @@ coverage*.xml
coverage*.json
setup/Output/
*.~is
.mono
#VS outout folders
bin

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"ms-dotnettools.csdevkit",
"ms-vscode-remote.remote-containers"
]
}

26
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": "Run Sonarr",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build dotnet",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/_output/net6.0/Sonarr",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

44
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,44 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build dotnet",
"command": "dotnet",
"type": "process",
"args": [
"msbuild",
"-restore",
"${workspaceFolder}/src/Sonarr.sln",
"-p:GenerateFullPaths=true",
"-p:Configuration=Debug",
"-p:Platform=Posix",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Sonarr.sln",
"-property:GenerateFullPaths=true",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Sonarr.sln"
],
"problemMatcher": "$msCompile"
}
]
}

View File

@@ -98,7 +98,7 @@ echo "Directories created"
echo ""
echo "Installing pre-requisite Packages"
# shellcheck disable=SC2086
apt update && apt install $app_prereq
apt update && apt install -y $app_prereq
echo ""
ARCH=$(dpkg --print-architecture)
# get arch

View File

@@ -2,6 +2,8 @@ const loose = true;
module.exports = {
plugins: [
'@babel/plugin-transform-logical-assignment-operators',
// Stage 1
'@babel/plugin-proposal-export-default-from',
['@babel/plugin-transform-optional-chaining', { loose }],

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -20,6 +21,7 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
import BlocklistFilterModal from './BlocklistFilterModal';
import BlocklistRowConnector from './BlocklistRowConnector';
class Blocklist extends Component {
@@ -114,9 +116,13 @@ class Blocklist extends Component {
error,
items,
columns,
selectedFilterKey,
filters,
customFilters,
totalRecords,
isRemoving,
isClearingBlocklistExecuting,
onFilterSelect,
...otherProps
} = this.props;
@@ -161,6 +167,15 @@ class Blocklist extends Component {
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={customFilters}
filterModalConnectorComponent={BlocklistFilterModal}
onFilterSelect={onFilterSelect}
/>
</PageToolbarSection>
</PageToolbar>
@@ -180,7 +195,11 @@ class Blocklist extends Component {
{
isPopulated && !error && !items.length &&
<Alert kind={kinds.INFO}>
{translate('NoHistoryBlocklist')}
{
selectedFilterKey === 'all' ?
translate('NoHistoryBlocklist') :
translate('BlocklistFilterHasNoItems')
}
</Alert>
}
@@ -251,11 +270,15 @@ Blocklist.propTypes = {
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
totalRecords: PropTypes.number,
isRemoving: PropTypes.bool.isRequired,
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
onRemoveSelected: PropTypes.func.isRequired,
onClearBlocklistPress: PropTypes.func.isRequired
onClearBlocklistPress: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired
};
export default Blocklist;

View File

@@ -6,6 +6,7 @@ import * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage';
import * as blocklistActions from 'Store/Actions/blocklistActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import Blocklist from './Blocklist';
@@ -13,10 +14,12 @@ import Blocklist from './Blocklist';
function createMapStateToProps() {
return createSelector(
(state) => state.blocklist,
createCustomFiltersSelector('blocklist'),
createCommandExecutingSelector(commandNames.CLEAR_BLOCKLIST),
(blocklist, isClearingBlocklistExecuting) => {
(blocklist, customFilters, isClearingBlocklistExecuting) => {
return {
isClearingBlocklistExecuting,
customFilters,
...blocklist
};
}
@@ -97,6 +100,10 @@ class BlocklistConnector extends Component {
this.props.setBlocklistSort({ sortKey });
};
onFilterSelect = (selectedFilterKey) => {
this.props.setBlocklistFilter({ selectedFilterKey });
};
onClearBlocklistPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
};
@@ -122,6 +129,7 @@ class BlocklistConnector extends Component {
onPageSelect={this.onPageSelect}
onRemoveSelected={this.onRemoveSelected}
onSortPress={this.onSortPress}
onFilterSelect={this.onFilterSelect}
onTableOptionChange={this.onTableOptionChange}
onClearBlocklistPress={this.onClearBlocklistPress}
{...this.props}
@@ -142,6 +150,7 @@ BlocklistConnector.propTypes = {
gotoBlocklistPage: PropTypes.func.isRequired,
removeBlocklistItems: PropTypes.func.isRequired,
setBlocklistSort: PropTypes.func.isRequired,
setBlocklistFilter: PropTypes.func.isRequired,
setBlocklistTableOption: PropTypes.func.isRequired,
clearBlocklist: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired

View File

@@ -0,0 +1,54 @@
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FilterModal from 'Components/Filter/FilterModal';
import { setBlocklistFilter } from 'Store/Actions/blocklistActions';
function createBlocklistSelector() {
return createSelector(
(state: AppState) => state.blocklist.items,
(blocklistItems) => {
return blocklistItems;
}
);
}
function createFilterBuilderPropsSelector() {
return createSelector(
(state: AppState) => state.blocklist.filterBuilderProps,
(filterBuilderProps) => {
return filterBuilderProps;
}
);
}
interface BlocklistFilterModalProps {
isOpen: boolean;
}
export default function BlocklistFilterModal(props: BlocklistFilterModalProps) {
const sectionItems = useSelector(createBlocklistSelector());
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
const customFilterType = 'blocklist';
const dispatch = useDispatch();
const dispatchSetFilter = useCallback(
(payload: unknown) => {
dispatch(setBlocklistFilter(payload));
},
[dispatch]
);
return (
<FilterModal
// TODO: Don't spread all the props
{...props}
sectionItems={sectionItems}
filterBuilderProps={filterBuilderProps}
customFilterType={customFilterType}
dispatchSetFilter={dispatchSetFilter}
/>
);
}

View File

@@ -6,7 +6,7 @@ import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './HistoryEventTypeCell.css';
function getIconName(eventType) {
function getIconName(eventType, data) {
switch (eventType) {
case 'grabbed':
return icons.DOWNLOADING;
@@ -17,7 +17,7 @@ function getIconName(eventType) {
case 'downloadFailed':
return icons.DOWNLOADING;
case 'episodeFileDeleted':
return icons.DELETE;
return data.reason === 'MissingFromDisk' ? icons.FILE_MISSING : icons.DELETE;
case 'episodeFileRenamed':
return icons.ORGANIZE;
case 'downloadIgnored':
@@ -47,7 +47,7 @@ function getTooltip(eventType, data) {
case 'downloadFailed':
return translate('DownloadFailedEpisodeTooltip');
case 'episodeFileDeleted':
return translate('EpisodeFileDeletedTooltip');
return data.reason === 'MissingFromDisk' ? translate('EpisodeFileMissingTooltip') : translate('EpisodeFileDeletedTooltip');
case 'episodeFileRenamed':
return translate('EpisodeFileRenamedTooltip');
case 'downloadIgnored':
@@ -58,7 +58,7 @@ function getTooltip(eventType, data) {
}
function HistoryEventTypeCell({ eventType, data }) {
const iconName = getIconName(eventType);
const iconName = getIconName(eventType, data);
const iconKind = getIconKind(eventType);
const tooltip = getTooltip(eventType, data);

View File

@@ -25,7 +25,7 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
import QueueFilterModal from './QueueFilterModal';
import QueueOptionsConnector from './QueueOptionsConnector';
import QueueRowConnector from './QueueRowConnector';
import RemoveQueueItemsModal from './RemoveQueueItemsModal';
import RemoveQueueItemModal from './RemoveQueueItemModal';
class Queue extends Component {
@@ -305,9 +305,16 @@ class Queue extends Component {
}
</PageContentBody>
<RemoveQueueItemsModal
<RemoveQueueItemModal
isOpen={isConfirmRemoveModalOpen}
selectedCount={selectedCount}
canChangeCategory={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
return !!(item && item.downloadClientHasPostImportCategory);
})
)}
canIgnore={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
@@ -315,7 +322,7 @@ class Queue extends Component {
return !!(item && item.seriesId && item.episodeId);
})
)}
allPending={isConfirmRemoveModalOpen && (
pending={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);

View File

@@ -99,7 +99,9 @@ class QueueRow extends Component {
indexer,
outputPath,
downloadClient,
downloadClientHasPostImportCategory,
estimatedCompletionTime,
added,
timeleft,
size,
sizeleft,
@@ -362,6 +364,15 @@ class QueueRow extends Component {
);
}
if (name === 'added') {
return (
<RelativeDateCellConnector
key={name}
date={added}
/>
);
}
if (name === 'actions') {
return (
<TableRowCell
@@ -410,6 +421,7 @@ class QueueRow extends Component {
<RemoveQueueItemModal
isOpen={isRemoveQueueItemModalOpen}
sourceTitle={title}
canChangeCategory={!!downloadClientHasPostImportCategory}
canIgnore={!!series}
isPending={isPending}
onRemovePress={this.onRemoveQueueItemModalConfirmed}
@@ -440,7 +452,9 @@ QueueRow.propTypes = {
indexer: PropTypes.string,
outputPath: PropTypes.string,
downloadClient: PropTypes.string,
downloadClientHasPostImportCategory: PropTypes.bool,
estimatedCompletionTime: PropTypes.string,
added: PropTypes.string,
timeleft: PropTypes.string,
size: PropTypes.number,
sizeleft: PropTypes.number,

View File

@@ -1,171 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 Modal from 'Components/Modal/Modal';
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, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
remove: true,
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
//
// Render
render() {
const {
isOpen,
sourceTitle,
canIgnore,
isPending
} = this.props;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
isOpen={isOpen}
size={sizes.MEDIUM}
onModalClose={this.onModalClose}
>
<ModalContent
onModalClose={this.onModalClose}
>
<ModalHeader>
{translate('RemoveQueueItem', { sourceTitle })}
</ModalHeader>
<ModalBody>
<div>
{translate('RemoveQueueItemConfirmation', { sourceTitle })}
</div>
{
isPending ?
null :
<FormGroup>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>{translate('BlocklistRelease')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistReleaseSearchEpisodeAgainHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody>
<ModalFooter>
<Button onPress={this.onModalClose}>
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
}
RemoveQueueItemModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
canIgnore: PropTypes.bool.isRequired,
isPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default RemoveQueueItemModal;

View File

@@ -0,0 +1,230 @@
import React, { useCallback, useMemo, useState } from 'react';
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 Modal from 'Components/Modal/Modal';
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, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemModal.css';
interface RemovePressProps {
remove: boolean;
changeCategory: boolean;
blocklist: boolean;
skipRedownload: boolean;
}
interface RemoveQueueItemModalProps {
isOpen: boolean;
sourceTitle: string;
canChangeCategory: boolean;
canIgnore: boolean;
isPending: boolean;
selectedCount?: number;
onRemovePress(props: RemovePressProps): void;
onModalClose: () => void;
}
type RemovalMethod = 'removeFromClient' | 'changeCategory' | 'ignore';
type BlocklistMethod =
| 'doNotBlocklist'
| 'blocklistAndSearch'
| 'blocklistOnly';
function RemoveQueueItemModal(props: RemoveQueueItemModalProps) {
const {
isOpen,
sourceTitle,
canIgnore,
canChangeCategory,
isPending,
selectedCount,
onRemovePress,
onModalClose,
} = props;
const multipleSelected = selectedCount && selectedCount > 1;
const [removalMethod, setRemovalMethod] =
useState<RemovalMethod>('removeFromClient');
const [blocklistMethod, setBlocklistMethod] =
useState<BlocklistMethod>('doNotBlocklist');
const { title, message } = useMemo(() => {
if (!selectedCount) {
return {
title: translate('RemoveQueueItem', { sourceTitle }),
message: translate('RemoveQueueItemConfirmation', { sourceTitle }),
};
}
if (selectedCount === 1) {
return {
title: translate('RemoveSelectedItem'),
message: translate('RemoveSelectedItemQueueMessageText'),
};
}
return {
title: translate('RemoveSelectedItems'),
message: translate('RemoveSelectedItemsQueueMessageText', {
selectedCount,
}),
};
}, [sourceTitle, selectedCount]);
const removalMethodOptions = useMemo(() => {
return [
{
key: 'removeFromClient',
value: translate('RemoveFromDownloadClient'),
hint: multipleSelected
? translate('RemoveMultipleFromDownloadClientHint')
: translate('RemoveFromDownloadClientHint'),
},
{
key: 'changeCategory',
value: translate('ChangeCategory'),
isDisabled: !canChangeCategory,
hint: multipleSelected
? translate('ChangeCategoryMultipleHint')
: translate('ChangeCategoryHint'),
},
{
key: 'ignore',
value: multipleSelected
? translate('IgnoreDownloads')
: translate('IgnoreDownload'),
isDisabled: !canIgnore,
hint: multipleSelected
? translate('IgnoreDownloadsHint')
: translate('IgnoreDownloadHint'),
},
];
}, [canChangeCategory, canIgnore, multipleSelected]);
const blocklistMethodOptions = useMemo(() => {
return [
{
key: 'doNotBlocklist',
value: translate('DoNotBlocklist'),
hint: translate('DoNotBlocklistHint'),
},
{
key: 'blocklistAndSearch',
value: translate('BlocklistAndSearch'),
hint: multipleSelected
? translate('BlocklistAndSearchMultipleHint')
: translate('BlocklistAndSearchHint'),
},
{
key: 'blocklistOnly',
value: translate('BlocklistOnly'),
hint: multipleSelected
? translate('BlocklistMultipleOnlyHint')
: translate('BlocklistOnlyHint'),
},
];
}, [multipleSelected]);
const handleRemovalMethodChange = useCallback(
({ value }: { value: RemovalMethod }) => {
setRemovalMethod(value);
},
[setRemovalMethod]
);
const handleBlocklistMethodChange = useCallback(
({ value }: { value: BlocklistMethod }) => {
setBlocklistMethod(value);
},
[setBlocklistMethod]
);
const handleConfirmRemove = useCallback(() => {
onRemovePress({
remove: removalMethod === 'removeFromClient',
changeCategory: removalMethod === 'changeCategory',
blocklist: blocklistMethod !== 'doNotBlocklist',
skipRedownload: blocklistMethod === 'blocklistOnly',
});
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
}, [
removalMethod,
blocklistMethod,
setRemovalMethod,
setBlocklistMethod,
onRemovePress,
]);
const handleModalClose = useCallback(() => {
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
onModalClose();
}, [setRemovalMethod, setBlocklistMethod, onModalClose]);
return (
<Modal isOpen={isOpen} size={sizes.MEDIUM} onModalClose={handleModalClose}>
<ModalContent onModalClose={handleModalClose}>
<ModalHeader>{title}</ModalHeader>
<ModalBody>
<div className={styles.message}>{message}</div>
{isPending ? null : (
<FormGroup>
<FormLabel>{translate('RemoveQueueItemRemovalMethod')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="removalMethod"
value={removalMethod}
values={removalMethodOptions}
isDisabled={!canChangeCategory && !canIgnore}
helpTextWarning={translate(
'RemoveQueueItemRemovalMethodHelpTextWarning'
)}
onChange={handleRemovalMethodChange}
/>
</FormGroup>
)}
<FormGroup>
<FormLabel>
{multipleSelected
? translate('BlocklistReleases')
: translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="blocklistMethod"
value={blocklistMethod}
values={blocklistMethodOptions}
helpText={translate('BlocklistReleaseHelpText')}
onChange={handleBlocklistMethodChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button onPress={handleModalClose}>{translate('Close')}</Button>
<Button kind={kinds.DANGER} onPress={handleConfirmRemove}>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
export default RemoveQueueItemModal;

View File

@@ -1,174 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
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 Modal from 'Components/Modal/Modal';
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, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemsModal.css';
class RemoveQueueItemsModal extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
remove: true,
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
//
// Render
render() {
const {
isOpen,
selectedCount,
canIgnore,
allPending
} = this.props;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
isOpen={isOpen}
size={sizes.MEDIUM}
onModalClose={this.onModalClose}
>
<ModalContent
onModalClose={this.onModalClose}
>
<ModalHeader>
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
</ModalHeader>
<ModalBody>
<div className={styles.message}>
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', { selectedCount }) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
allPending ?
null :
<FormGroup>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistReleaseSearchEpisodeAgainHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody>
<ModalFooter>
<Button onPress={this.onModalClose}>
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
}
RemoveQueueItemsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
selectedCount: PropTypes.number.isRequired,
canIgnore: PropTypes.bool.isRequired,
allPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default RemoveQueueItemsModal;

View File

@@ -24,7 +24,11 @@ function TimeleftCell(props) {
} = props;
if (status === 'delay') {
const date = getRelativeDate(estimatedCompletionTime, shortDateFormat, showRelativeDates);
const date = getRelativeDate({
date: estimatedCompletionTime,
shortDateFormat,
showRelativeDates
});
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (
@@ -40,7 +44,11 @@ function TimeleftCell(props) {
}
if (status === 'downloadClientUnavailable') {
const date = getRelativeDate(estimatedCompletionTime, shortDateFormat, showRelativeDates);
const date = getRelativeDate({
date: estimatedCompletionTime,
shortDateFormat,
showRelativeDates
});
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (

View File

@@ -12,11 +12,10 @@ function App({ store, history }) {
<DocumentTitle title={window.Sonarr.instanceName}>
<Provider store={store}>
<ConnectedRouter history={history}>
<ApplyTheme>
<PageConnector>
<AppRoutes app={App} />
</PageConnector>
</ApplyTheme>
<ApplyTheme />
<PageConnector>
<AppRoutes app={App} />
</PageConnector>
</ConnectedRouter>
</Provider>
</DocumentTitle>

View File

@@ -1,50 +0,0 @@
import PropTypes from 'prop-types';
import React, { Fragment, useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import themes from 'Styles/Themes';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.ui.item.theme || window.Sonarr.theme,
(
theme
) => {
return {
theme
};
}
);
}
function ApplyTheme({ theme, children }) {
// Update the CSS Variables
const updateCSSVariables = useCallback(() => {
const arrayOfVariableKeys = Object.keys(themes[theme]);
const arrayOfVariableValues = Object.values(themes[theme]);
// Loop through each array key and set the CSS Variables
arrayOfVariableKeys.forEach((cssVariableKey, index) => {
// Based on our snippet from MDN
document.documentElement.style.setProperty(
`--${cssVariableKey}`,
arrayOfVariableValues[index]
);
});
}, [theme]);
// On Component Mount and Component Update
useEffect(() => {
updateCSSVariables(theme);
}, [updateCSSVariables, theme]);
return <Fragment>{children}</Fragment>;
}
ApplyTheme.propTypes = {
theme: PropTypes.string.isRequired,
children: PropTypes.object.isRequired
};
export default connect(createMapStateToProps)(ApplyTheme);

View File

@@ -0,0 +1,37 @@
import React, { Fragment, ReactNode, useCallback, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import themes from 'Styles/Themes';
import AppState from './State/AppState';
interface ApplyThemeProps {
children: ReactNode;
}
function createThemeSelector() {
return createSelector(
(state: AppState) => state.settings.ui.item.theme || window.Sonarr.theme,
(theme) => {
return theme;
}
);
}
function ApplyTheme({ children }: ApplyThemeProps) {
const theme = useSelector(createThemeSelector());
const updateCSSVariables = useCallback(() => {
Object.entries(themes[theme]).forEach(([key, value]) => {
document.documentElement.style.setProperty(`--${key}`, value);
});
}, [theme]);
// On Component Mount and Component Update
useEffect(() => {
updateCSSVariables();
}, [updateCSSVariables, theme]);
return <Fragment>{children}</Fragment>;
}
export default ApplyTheme;

View File

@@ -19,6 +19,7 @@ export interface AppSectionSaveState {
export interface PagedAppSectionState {
pageSize: number;
totalRecords?: number;
}
export interface AppSectionFilterState<T> {
@@ -38,6 +39,7 @@ export interface AppSectionItemState<T> {
isFetching: boolean;
isPopulated: boolean;
error: Error;
pendingChanges: Partial<T>;
item: T;
}

View File

@@ -1,4 +1,5 @@
import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
import BlocklistAppState from './BlocklistAppState';
import CalendarAppState from './CalendarAppState';
import CommandAppState from './CommandAppState';
import EpisodeFilesAppState from './EpisodeFilesAppState';
@@ -44,7 +45,17 @@ export interface CustomFilter {
filers: PropertyFilter[];
}
export interface AppSectionState {
dimensions: {
isSmallScreen: boolean;
width: number;
height: number;
};
}
interface AppState {
app: AppSectionState;
blocklist: BlocklistAppState;
calendar: CalendarAppState;
commands: CommandAppState;
episodeFiles: EpisodeFilesAppState;

View File

@@ -0,0 +1,8 @@
import Blocklist from 'typings/Blocklist';
import AppSectionState, { AppSectionFilterState } from './AppSectionState';
interface BlocklistAppState
extends AppSectionState<Blocklist>,
AppSectionFilterState<Blocklist> {}
export default BlocklistAppState;

View File

@@ -3,11 +3,15 @@ import AppSectionState, {
AppSectionItemState,
AppSectionSaveState,
AppSectionSchemaState,
PagedAppSectionState,
} from 'App/State/AppSectionState';
import Language from 'Language/Language';
import DownloadClient from 'typings/DownloadClient';
import ImportList from 'typings/ImportList';
import ImportListExclusion from 'typings/ImportListExclusion';
import ImportListOptionsSettings from 'typings/ImportListOptionsSettings';
import Indexer from 'typings/Indexer';
import IndexerFlag from 'typings/IndexerFlag';
import Notification from 'typings/Notification';
import QualityProfile from 'typings/QualityProfile';
import { UiSettings } from 'typings/UiSettings';
@@ -35,12 +39,29 @@ export interface QualityProfilesAppState
extends AppSectionState<QualityProfile>,
AppSectionSchemaState<QualityProfile> {}
export interface ImportListOptionsSettingsAppState
extends AppSectionItemState<ImportListOptionsSettings>,
AppSectionSaveState {}
export interface ImportListExclusionsSettingsAppState
extends AppSectionState<ImportListExclusion>,
AppSectionSaveState,
PagedAppSectionState,
AppSectionDeleteState {
pendingChanges: Partial<ImportListExclusion>;
}
export type IndexerFlagSettingsAppState = AppSectionState<IndexerFlag>;
export type LanguageSettingsAppState = AppSectionState<Language>;
export type UiSettingsAppState = AppSectionItemState<UiSettings>;
interface SettingsAppState {
advancedSettings: boolean;
downloadClients: DownloadClientAppState;
importListExclusions: ImportListExclusionsSettingsAppState;
importListOptions: ImportListOptionsSettingsAppState;
importLists: ImportListAppState;
indexerFlags: IndexerFlagSettingsAppState;
indexers: IndexerAppState;
languages: LanguageSettingsAppState;
notifications: NotificationAppState;

View File

@@ -28,7 +28,7 @@ class DayOfWeek extends Component {
if (view === calendarViews.WEEK) {
formatedDate = momentDate.format(calendarWeekColumnHeader);
} else if (view === calendarViews.FORECAST) {
formatedDate = getRelativeDate(date, shortDateFormat, showRelativeDates);
formatedDate = getRelativeDate({ date, shortDateFormat, showRelativeDates });
}
return (

View File

@@ -52,6 +52,10 @@ $fullColorGradient: rgba(244, 245, 246, 0.2);
.statusContainer {
display: flex;
align-items: center;
&:global(.fullColor) {
filter: var(--calendarFullColorFilter)
}
}
.statusIcon {

View File

@@ -102,7 +102,12 @@ class CalendarEvent extends Component {
{series.title}
</div>
<div className={styles.statusContainer}>
<div
className={classNames(
styles.statusContainer,
fullColorEvents && 'fullColor'
)}
>
{
missingAbsoluteNumber ?
<Icon
@@ -128,6 +133,7 @@ class CalendarEvent extends Component {
<span className={styles.statusIcon}>
<CalendarEventQueueDetails
{...queueItem}
fullColorEvents={fullColorEvents}
/>
</span> :
null
@@ -150,7 +156,7 @@ class CalendarEvent extends Component {
<Icon
className={styles.statusIcon}
name={icons.EPISODE_FILE}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
kind={kinds.WARNING}
title={translate('QualityCutoffNotMet')}
/> :
null
@@ -160,9 +166,8 @@ class CalendarEvent extends Component {
episodeNumber === 1 && seasonNumber > 0 ?
<Icon
className={styles.statusIcon}
name={icons.INFO}
name={icons.PREMIERE}
kind={kinds.INFO}
darken={fullColorEvents}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/> :
null
@@ -173,8 +178,8 @@ class CalendarEvent extends Component {
finaleType ?
<Icon
className={styles.statusIcon}
name={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
name={finaleType === 'series' ? icons.FINALE_SERIES : icons.FINALE_SEASON}
kind={finaleType === 'series' ? kinds.DANGER : kinds.WARNING}
title={getFinaleTypeName(finaleType)}
/> :
null
@@ -187,7 +192,6 @@ class CalendarEvent extends Component {
className={styles.statusIcon}
name={icons.INFO}
kind={kinds.PINK}
darken={fullColorEvents}
title={translate('Special')}
/> :
null

View File

@@ -43,6 +43,7 @@
.expandContainer,
.collapseContainer {
display: flex;
align-items: center;
justify-content: center;
}
@@ -50,6 +51,15 @@
margin-bottom: 5px;
}
.statusContainer {
display: flex;
align-items: center;
&:global(.fullColor) {
filter: var(--calendarFullColorFilter)
}
}
.statusIcon {
margin-left: 3px;
}

View File

@@ -16,6 +16,7 @@ interface CssExports {
'onAir': string;
'premiere': string;
'seriesTitle': string;
'statusContainer': string;
'statusIcon': string;
'unaired': string;
'unmonitored': string;

View File

@@ -145,45 +145,51 @@ class CalendarEventGroup extends Component {
{series.title}
</div>
{
isMissingAbsoluteNumber &&
<Icon
containerClassName={styles.statusIcon}
name={icons.WARNING}
title={translate('EpisodeMissingAbsoluteNumber')}
/>
}
<div
className={classNames(
styles.statusContainer,
fullColorEvents && 'fullColor'
)}
>
{
isMissingAbsoluteNumber &&
<Icon
containerClassName={styles.statusIcon}
name={icons.WARNING}
title={translate('EpisodeMissingAbsoluteNumber')}
/>
}
{
anyDownloading &&
<Icon
containerClassName={styles.statusIcon}
name={icons.DOWNLOADING}
title={translate('AnEpisodeIsDownloading')}
/>
}
{
anyDownloading &&
<Icon
containerClassName={styles.statusIcon}
name={icons.DOWNLOADING}
title={translate('AnEpisodeIsDownloading')}
/>
}
{
firstEpisode.episodeNumber === 1 && seasonNumber > 0 &&
<Icon
containerClassName={styles.statusIcon}
name={icons.INFO}
kind={kinds.INFO}
darken={fullColorEvents}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/>
}
{
firstEpisode.episodeNumber === 1 && seasonNumber > 0 &&
<Icon
containerClassName={styles.statusIcon}
name={icons.PREMIERE}
kind={kinds.INFO}
title={seasonNumber === 1 ? translate('SeriesPremiere') : translate('SeasonPremiere')}
/>
}
{
showFinaleIcon &&
lastEpisode.finaleType ?
<Icon
containerClassName={styles.statusIcon}
name={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
title={getFinaleTypeName(lastEpisode.finaleType)}
/> : null
}
{
showFinaleIcon &&
lastEpisode.finaleType ?
<Icon
containerClassName={styles.statusIcon}
name={lastEpisode.finaleType === 'series' ? icons.FINALE_SERIES : icons.FINALE_SEASON}
kind={lastEpisode.finaleType === 'series' ? kinds.DANGER : kinds.WARNING}
title={getFinaleTypeName(lastEpisode.finaleType)}
/> : null
}
</div>
</div>
<div className={styles.airingInfo}>
@@ -218,16 +224,19 @@ class CalendarEventGroup extends Component {
</div>
{
showEpisodeInformation &&
showEpisodeInformation ?
<Link
className={styles.expandContainer}
component="div"
onPress={this.onExpandPress}
>
&nbsp;
<Icon
name={icons.EXPAND}
/>
</Link>
&nbsp;
</Link> :
null
}
</div>
);

View File

@@ -10,7 +10,7 @@ function createIsDownloadingSelector() {
(state) => state.queue.details,
(episodeIds, details) => {
return details.items.some((item) => {
return item.episode && episodeIds.includes(item.episode.id);
return !!(item.episodeId && episodeIds.includes(item.episodeId));
});
}
);

View File

@@ -22,9 +22,20 @@ function Legend(props) {
if (showFinaleIcon) {
iconsToShow.push(
<LegendIconItem
name="Finale"
icon={icons.INFO}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
name={translate('SeasonFinale')}
icon={icons.FINALE_SEASON}
kind={kinds.WARNING}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesFinaleTooltip')}
/>
);
iconsToShow.push(
<LegendIconItem
name={translate('SeriesFinale')}
icon={icons.FINALE_SERIES}
kind={kinds.DANGER}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesFinaleTooltip')}
/>
);
@@ -33,10 +44,10 @@ function Legend(props) {
if (showSpecialIcon) {
iconsToShow.push(
<LegendIconItem
name="Special"
name={translate('Special')}
icon={icons.INFO}
kind={kinds.PINK}
darken={fullColorEvents}
fullColorEvents={fullColorEvents}
tooltip={translate('SpecialEpisode')}
/>
);
@@ -45,9 +56,10 @@ function Legend(props) {
if (showCutoffUnmetIcon) {
iconsToShow.push(
<LegendIconItem
name="Cutoff Not Met"
name={translate('Cutoff Not Met')}
icon={icons.EPISODE_FILE}
kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
kind={kinds.WARNING}
fullColorEvents={fullColorEvents}
tooltip={translate('QualityCutoffNotMet')}
/>
);
@@ -112,10 +124,10 @@ function Legend(props) {
<div>
<LegendIconItem
name="Premiere"
icon={icons.INFO}
name={translate('Premiere')}
icon={icons.PREMIERE}
kind={kinds.INFO}
darken={true}
fullColorEvents={fullColorEvents}
tooltip={translate('CalendarLegendSeriesPremiereTooltip')}
/>
@@ -129,6 +141,12 @@ function Legend(props) {
{iconsToShow[2]}
</div>
}
{
iconsToShow.length > 3 &&
<div>
{iconsToShow[3]}
</div>
}
</div>
);
}

View File

@@ -7,4 +7,8 @@
.icon {
margin-right: 5px;
&:global(.fullColorEvents) {
filter: var(--calendarFullColorFilter)
}
}

View File

@@ -1,3 +1,4 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
@@ -6,9 +7,9 @@ import styles from './LegendIconItem.css';
function LegendIconItem(props) {
const {
name,
fullColorEvents,
icon,
kind,
darken,
tooltip
} = props;
@@ -18,9 +19,11 @@ function LegendIconItem(props) {
title={tooltip}
>
<Icon
className={styles.icon}
className={classNames(
styles.icon,
fullColorEvents && 'fullColorEvents'
)}
name={icon}
darken={darken}
kind={kind}
/>
@@ -31,14 +34,10 @@ function LegendIconItem(props) {
LegendIconItem.propTypes = {
name: PropTypes.string.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
icon: PropTypes.object.isRequired,
kind: PropTypes.string.isRequired,
darken: PropTypes.bool.isRequired,
tooltip: PropTypes.string.isRequired
};
LegendIconItem.defaultProps = {
darken: false
};
export default LegendIconItem;

View File

@@ -13,6 +13,8 @@ export interface CommandBody {
trigger: string;
suppressMessages: boolean;
seriesId?: number;
seriesIds?: number[];
seasonNumber?: number;
}
interface Command extends ModelBase {

View File

@@ -6,7 +6,7 @@ export const CLEAR_LOGS = 'ClearLog';
export const CUTOFF_UNMET_EPISODE_SEARCH = 'CutoffUnmetEpisodeSearch';
export const DELETE_LOG_FILES = 'DeleteLogFiles';
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';
export const DOWNLOADED_EPSIODES_SCAN = 'DownloadedEpisodesScan';
export const DOWNLOADED_EPISODES_SCAN = 'DownloadedEpisodesScan';
export const EPISODE_SEARCH = 'EpisodeSearch';
export const INTERACTIVE_IMPORT = 'ManualImport';
export const MISSING_EPISODE_SEARCH = 'MissingEpisodeSearch';

View File

@@ -117,7 +117,7 @@ class FileBrowserModalContent extends Component {
className={styles.mappedDrivesWarning}
kind={kinds.WARNING}
>
<InlineMarkdown data={translate('MappedNetworkDrivesWindowsService')} />
<InlineMarkdown data={translate('MappedNetworkDrivesWindowsService', { url: 'https://wiki.servarr.com/sonarr/faq#why-cant-sonarr-see-my-files-on-a-remote-server' })} />
</Alert>
}

View File

@@ -1,3 +1,4 @@
import { maxBy } from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -8,6 +9,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import FilterBuilderRow from './FilterBuilderRow';
import styles from './FilterBuilderModalContent.css';
@@ -49,7 +51,7 @@ class FilterBuilderModalContent extends Component {
if (id) {
dispatchSetFilter({ selectedFilterKey: id });
} else {
const last = customFilters[customFilters.length -1];
const last = maxBy(customFilters, 'id');
dispatchSetFilter({ selectedFilterKey: last.id });
}
@@ -107,7 +109,7 @@ class FilterBuilderModalContent extends Component {
this.setState({
labelErrors: [
{
message: 'Label is required'
message: translate('LabelIsRequired')
}
]
});
@@ -145,13 +147,13 @@ class FilterBuilderModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Custom Filter
{translate('CustomFilter')}
</ModalHeader>
<ModalBody>
<div className={styles.labelContainer}>
<div className={styles.label}>
Label
{translate('Label')}
</div>
<div className={styles.labelInputContainer}>
@@ -165,7 +167,9 @@ class FilterBuilderModalContent extends Component {
</div>
</div>
<div className={styles.label}>Filters</div>
<div className={styles.label}>
{translate('Filters')}
</div>
<div className={styles.rows}>
{
@@ -192,7 +196,7 @@ class FilterBuilderModalContent extends Component {
<ModalFooter>
<Button onPress={onCancelPress}>
Cancel
{translate('Cancel')}
</Button>
<SpinnerErrorButton
@@ -200,7 +204,7 @@ class FilterBuilderModalContent extends Component {
error={saveError}
onPress={this.onSaveFilterPress}
>
Save
{translate('Save')}
</SpinnerErrorButton>
</ModalFooter>
</ModalContent>

View File

@@ -37,8 +37,8 @@ class CustomFilter extends Component {
dispatchSetFilter
} = this.props;
// Assume that delete and then unmounting means the delete was successful.
// Moving this check to a ancestor would be more accurate, but would have
// Assume that delete and then unmounting means the deletion was successful.
// Moving this check to an ancestor would be more accurate, but would have
// more boilerplate.
if (this.state.isDeleting && id === selectedFilterKey) {
dispatchSetFilter({ selectedFilterKey: 'all' });

View File

@@ -30,22 +30,24 @@ function CustomFiltersModalContent(props) {
<ModalBody>
{
customFilters.map((customFilter) => {
return (
<CustomFilter
key={customFilter.id}
id={customFilter.id}
label={customFilter.label}
filters={customFilter.filters}
selectedFilterKey={selectedFilterKey}
isDeleting={isDeleting}
deleteError={deleteError}
dispatchSetFilter={dispatchSetFilter}
dispatchDeleteCustomFilter={dispatchDeleteCustomFilter}
onEditPress={onEditCustomFilter}
/>
);
})
customFilters
.sort((a, b) => a.label.localeCompare(b.label))
.map((customFilter) => {
return (
<CustomFilter
key={customFilter.id}
id={customFilter.id}
label={customFilter.label}
filters={customFilter.filters}
selectedFilterKey={selectedFilterKey}
isDeleting={isDeleting}
deleteError={deleteError}
dispatchSetFilter={dispatchSetFilter}
dispatchDeleteCustomFilter={dispatchDeleteCustomFilter}
onEditPress={onEditCustomFilter}
/>
);
})
}
<div className={styles.addButtonContainer}>

View File

@@ -26,7 +26,8 @@ function createMapStateToProps() {
const values = _.map(filteredItems.sort(sortByName), (downloadClient) => {
return {
key: downloadClient.id,
value: downloadClient.name
value: downloadClient.name,
hint: `(${downloadClient.id})`
};
});

View File

@@ -19,7 +19,7 @@
.isDisabled {
opacity: 0.7;
cursor: not-allowed;
cursor: not-allowed !important;
}
.dropdownArrowContainer {

View File

@@ -11,6 +11,7 @@ import DownloadClientSelectInputConnector from './DownloadClientSelectInputConne
import EnhancedSelectInput from './EnhancedSelectInput';
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
import FormInputHelpText from './FormInputHelpText';
import IndexerFlagsSelectInput from './IndexerFlagsSelectInput';
import IndexerSelectInputConnector from './IndexerSelectInputConnector';
import KeyValueListInput from './KeyValueListInput';
import MonitorEpisodesSelectInput from './MonitorEpisodesSelectInput';
@@ -21,6 +22,7 @@ import PasswordInput from './PasswordInput';
import PathInputConnector from './PathInputConnector';
import QualityProfileSelectInputConnector from './QualityProfileSelectInputConnector';
import RootFolderSelectInputConnector from './RootFolderSelectInputConnector';
import SeriesTagInput from './SeriesTagInput';
import SeriesTypeSelectInput from './SeriesTypeSelectInput';
import TagInputConnector from './TagInputConnector';
import TagSelectInputConnector from './TagSelectInputConnector';
@@ -71,6 +73,9 @@ function getComponent(type) {
case inputTypes.INDEXER_SELECT:
return IndexerSelectInputConnector;
case inputTypes.INDEXER_FLAGS_SELECT:
return IndexerFlagsSelectInput;
case inputTypes.DOWNLOAD_CLIENT_SELECT:
return DownloadClientSelectInputConnector;
@@ -83,6 +88,9 @@ function getComponent(type) {
case inputTypes.DYNAMIC_SELECT:
return EnhancedSelectInputConnector;
case inputTypes.SERIES_TAG:
return SeriesTagInput;
case inputTypes.SERIES_TYPE_SELECT:
return SeriesTypeSelectInput;
@@ -264,6 +272,7 @@ FormInputGroup.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.any,
values: PropTypes.arrayOf(PropTypes.any),
isDisabled: PropTypes.bool,
type: PropTypes.string.isRequired,
kind: PropTypes.oneOf(kinds.all),
min: PropTypes.number,
@@ -278,6 +287,7 @@ FormInputGroup.propTypes = {
includeNoChange: PropTypes.bool,
includeNoChangeDisabled: PropTypes.bool,
selectedValueOptions: PropTypes.object,
indexerFlags: PropTypes.number,
pending: PropTypes.bool,
errors: PropTypes.arrayOf(PropTypes.object),
warnings: PropTypes.arrayOf(PropTypes.object),

View File

@@ -0,0 +1,62 @@
import React, { useCallback } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import EnhancedSelectInput from './EnhancedSelectInput';
const selectIndexerFlagsValues = (selectedFlags: number) =>
createSelector(
(state: AppState) => state.settings.indexerFlags,
(indexerFlags) => {
const value = indexerFlags.items.reduce((acc: number[], { id }) => {
// eslint-disable-next-line no-bitwise
if ((selectedFlags & id) === id) {
acc.push(id);
}
return acc;
}, []);
const values = indexerFlags.items.map(({ id, name }) => ({
key: id,
value: name,
}));
return {
value,
values,
};
}
);
interface IndexerFlagsSelectInputProps {
name: string;
indexerFlags: number;
onChange(payload: object): void;
}
function IndexerFlagsSelectInput(props: IndexerFlagsSelectInputProps) {
const { indexerFlags, onChange } = props;
const { value, values } = useSelector(selectIndexerFlagsValues(indexerFlags));
const onChangeWrapper = useCallback(
({ name, value }: { name: string; value: number[] }) => {
const indexerFlags = value.reduce((acc, flagId) => acc + flagId, 0);
onChange({ name, value: indexerFlags });
},
[onChange]
);
return (
<EnhancedSelectInput
{...props}
value={value}
values={values}
onChange={onChangeWrapper}
/>
);
}
export default IndexerFlagsSelectInput;

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import monitorOptions from 'Utilities/Series/monitorOptions';
import translate from 'Utilities/String/translate';
import SelectInput from './SelectInput';
import EnhancedSelectInput from './EnhancedSelectInput';
function MonitorEpisodesSelectInput(props) {
const {
@@ -19,7 +19,7 @@ function MonitorEpisodesSelectInput(props) {
get value() {
return translate('NoChange');
},
disabled: true
isDisabled: true
});
}
@@ -29,12 +29,12 @@ function MonitorEpisodesSelectInput(props) {
get value() {
return `(${translate('Mixed')})`;
},
disabled: true
isDisabled: true
});
}
return (
<SelectInput
<EnhancedSelectInput
values={values}
{...otherProps}
/>

View File

@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import monitorNewItemsOptions from 'Utilities/Series/monitorNewItemsOptions';
import SelectInput from './SelectInput';
import EnhancedSelectInput from './EnhancedSelectInput';
function MonitorNewItemsSelectInput(props) {
const {
@@ -16,7 +16,7 @@ function MonitorNewItemsSelectInput(props) {
values.unshift({
key: 'noChange',
value: 'No Change',
disabled: true
isDisabled: true
});
}
@@ -24,12 +24,12 @@ function MonitorNewItemsSelectInput(props) {
values.unshift({
key: 'mixed',
value: '(Mixed)',
disabled: true
isDisabled: true
});
}
return (
<SelectInput
<EnhancedSelectInput
values={values}
{...otherProps}
/>

View File

@@ -1,5 +0,0 @@
.input {
composes: input from '~Components/Form/TextInput.css';
font-family: $passwordFamily;
}

View File

@@ -1,7 +1,5 @@
import PropTypes from 'prop-types';
import React from 'react';
import TextInput from './TextInput';
import styles from './PasswordInput.css';
// Prevent a user from copying (or cutting) the password from the input
function onCopy(e) {
@@ -13,17 +11,14 @@ function PasswordInput(props) {
return (
<TextInput
{...props}
type="password"
onCopy={onCopy}
/>
);
}
PasswordInput.propTypes = {
className: PropTypes.string.isRequired
};
PasswordInput.defaultProps = {
className: styles.input
...TextInput.props
};
export default PasswordInput;

View File

@@ -27,6 +27,8 @@ function getType({ type, selectOptionsProviderAction }) {
return inputTypes.DYNAMIC_SELECT;
}
return inputTypes.SELECT;
case 'seriesTag':
return inputTypes.SERIES_TAG;
case 'tag':
return inputTypes.TEXT_TAG;
case 'tagSelect':

View File

@@ -28,7 +28,7 @@ function createMapStateToProps() {
get value() {
return translate('NoChange');
},
disabled: includeNoChangeDisabled
isDisabled: includeNoChangeDisabled
});
}
@@ -38,7 +38,7 @@ function createMapStateToProps() {
get value() {
return `(${translate('Mixed')})`;
},
disabled: true
isDisabled: true
});
}

View File

@@ -0,0 +1,53 @@
import React, { useCallback } from 'react';
import TagInputConnector from './TagInputConnector';
interface SeriesTageInputProps {
name: string;
value: number | number[];
onChange: ({
name,
value,
}: {
name: string;
value: number | number[];
}) => void;
}
export default function SeriesTagInput(props: SeriesTageInputProps) {
const { value, onChange, ...otherProps } = props;
const isArray = Array.isArray(value);
const handleChange = useCallback(
({ name, value: newValue }: { name: string; value: number[] }) => {
if (isArray) {
onChange({ name, value: newValue });
} else {
onChange({
name,
value: newValue.length ? newValue[newValue.length - 1] : 0,
});
}
},
[isArray, onChange]
);
let finalValue: number[] = [];
if (isArray) {
finalValue = value;
} else if (value === 0) {
finalValue = [];
} else {
finalValue = [value];
}
return (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore 2786 'TagInputConnector' isn't typed yet
<TagInputConnector
{...otherProps}
value={finalValue}
onChange={handleChange}
/>
);
}

View File

@@ -15,7 +15,7 @@ interface ISeriesTypeOption {
key: string;
value: string;
format?: string;
disabled?: boolean;
isDisabled?: boolean;
}
const seriesTypeOptions: ISeriesTypeOption[] = [
@@ -55,7 +55,7 @@ function SeriesTypeSelectInput(props: SeriesTypeSelectInputProps) {
values.unshift({
key: 'noChange',
value: translate('NoChange'),
disabled: includeNoChangeDisabled,
isDisabled: includeNoChangeDisabled,
});
}
@@ -63,7 +63,7 @@ function SeriesTypeSelectInput(props: SeriesTypeSelectInputProps) {
values.unshift({
key: 'mixed',
value: `(${translate('Mixed')})`,
disabled: true,
isDisabled: true,
});
}

View File

@@ -91,6 +91,7 @@ class TextTagInputConnector extends Component {
render() {
return (
<TagInput
delimiters={['Tab', 'Enter', ',']}
tagList={[]}
onTagAdd={this.onTagAdd}
onTagDelete={this.onTagDelete}

View File

@@ -12,18 +12,10 @@
.info {
color: var(--infoColor);
&:global(.darken) {
color: color(var(--infoColor) shade(30%));
}
}
.pink {
color: var(--pink);
&:global(.darken) {
color: color(var(--pink) shade(30%));
}
}
.success {

View File

@@ -18,7 +18,6 @@ class Icon extends PureComponent {
kind,
size,
title,
darken,
isSpinning,
...otherProps
} = this.props;
@@ -27,8 +26,7 @@ class Icon extends PureComponent {
<FontAwesomeIcon
className={classNames(
className,
styles[kind],
darken && 'darken'
styles[kind]
)}
icon={name}
spin={isSpinning}
@@ -61,7 +59,6 @@ Icon.propTypes = {
kind: PropTypes.string.isRequired,
size: PropTypes.number.isRequired,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
darken: PropTypes.bool.isRequired,
isSpinning: PropTypes.bool.isRequired,
fixedWidth: PropTypes.bool.isRequired
};
@@ -69,7 +66,6 @@ Icon.propTypes = {
Icon.defaultProps = {
kind: kinds.DEFAULT,
size: 14,
darken: false,
isSpinning: false,
fixedWidth: false
};

View File

@@ -40,18 +40,26 @@ class FilterMenuContent extends Component {
}
{
customFilters.map((filter) => {
return (
<FilterMenuItem
key={filter.id}
filterKey={filter.id}
selectedFilterKey={selectedFilterKey}
onPress={onFilterSelect}
>
{filter.label}
</FilterMenuItem>
);
})
customFilters.length > 0 ?
<MenuItemSeparator /> :
null
}
{
customFilters
.sort((a, b) => a.label.localeCompare(b.label))
.map((filter) => {
return (
<FilterMenuItem
key={filter.id}
filterKey={filter.id}
selectedFilterKey={selectedFilterKey}
onPress={onFilterSelect}
>
{filter.label}
</FilterMenuItem>
);
})
}
{

View File

@@ -63,6 +63,13 @@
width: 1280px;
}
.extraExtraLarge {
composes: modal;
width: 1600px;
}
@media only screen and (max-width: $breakpointExtraLarge) {
.modal.extraLarge {
width: 90%;
@@ -90,7 +97,8 @@
.modal.small,
.modal.medium,
.modal.large,
.modal.extraLarge {
.modal.extraLarge,
.modal.extraExtraLarge {
max-height: 100%;
width: 100%;
height: 100% !important;

View File

@@ -1,6 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'extraExtraLarge': string;
'extraLarge': string;
'large': string;
'medium': string;

View File

@@ -6,7 +6,13 @@ import { createSelector } from 'reselect';
import { fetchTranslations, saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchSeries } from 'Store/Actions/seriesActions';
import { fetchImportLists, fetchLanguages, fetchQualityProfiles, fetchUISettings } from 'Store/Actions/settingsActions';
import {
fetchImportLists,
fetchIndexerFlags,
fetchLanguages,
fetchQualityProfiles,
fetchUISettings
} from 'Store/Actions/settingsActions';
import { fetchStatus } from 'Store/Actions/systemActions';
import { fetchTags } from 'Store/Actions/tagActions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
@@ -51,6 +57,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.qualityProfiles.isPopulated,
(state) => state.settings.languages.isPopulated,
(state) => state.settings.importLists.isPopulated,
(state) => state.settings.indexerFlags.isPopulated,
(state) => state.system.status.isPopulated,
(state) => state.app.translations.isPopulated,
(
@@ -61,6 +68,7 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated,
languagesIsPopulated,
importListsIsPopulated,
indexerFlagsIsPopulated,
systemStatusIsPopulated,
translationsIsPopulated
) => {
@@ -72,6 +80,7 @@ const selectIsPopulated = createSelector(
qualityProfilesIsPopulated &&
languagesIsPopulated &&
importListsIsPopulated &&
indexerFlagsIsPopulated &&
systemStatusIsPopulated &&
translationsIsPopulated
);
@@ -86,6 +95,7 @@ const selectErrors = createSelector(
(state) => state.settings.qualityProfiles.error,
(state) => state.settings.languages.error,
(state) => state.settings.importLists.error,
(state) => state.settings.indexerFlags.error,
(state) => state.system.status.error,
(state) => state.app.translations.error,
(
@@ -96,6 +106,7 @@ const selectErrors = createSelector(
qualityProfilesError,
languagesError,
importListsError,
indexerFlagsError,
systemStatusError,
translationsError
) => {
@@ -107,6 +118,7 @@ const selectErrors = createSelector(
qualityProfilesError ||
languagesError ||
importListsError ||
indexerFlagsError ||
systemStatusError ||
translationsError
);
@@ -120,6 +132,7 @@ const selectErrors = createSelector(
qualityProfilesError,
languagesError,
importListsError,
indexerFlagsError,
systemStatusError,
translationsError
};
@@ -174,6 +187,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchImportLists() {
dispatch(fetchImportLists());
},
dispatchFetchIndexerFlags() {
dispatch(fetchIndexerFlags());
},
dispatchFetchUISettings() {
dispatch(fetchUISettings());
},
@@ -213,6 +229,7 @@ class PageConnector extends Component {
this.props.dispatchFetchQualityProfiles();
this.props.dispatchFetchLanguages();
this.props.dispatchFetchImportLists();
this.props.dispatchFetchIndexerFlags();
this.props.dispatchFetchUISettings();
this.props.dispatchFetchStatus();
this.props.dispatchFetchTranslations();
@@ -238,6 +255,7 @@ class PageConnector extends Component {
dispatchFetchQualityProfiles,
dispatchFetchLanguages,
dispatchFetchImportLists,
dispatchFetchIndexerFlags,
dispatchFetchUISettings,
dispatchFetchStatus,
dispatchFetchTranslations,
@@ -278,6 +296,7 @@ PageConnector.propTypes = {
dispatchFetchQualityProfiles: PropTypes.func.isRequired,
dispatchFetchLanguages: PropTypes.func.isRequired,
dispatchFetchImportLists: PropTypes.func.isRequired,
dispatchFetchIndexerFlags: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired,
dispatchFetchStatus: PropTypes.func.isRequired,
dispatchFetchTranslations: PropTypes.func.isRequired,

View File

@@ -244,7 +244,7 @@ class SignalRConnector extends Component {
handleWantedCutoff = (body) => {
if (body.action === 'updated') {
this.props.dispatchUpdateItem({
section: 'cutoffUnmet',
section: 'wanted.cutoffUnmet',
updateOnly: true,
...body.resource
});
@@ -254,7 +254,7 @@ class SignalRConnector extends Component {
handleWantedMissing = (body) => {
if (body.action === 'updated') {
this.props.dispatchUpdateItem({
section: 'missing',
section: 'wanted.missing',
updateOnly: true,
...body.resource
});

View File

@@ -15,6 +15,7 @@ class RelativeDateCell extends PureComponent {
className,
date,
includeSeconds,
includeTime,
showRelativeDates,
shortDateFormat,
longDateFormat,
@@ -39,7 +40,7 @@ class RelativeDateCell extends PureComponent {
title={formatDateTime(date, longDateFormat, timeFormat, { includeSeconds, includeRelativeDay: !showRelativeDates })}
{...otherProps}
>
{getRelativeDate(date, shortDateFormat, showRelativeDates, { timeFormat, includeSeconds, timeForToday: true })}
{getRelativeDate({ date, shortDateFormat, showRelativeDates, timeFormat, includeSeconds, includeTime, timeForToday: true })}
</Component>
);
}
@@ -49,6 +50,7 @@ RelativeDateCell.propTypes = {
className: PropTypes.string.isRequired,
date: PropTypes.string,
includeSeconds: PropTypes.bool.isRequired,
includeTime: PropTypes.bool.isRequired,
showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,
longDateFormat: PropTypes.string.isRequired,
@@ -60,6 +62,7 @@ RelativeDateCell.propTypes = {
RelativeDateCell.defaultProps = {
className: styles.cell,
includeSeconds: false,
includeTime: false,
component: TableRowCell
};

View File

@@ -25,14 +25,3 @@
font-family: 'Ubuntu Mono';
src: url('UbuntuMono-Regular.eot?#iefix&v=1.3.0') format('embedded-opentype'), url('UbuntuMono-Regular.woff?v=1.3.0') format('woff'), url('UbuntuMono-Regular.ttf?v=1.3.0') format('truetype');
}
/*
* text-security-disc
*/
@font-face {
font-weight: normal;
font-style: normal;
font-family: 'text-security-disc';
src: url('text-security-disc.woff?v=1.3.0') format('woff'), url('text-security-disc.ttf?v=1.3.0') format('truetype');
}

View File

@@ -15,5 +15,5 @@
"start_url": "../../../../",
"theme_color": "#3a3f51",
"background_color": "#3a3f51",
"display": "minimal-ui"
"display": "standalone"
}

View File

@@ -37,7 +37,7 @@ class EpisodeDetailsModal extends Component {
return (
<Modal
isOpen={isOpen}
size={sizes.EXTRA_LARGE}
size={sizes.EXTRA_EXTRA_LARGE}
closeOnBackgroundClick={this.state.closeOnBackgroundClick}
onModalClose={onModalClose}
>

View File

@@ -111,6 +111,8 @@ class EpisodeHistoryRow extends Component {
<RelativeDateCellConnector
date={date}
includeSeconds={true}
includeTime={true}
/>
<TableRowCell className={styles.actions}>

View File

@@ -0,0 +1,26 @@
import React from 'react';
import { useSelector } from 'react-redux';
import createIndexerFlagsSelector from 'Store/Selectors/createIndexerFlagsSelector';
interface IndexerFlagsProps {
indexerFlags: number;
}
function IndexerFlags({ indexerFlags = 0 }: IndexerFlagsProps) {
const allIndexerFlags = useSelector(createIndexerFlagsSelector);
const flags = allIndexerFlags.items.filter(
// eslint-disable-next-line no-bitwise
(item) => (indexerFlags & item.id) === item.id
);
return flags.length ? (
<ul>
{flags.map((flag, index) => {
return <li key={index}>{flag.name}</li>;
})}
</ul>
) : null;
}
export default IndexerFlags;

View File

@@ -17,6 +17,12 @@
width: 175px;
}
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 65px;
}
.actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css';

View File

@@ -2,6 +2,7 @@
// Please do not change this file!
interface CssExports {
'actions': string;
'customFormatScore': string;
'customFormats': string;
'languages': string;
'quality': string;

View File

@@ -11,6 +11,7 @@ import EpisodeLanguages from 'Episode/EpisodeLanguages';
import EpisodeQuality from 'Episode/EpisodeQuality';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import translate from 'Utilities/String/translate';
import MediaInfo from './MediaInfo';
import styles from './EpisodeFileRow.css';
@@ -55,6 +56,7 @@ class EpisodeFileRow extends Component {
languages,
quality,
customFormats,
customFormatScore,
qualityCutoffNotMet,
mediaInfo,
columns
@@ -127,6 +129,17 @@ class EpisodeFileRow extends Component {
);
}
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
{formatCustomFormatScore(customFormatScore, customFormats.length)}
</TableRowCell>
);
}
if (name === 'actions') {
return (
<TableRowCell
@@ -183,6 +196,7 @@ EpisodeFileRow.propTypes = {
quality: PropTypes.object.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
mediaInfo: PropTypes.object,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onDeleteEpisodeFile: PropTypes.func.isRequired

View File

@@ -1,10 +1,11 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { kinds, sizes } from 'Helpers/Props';
import { icons, kinds, sizes } from 'Helpers/Props';
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
import translate from 'Utilities/String/translate';
import EpisodeAiringConnector from './EpisodeAiringConnector';
@@ -42,6 +43,15 @@ const columns = [
isSortable: false,
isVisible: true
},
{
name: 'customFormatScore',
label: React.createElement(Icon, {
name: icons.SCORE,
title: () => translate('CustomFormatScore')
}),
isSortable: true,
isVisible: true
},
{
name: 'actions',
label: '',
@@ -94,6 +104,7 @@ class EpisodeSummary extends Component {
languages,
quality,
customFormats,
customFormatScore,
qualityCutoffNotMet,
onDeleteEpisodeFile
} = this.props;
@@ -143,6 +154,7 @@ class EpisodeSummary extends Component {
quality={quality}
qualityCutoffNotMet={qualityCutoffNotMet}
customFormats={customFormats}
customFormatScore={customFormatScore}
mediaInfo={mediaInfo}
columns={columns}
onDeleteEpisodeFile={onDeleteEpisodeFile}
@@ -179,6 +191,7 @@ EpisodeSummary.propTypes = {
quality: PropTypes.object,
qualityCutoffNotMet: PropTypes.bool,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
onDeleteEpisodeFile: PropTypes.func.isRequired
};

View File

@@ -31,7 +31,8 @@ function createMapStateToProps() {
languages,
quality,
qualityCutoffNotMet,
customFormats
customFormats,
customFormatScore
} = episodeFile;
return {
@@ -45,7 +46,8 @@ function createMapStateToProps() {
languages,
quality,
qualityCutoffNotMet,
customFormats
customFormats,
customFormatScore
};
}
);

View File

@@ -0,0 +1,17 @@
import ReleaseType from 'InteractiveImport/ReleaseType';
import translate from 'Utilities/String/translate';
export default function getReleaseTypeName(
releaseType?: ReleaseType
): string | null {
switch (releaseType) {
case 'singleEpisode':
return translate('SingleEpisode');
case 'multiEpisode':
return translate('MultiEpisode');
case 'seasonPack':
return translate('SeasonPack');
default:
return translate('Unknown');
}
}

View File

@@ -1,4 +1,5 @@
import ModelBase from 'App/ModelBase';
import ReleaseType from 'InteractiveImport/ReleaseType';
import Language from 'Language/Language';
import { QualityModel } from 'Quality/Quality';
import CustomFormat from 'typings/CustomFormat';
@@ -16,6 +17,8 @@ export interface EpisodeFile extends ModelBase {
languages: Language[];
quality: QualityModel;
customFormats: CustomFormat[];
indexerFlags: number;
releaseType: ReleaseType;
mediaInfo: MediaInfo;
qualityCutoffNotMet: boolean;
}

View File

@@ -0,0 +1,17 @@
import { useCallback, useState } from 'react';
export default function useModalOpenState(
initialState: boolean
): [boolean, () => void, () => void] {
const [isOpen, setOpen] = useState(initialState);
const setModalOpen = useCallback(() => {
setOpen(true);
}, [setOpen]);
const setModalClosed = useCallback(() => {
setOpen(false);
}, [setOpen]);
return [isOpen, setModalOpen, setModalClosed];
}

View File

@@ -41,6 +41,9 @@ import {
faChevronCircleUp as fasChevronCircleUp,
faCircle as fasCircle,
faCircleDown as fasCircleDown,
faCirclePause as fasCirclePause,
faCirclePlay as fasCirclePlay,
faCircleStop as fasCircleStop,
faCloud as fasCloud,
faCloudDownloadAlt as fasCloudDownloadAlt,
faCog as fasCog,
@@ -55,9 +58,11 @@ import {
faEye as fasEye,
faFastBackward as fasFastBackward,
faFastForward as fasFastForward,
faFileCircleQuestion as fasFileCircleQuestion,
faFileExport as fasFileExport,
faFileInvoice as farFileInvoice,
faFilter as fasFilter,
faFlag as fasFlag,
faFolderOpen as fasFolderOpen,
faForward as fasForward,
faHeart as fasHeart,
@@ -146,7 +151,11 @@ export const EXPORT = fasFileExport;
export const EXTERNAL_LINK = fasExternalLinkAlt;
export const FATAL = fasTimesCircle;
export const FILE = farFile;
export const FILE_MISSING = fasFileCircleQuestion;
export const FILTER = fasFilter;
export const FINALE_SEASON = fasCirclePause;
export const FINALE_SERIES = fasCircleStop;
export const FLAG = fasFlag;
export const FOOTNOTE = fasAsterisk;
export const FOLDER = farFolder;
export const FOLDER_OPEN = fasFolderOpen;
@@ -178,6 +187,7 @@ export const PARENT = fasLevelUpAlt;
export const PARSE = fasCalculator;
export const PAUSED = fasPause;
export const PENDING = farClock;
export const PREMIERE = fasCirclePlay;
export const PROFILE = fasUser;
export const POSTER = fasTh;
export const QUEUED = fasCloud;

View File

@@ -12,10 +12,12 @@ export const PASSWORD = 'password';
export const PATH = 'path';
export const QUALITY_PROFILE_SELECT = 'qualityProfileSelect';
export const INDEXER_SELECT = 'indexerSelect';
export const INDEXER_FLAGS_SELECT = 'indexerFlagsSelect';
export const LANGUAGE_SELECT = 'languageSelect';
export const DOWNLOAD_CLIENT_SELECT = 'downloadClientSelect';
export const ROOT_FOLDER_SELECT = 'rootFolderSelect';
export const SELECT = 'select';
export const SERIES_TAG = 'seriesTag';
export const DYNAMIC_SELECT = 'dynamicSelect';
export const SERIES_TYPE_SELECT = 'seriesTypeSelect';
export const TAG = 'tag';
@@ -44,6 +46,7 @@ export const all = [
ROOT_FOLDER_SELECT,
LANGUAGE_SELECT,
SELECT,
SERIES_TAG,
DYNAMIC_SELECT,
SERIES_TYPE_SELECT,
TAG,

View File

@@ -3,5 +3,5 @@ export const SMALL = 'small';
export const MEDIUM = 'medium';
export const LARGE = 'large';
export const EXTRA_LARGE = 'extraLarge';
export const all = [EXTRA_SMALL, SMALL, MEDIUM, LARGE, EXTRA_LARGE];
export const EXTRA_EXTRA_LARGE = 'extraExtraLarge';
export const all = [EXTRA_SMALL, SMALL, MEDIUM, LARGE, EXTRA_LARGE, EXTRA_EXTRA_LARGE];

View File

@@ -77,7 +77,7 @@ function InteractiveImportSelectFolderModalContent(
dispatch(
executeCommand({
name: commandNames.DOWNLOADED_EPSIODES_SCAN,
name: commandNames.DOWNLOADED_EPISODES_SCAN,
path: folder,
})
);

View File

@@ -0,0 +1,34 @@
import React from 'react';
import Modal from 'Components/Modal/Modal';
import SelectIndexerFlagsModalContent from './SelectIndexerFlagsModalContent';
interface SelectIndexerFlagsModalProps {
isOpen: boolean;
indexerFlags: number;
modalTitle: string;
onIndexerFlagsSelect(indexerFlags: number): void;
onModalClose(): void;
}
function SelectIndexerFlagsModal(props: SelectIndexerFlagsModalProps) {
const {
isOpen,
indexerFlags,
modalTitle,
onIndexerFlagsSelect,
onModalClose,
} = props;
return (
<Modal isOpen={isOpen} onModalClose={onModalClose}>
<SelectIndexerFlagsModalContent
indexerFlags={indexerFlags}
modalTitle={modalTitle}
onIndexerFlagsSelect={onIndexerFlagsSelect}
onModalClose={onModalClose}
/>
</Modal>
);
}
export default SelectIndexerFlagsModal;

View File

@@ -0,0 +1,7 @@
.modalBody {
composes: modalBody from '~Components/Modal/ModalBody.css';
display: flex;
flex: 1 1 auto;
flex-direction: column;
}

View File

@@ -0,0 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'modalBody': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,75 @@
import React, { useCallback, useState } 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, scrollDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './SelectIndexerFlagsModalContent.css';
interface SelectIndexerFlagsModalContentProps {
indexerFlags: number;
modalTitle: string;
onIndexerFlagsSelect(indexerFlags: number): void;
onModalClose(): void;
}
function SelectIndexerFlagsModalContent(
props: SelectIndexerFlagsModalContentProps
) {
const { modalTitle, onIndexerFlagsSelect, onModalClose } = props;
const [indexerFlags, setIndexerFlags] = useState(props.indexerFlags);
const onIndexerFlagsChange = useCallback(
({ value }: { value: number }) => {
setIndexerFlags(value);
},
[setIndexerFlags]
);
const onIndexerFlagsSelectWrapper = useCallback(() => {
onIndexerFlagsSelect(indexerFlags);
}, [indexerFlags, onIndexerFlagsSelect]);
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('SetIndexerFlagsModalTitle', { modalTitle })}
</ModalHeader>
<ModalBody
className={styles.modalBody}
scrollDirection={scrollDirections.NONE}
>
<Form>
<FormGroup>
<FormLabel>{translate('IndexerFlags')}</FormLabel>
<FormInputGroup
type={inputTypes.INDEXER_FLAGS_SELECT}
name="indexerFlags"
indexerFlags={indexerFlags}
autoFocus={true}
onChange={onIndexerFlagsChange}
/>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.SUCCESS} onPress={onIndexerFlagsSelectWrapper}>
{translate('SetIndexerFlags')}
</Button>
</ModalFooter>
</ModalContent>
);
}
export default SelectIndexerFlagsModalContent;

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