1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-03-14 15:44:53 -04:00

Compare commits

...

972 Commits

Author SHA1 Message Date
bakerboy448
65aeb19486 Improve Custom Format compare logging
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
2023-12-28 15:35:04 -05:00
Weblate
f9d9754220 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Aitzol Garmendia <aitzolgarmendia@gmail.com>
Co-authored-by: Dimitri <dimitridroeck@gmail.com>
Co-authored-by: Koch Norbert <kochnorbert@icloud.com>
Co-authored-by: Nicola <nicola.neri@gmail.com>
Co-authored-by: Pietro Ribeiro <xxb1exuv6@mozmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: chrizl <chrizl@gmail.com>
Co-authored-by: resi23 <x-resistant-x@gmx.de>
Co-authored-by: slammingdeath <sebastianbrudny97@gmail.com>
Co-authored-by: ηg <jonas.konrath@icloud.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/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/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt/
Translation: Servarr/Sonarr
2023-12-28 12:34:30 -08:00
Bogdan
e291834393 Fixed: Bump media info revision for DV HDR10Plus 2023-12-18 22:54:54 -08:00
Weblate
8ff6354d44 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Andrés Reyes Monge <armonge@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Menno Liefstingh <mennoliefstingh@gmail.com>
Co-authored-by: Michael Schönenberger <muchi94@gmail.com>
Co-authored-by: VisoTC <szlytlyt@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
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/nl/
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
2023-12-18 22:54:40 -08:00
Mark McDowall
5a3bc49392 Fixed: Imported episodes updating on Calendar
Closes #6240
2023-12-14 17:27:53 -08:00
Bogdan
0cd5bb50bd Fixed: Undefined statistics and season folder column width on series index 2023-12-14 20:25:36 -05:00
nuxen
e4ec065386 New: Parse 'E.N.D' Release Group 2023-12-14 20:24:48 -05:00
Fossil
e7224832cf Updated NZB Finder categories and removed OZnzb 2023-12-14 20:24:17 -05:00
Agneev Mukherjee
da9a60691f Enable browser navigation buttons for PWA 2023-12-14 20:24:09 -05:00
Bogdan
848c03f16a New: Support for DV HDR10Plus from media info
Co-authored-by: Chad A Simmons <chad.simmons@member.fsf.org>
2023-12-14 20:23:54 -05:00
Bogdan
96cb7c4d5f Fixed: Handle query limit error and add rate limit for BroadcastheNet
Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-12-14 20:23:07 -05:00
Stevie Robinson
aa9d25211f Hide ratings on series page if non existent 2023-12-14 20:22:34 -05:00
Weblate
c9a8d32042 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Appoxo <appoxo@appoxo.de>
Co-authored-by: Augusto Poletti <augustpolet@gmail.com>
Co-authored-by: Charlie <zola@zipmail.pw>
Co-authored-by: David Molero <contact@dolvem.com>
Co-authored-by: Dimitri <dimitridroeck@gmail.com>
Co-authored-by: Dominika Matějková <dominika.matejkova@outlook.cz>
Co-authored-by: Hajiroxx <luypanda@163.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jurriaan Den Toonder <jur.den.toonder@gmail.com>
Co-authored-by: Patatra <patrice.chevreau@gmail.com>
Co-authored-by: ROSERAT Ugo <roserat.ugo@gmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: SHUAI.W <x@ousui.org>
Co-authored-by: VisoTC <szlytlyt@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: liimee <git.taaa@fedora.email>
Co-authored-by: ndqnnwg <andydq@foxmail.com>
Co-authored-by: resi23 <x-resistant-x@gmx.de>
Co-authored-by: 米大饭 <1246333567@qq.com>
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/es/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/lv/
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/zh_CN/
Translation: Servarr/Sonarr
2023-12-14 17:22:15 -08:00
Qstick
97ee24507f Fixed: Correctly handle Migration when PG Host has ".db" 2023-12-11 16:43:03 -08:00
Bogdan
4bb9dc78a7 Add missing translation key MonitorNewItems 2023-12-11 16:42:48 -08:00
Bogdan
5e61b413b7 Fix filter type for series' network 2023-12-11 16:42:48 -08:00
Stevie Robinson
c6ad2396bb New: Remove Defunct Boxcar notifications 2023-11-25 15:23:00 -05:00
Stevie Robinson
75420d4a89 Fix missing translation key MonitorNone 2023-11-25 15:22:37 -05:00
Weblate
749d841d3a 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
2023-11-25 12:20:56 -08:00
Bogdan
4e048bf499 Wrap long lines in description lists 2023-11-19 21:32:06 -08:00
Mark McDowall
65cb1ccafd Fixed force saving provider triggering testing 2023-11-19 21:02:28 -08:00
Mark McDowall
d211887050 New: Add more exception release groups
Closes #6146
2023-11-19 20:45:37 -08:00
Mark McDowall
804a5921b3 Fixed: Saving indexer, download client, etc settings 2023-11-19 14:47:30 -08:00
Bogdan
87ecbf39c1 Fixed: Autotagging Genres are case insensitive 2023-11-19 17:47:27 -05:00
Stevie Robinson
174deb2509 Fix missing translation renames 2023-11-19 14:54:18 -05:00
Stevie Robinson
7464c09a46 Update translation keys to be Sonarr specific 2023-11-19 14:34:32 -05:00
Sonarr
0bfa7aed83 Automated API Docs update
ignore-downstream
2023-11-19 11:29:11 -08:00
Weblate
dd5a4ad0dc 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: Андрей <andryfly7@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ru/
Translation: Servarr/Sonarr
2023-11-19 11:28:59 -08:00
nexus671
4f57c088a1 Fixed: Plex RSS TMDb ID Lookup 2023-11-19 14:27:31 -05:00
Stevie Robinson
81f3c4bd55 Cleanup appName tokens 2023-11-19 13:56:28 -05:00
Bogdan
366d8a4e78 New: Confirmation before clearing blocklist 2023-11-19 10:55:28 -08:00
Mark McDowall
b248163df5 New: Require password confirmation when setting or changing password 2023-11-19 10:54:20 -08:00
Mark McDowall
d95660d3c7 Fixed: Disable SSL when migrating from v3
Closes #5979
2023-11-19 10:54:20 -08:00
Mark McDowall
c922cc5dc6 Always validate Custom Script path 2023-11-19 10:54:05 -08:00
Stevie Robinson
c3dcc542da Fix translation tokens 2023-11-19 13:53:30 -05:00
Jendrik Weise
b4ac495983 New: Custom import scripts can communicate information back 2023-11-19 13:52:37 -05:00
Mark McDowall
3541cd7ba8 Fixed: Blocklisting torrents from indexers that do not provide torrent hash
Closes #6108
2023-11-19 10:50:08 -08:00
Mark McDowall
5d86329c18 Last Season and Recent Episodes
New: Added option to only monitor recent episodes
Fixed: Last Season always monitors the whole season
Closes #6175
2023-11-19 10:49:53 -08:00
Qstick
ade40b72bc New: Option to control whether new seasons get monitored automatically
(cherry picked from commit b95a84f6612333d96fcdca083f9c39d96956f3f4)
Closes #5083
2023-11-19 10:49:53 -08:00
Bogdan
5328fb4ab3 New: Additional options for HDBits 2023-11-17 10:25:38 -05:00
Weblate
6ddfd99619 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: kevin8717 <871728422@qq.com>
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
2023-11-17 07:23:21 -08:00
Mark McDowall
812712e284 Rename 'ReturnUrl' to 'returnUrl' for forms auth redirection 2023-11-16 16:35:15 -08:00
Mark McDowall
c028222617 New: Support import list lookup by TMDb ID 2023-11-16 16:35:15 -08:00
Mark McDowall
71fd09f162 Don't retest unchanged providers
New: Don't retest connections, indexers, download clients, etc if re-saved with the exact same settings
Closes #6169
2023-11-16 16:35:15 -08:00
bakerboy448
c7d12066bf Fixed: Logging length of sample file
Closes #6180
2023-11-16 19:32:51 -05:00
Stevie Robinson
b76bf37371 Fixed: Custom Format Deletion confirmation message
Closes #6172
2023-11-16 19:31:44 -05:00
Bogdan
c3b4126d0c Fixed: Enforce validation warnings when testing providers 2023-11-16 16:30:43 -08:00
Stevie Robinson
f205cfabab Translate Indexers on the backend 2023-11-16 19:30:22 -05:00
Qstick
e68b13940d Bump ffprobe to 5.1.4 2023-11-11 11:17:08 -06:00
Stevie Robinson
48b12f5b00 Translate Download Clients on the backend 2023-11-10 11:44:04 -05:00
Bogdan
3d05913534 Fixed: Record status for notifications on tests 2023-11-10 11:43:25 -05:00
Mark McDowall
de23182d59 Don't store successful results for invalid providers 2023-11-09 17:08:34 -08:00
Mark McDowall
1e295d81f2 Fixed: Don't do title search when adding series from AniList import list
Closes #6140
2023-11-09 17:08:34 -08:00
Mark McDowall
0fe05fb3a9 Remove extraneous comments/code from migrations 2023-11-09 17:08:34 -08:00
Sonarr
24759b9060 Automated API Docs update
ignore-downstream
2023-11-09 19:52:43 -05:00
Weblate
eec862d3ff Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Baptiste Mongin <baptiste.mongin@gmail.com>
Co-authored-by: Francisco Cachado <franciscomcachado@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Javier Parada <jparada@gmail.com>
Co-authored-by: Nesego <nesego@gmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: Ruben Lourenco <ruben.lourenco01@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: bowsefather <husseinali39@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/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/tr/
Translation: Servarr/Sonarr
2023-11-09 19:52:27 -05:00
Stevie Robinson
2e51b8792d Fixed: Replacing 'appName' translation token 2023-11-09 19:00:54 -05:00
Bogdan
8c3a0ebaba Fixed: Showing already imported episodes as downloading in Series index 2023-11-09 18:59:29 -05:00
Xetera
10fbc4e25a New: Parsing of Turkish release names 2023-11-09 18:58:38 -05:00
Collin Heist
6432f310e7 New: Add TvdbId to Webhook Episode payload 2023-11-09 18:57:20 -05:00
Bogdan
e4b9086a7a New: Sort root folders by path 2023-11-09 18:57:04 -05:00
Bogdan
0496e728dc New: Resolve download client by name using 'downloadClient' for pushed releases 2023-11-09 18:56:35 -05:00
Zach Nedwich
0a2090237a Remove extraneous $1 from translation 2023-11-09 18:56:21 -05:00
Mark McDowall
165e3dbae8 New: Parsing for titles with multiple translated titles separated by '/'
Closes #6137
2023-10-29 16:27:30 -07:00
Mark McDowall
d484553b31 New: Support SABnzb's new format for sorters
Closes #6125
2023-10-29 14:19:47 -07:00
Mark McDowall
44d8dbaac8 Fixed: Blocking unknown indexers from pushed releases
Closes #5900
2023-10-29 12:14:02 -07:00
Mark McDowall
58d841c463 Fixed: Searching for series with XEM and TVDB mapping overrides 2023-10-29 11:23:31 -07:00
Bogdan
aa8659eecd Fix full disk releases regex for DVDs at the end of the title 2023-10-29 12:44:42 -04:00
Stevie Robinson
6e2162ebf4 New: Relative path as default Sort order on Manual Import 2023-10-28 17:56:18 -04:00
Weblate
fc0b42efd5 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: ID-86 <id86dev@gmail.com>
Co-authored-by: Jordy <prive@jordyhoebergen.nl>
Co-authored-by: LeDaFeEs <leonardo.fonseca85300@gmail.com>
Co-authored-by: Lizandra Candido da Silva <lizandra.c.s@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: bai0012 <baicongrui@gmail.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
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/zh_CN/
Translation: Servarr/Sonarr
2023-10-28 14:53:59 -07:00
Sonarr
b0cf36a431 Automated API Docs update
ignore-downstream
2023-10-28 14:52:51 -07:00
Bogdan
192eb7b62a New: Set busy timeout for SQLite 2023-10-28 17:52:30 -04:00
Bogdan
ba447c93e3 Fixed: DVDRip/DVDRemux being treated as full disk releases
Closes #6134
2023-10-28 17:52:13 -04:00
Stevie Robinson
a5506b09d2 New: Add [SEV] to release group exceptions
Closes #6118
2023-10-28 17:49:52 -04:00
Stevie Robinson
cd1d8a3ff0 fix translation token 2023-10-28 14:49:21 -07:00
Bogdan
36ca24e55a Allow 0 as valid value in QualityProfileExistsValidator 2023-10-28 14:48:39 -07:00
Bogdan
e53b7f8c94 New: Add Download Client validation for indexers 2023-10-28 14:48:39 -07:00
Bogdan
653aede0b7 Rename instances of Profile to QualityProfile 2023-10-28 14:48:39 -07:00
Bogdan
b06d5fb07b Use the correct property for quality profile on overview 2023-10-28 14:48:26 -07:00
Bogdan
f2cae4e2b2 Improve UI notice for delayed queue items 2023-10-28 14:47:50 -07:00
Bogdan
dc099a77ca Set proper default props for Queue details and status 2023-10-28 14:47:50 -07:00
Bogdan
a171132f98 Fix typo in visible for Queue size 2023-10-28 14:47:50 -07:00
Bogdan
43ed7730f0 Add default value for Queue count to avoid failed prop type 2023-10-28 14:47:50 -07:00
Bogdan
3a99c2781b Remove duplicated condition in history controller 2023-10-28 14:47:50 -07:00
Bogdan
910c403d84 Add translations to history and queue custom filters 2023-10-28 14:47:50 -07:00
Bogdan
6027041a4f Sort series by name in filter builder 2023-10-28 14:47:50 -07:00
Bogdan
e9bb1d52a7 Sort Custom Formats by name 2023-10-28 14:46:00 -07:00
Bogdan
b183743d9f Fixed: Avoid import loop for already imported episodes part of season packs
Closes #6075
2023-10-28 17:45:47 -04:00
Stevie Robinson
59ea524e0c Use Diacritical.Net library for TitleFirstCharacter token 2023-10-28 14:45:10 -07:00
Stevie Robinson
99b34c2065 Fix Localization test after translation changes 2023-10-27 09:53:05 -04:00
Qstick
5d90d68bf7 Fix translation for Search for Missing option 2023-10-20 22:14:04 -05:00
Weblate
b5e2b32915 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Daniel Suárez Bobes <danielsbobes@gmail.com>
Co-authored-by: DavidHenryThoreau <sorau@protonmail.com>
Co-authored-by: Dlgeri123 <bornemiszageri@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ruben Lourenco <ruben.lourenco01@gmail.com>
Co-authored-by: Timo <Tclemens@live.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: bai0012 <baicongrui@gmail.com>
Co-authored-by: jianl <jianjianfengyun@126.com>
Co-authored-by: 宿命 <331874545@qq.com>
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/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/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2023-10-20 19:29:48 -05:00
Daniel Martin Gonzalez
a131c88d5f New: Add Watched filter type to Trakt User Import List 2023-10-17 02:58:05 -04:00
Stevie Robinson
03f5174a4b Fixed: Reduce font size for series title on series details
Closes #6087
2023-10-17 02:55:48 -04:00
Stevie Robinson
0219f84789 Fixed: Has Missing Season not applying false condition 2023-10-17 02:54:39 -04:00
Bogdan
e8a47b4d0b New: Support for IMDb ID in Plex Watchlist RSS
Closes #6105
2023-10-17 02:52:59 -04:00
Mark McDowall
2fe8f3084c New: History custom filters
Closes #2974
2023-10-16 23:52:04 -07:00
Mark McDowall
e357d17b18 New: Queue custom filters 2023-10-16 23:52:04 -07:00
Mark McDowall
fd789343b5 Cleanup Calendar custom filters 2023-10-16 23:52:04 -07:00
Mark McDowall
11f96c3104 Use named tokens for backend translations
Closes #6051
2023-10-17 02:51:00 -04:00
Bogdan
41ed300899 Fixed: Ignore case when cleansing announce URLs
Closes #6047
2023-10-17 02:50:23 -04:00
bakerboy448
7b31287fc4 Fixed: Re-run Removed Series health check after series is deleted 2023-10-17 02:50:08 -04:00
scampower3
ec8da1c7de New: Add "enddate" tag to Kodi/Jellyfin series metadata 2023-10-17 02:49:22 -04:00
Mark McDowall
076aaba908 Fixed: End year displayed on series details
Closes #6067
2023-10-10 06:58:16 -07:00
Mark McDowall
df2e867528 Fixed: Reject full DVD disk releases
Closes #5975
2023-10-10 06:58:16 -07:00
Stevie Robinson
81aaf00a4c New: Add additional CleanTitle tokens and re-order options
Closes #6066
2023-10-10 09:58:03 -04:00
Bogdan
3ade52fc90 Fixed: Wanted Missing showing Unmonitored episodes
Closes #6084
2023-10-10 09:56:35 -04:00
Sonarr
5bceacb30e Automated API Docs update
ignore-downstream
2023-10-09 22:15:38 -07:00
Mark McDowall
95b389a948 Fix previous airing test 2023-10-09 22:13:00 -07:00
Mark McDowall
78b39bd2fe Log executing health check
Towards #6076
2023-10-09 21:00:05 -07:00
Mark McDowall
4b9baddccd Fixed: Only use monitored episodes for previous/next airing
Closes #6068
2023-10-09 20:41:46 -07:00
Mark McDowall
87e0a7983a New: Download client option for redownloading failed releases from Interactive Search
Closes #5580
2023-10-09 20:41:46 -07:00
Mark McDowall
113b0864b8 New: Sort episodes on series details page
Closes #  4558
2023-10-09 20:41:46 -07:00
Mark McDowall
db15a03c1e New: Import List option to search for missing episodes
Close #5882
2023-10-09 20:41:45 -07:00
Bogdan
44eb729ccc Fixed: Avoid logging evaluations when not using any Remote Path Mappings 2023-10-09 20:40:33 -07:00
Bogdan
6de3e7c950 New: Auto tag based on series quality profile 2023-10-09 20:40:22 -07:00
Bogdan
a26df9e9af Prevent NullRef for cases when media covers have nullable urls 2023-10-09 20:40:13 -07:00
Stevie Robinson
8c07f0d3d1 New: Additional tooltips for icon buttons 2023-10-09 23:40:00 -04:00
Stevie Robinson
732c2fe12f Fixed: Parsing Spanish releases 2023-10-09 23:39:26 -04:00
Bogdan
4ffa1816bd Add status test all button for IndexerLongTermStatusCheck 2023-10-09 20:38:59 -07:00
Stevie Robinson
b3c691859a Fixed: Cleanup First Character in Title when using 'TitleFirstCharacter'
Closes #6055
2023-10-09 23:38:49 -04:00
Mark McDowall
bfaa7291e1 Paging params in API docs
Closes #6003
2023-10-09 23:37:31 -04:00
Weblate
9f3915d4ad Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Dimitri <dimitridroeck@gmail.com>
Co-authored-by: Florian <sephrat.flo@gmail.com>
Co-authored-by: Garkus98 <ivan12061998@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: He Zhu <zhuhe202@qq.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: blankhang <blankhang@gmail.com>
Co-authored-by: 宿命 <331874545@qq.com>
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/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/zh_CN/
Translation: Servarr/Sonarr
2023-10-09 20:37:07 -07:00
Mark McDowall
b4ef873cc3 Fixed: Treat season packs with volume as partial season packs 2023-09-30 11:59:18 -07:00
Stevie Robinson
33b87acabf Fixed: qBittorent history retention to allow at least 14 days seeding 2023-09-30 11:58:34 -07:00
Stevie Robinson
e611e6c1ed Add Translated + Sponsor Badges to README.md 2023-09-30 11:58:27 -07:00
Weblate
feee85957f Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: mr cmuc <github@nextcos.de>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nl/
Translation: Servarr/Sonarr
2023-09-30 11:58:18 -07:00
Mark McDowall
35365665cf Fixed: Completed downloads in Qbit missing import path 2023-09-27 12:06:30 -07:00
bakerboy448
583eb52ddc Fixed: Only apply remote path mappings for completed items in Qbit 2023-09-27 10:50:06 -04:00
Stevie Robinson
d7ca3490a8 New: Year custom filter in Series Index 2023-09-27 07:48:29 -07:00
Stevie Robinson
a3938d8e02 Fixed: SABnzbd history retention to allow at least 14 days
Closes #6044
2023-09-27 10:48:15 -04:00
Bogdan
3620ad2517 Fix typo for Romanian regex group
ignore-downstream
2023-09-27 07:47:38 -07:00
Bogdan
a1ea7accb3 Avoid returning null in static resource mapper Task 2023-09-27 07:47:30 -07:00
Weblate
0544011177 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Daghriry <mdaghriri@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jaspils <jasperkemper@gmail.com>
Co-authored-by: SKAL <sir_kalot@yahoo.it>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ar/
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/zh_CN/
Translation: Servarr/Sonarr
2023-09-27 07:47:19 -07:00
Bogdan
c7824bb593 Fixed: Skip parsing releases without title
Closes #6030
2023-09-19 00:05:28 -04:00
Bogdan
d8633b9688 Preserve the protocol for fanart images 2023-09-18 21:02:05 -07:00
Mark McDowall
07f816ffb1 Fixed: Pushed releases not being properly rejected 2023-09-18 20:59:06 -07:00
Weblate
11deefc51d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ro/
Translation: Servarr/Sonarr
2023-09-18 00:11:09 -07:00
Bogdan
a2f16bddfd Preserve the protocol in Series Image 2023-09-18 00:09:25 -07:00
Qstick
f2b0fc946e Fixed: Show correct error on unauthorized caps call 2023-09-18 00:09:12 -07:00
Stevie Robinson
7f2cd8a0e9 Add health check for dl clients removing completed downloads + enable for sab and qbit 2023-09-18 00:08:24 -07:00
Mark McDowall
5eb420bbe1 New: Don't treat 400 responses from Notifiarr as errors
Closes #5953
2023-09-17 23:56:17 -07:00
Mark McDowall
32e1ae2f64 Fixed: Don't allow quality profile to be created without all qualities
Closes #6005
2023-09-17 23:45:31 -07:00
Mark McDowall
5ff254b646 Fixed: Skip free space check only applies during import
Closes #5951
2023-09-17 23:27:44 -07:00
Mark McDowall
fa5bfc3742 New: Optional 'downloadClientId' for pushed releases
Closes #6024
2023-09-17 23:25:00 -07:00
Mark McDowall
9a1022386a Fixed: Don't try to create metadata images if source files doesn't exist
Closes #6015
2023-09-17 23:25:00 -07:00
Herve Lauwerier
a4ba3ea244 Multiple Translations updated by Weblate
Translation: Servarr/Sonarr
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
(cherry picked from commit aa8339e6c09182b65ed6e0497eb0fcf9a5abbea9)
2023-09-17 20:07:01 -05:00
Havok Dan
c034d50ff3 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.0% (1471 of 1485 strings)

Translation: Servarr/Sonarr
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
(cherry picked from commit 3bf0f8ad5b1b05596f1b04f8963be2c5a9da9493)
2023-09-17 19:55:58 -05:00
Bogdan
c1d9187bb6 Log exceptions for failed fetches in Custom and Sonarr import lists
Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-09-17 17:17:32 -07:00
Bogdan
82d586e701 Use await on reading the response content 2023-09-17 17:17:04 -07:00
Bogdan
ad1f185330 Use async requests for media cover proxy 2023-09-17 17:12:58 -07:00
Qstick
ddabe66262 Use variable for App name in translations 2023-09-17 17:12:29 -07:00
Bogdan
60f18249b0 Fixed: Ignore inaccessible mount points 2023-09-13 21:06:08 -04:00
Weblate
7593d4e370 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Akashi2020 <dieux02400@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: He Zhu <zhuhe202@qq.com>
Co-authored-by: Qstick <qstick@gmail.com>
Co-authored-by: Richard de Souza Leite <rs9010482@gmail.com>
Co-authored-by: Shiessis <shiessis@gmail.com>
Co-authored-by: Ulna <ulnasensei@proton.me>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: leotpp <yangdom_li@126.com>
Co-authored-by: volrod64 <sebsogamer@gmail.com>
Co-authored-by: 宿命 <331874545@qq.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/
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
2023-09-13 18:05:26 -07:00
Bogdan
026327e7a3 Add missing using directive in HealthCheckServiceFixture 2023-09-11 12:40:27 -07:00
Mark McDowall
0abb4ceb26 Fixed: More restrictive finale guessing 2023-09-10 15:25:15 -07:00
Mark McDowall
bb7b2808e2 Mock debouncer for testing 2023-09-10 15:25:15 -07:00
Mark McDowall
2a241294b5 Fixed: Parsing of multiple languages from Newznab/Torznab indexer releases
Closes #6004
2023-09-10 15:25:15 -07:00
Denis Gheorghescu
5f09f2b25f New: Pushcut notifications 2023-09-10 16:09:15 -04:00
Mark McDowall
c0e54773e2 Fixed: Duplicate notifications for failed health checks
Closes #4462
2023-09-10 13:07:57 -07:00
Mark McDowall
809788eb2e Map Clearlogo images to cover type 2023-09-10 13:05:41 -07:00
Mark McDowall
40a71d65ec Sonarr not Radarr 2023-09-08 07:34:22 -07:00
Mark McDowall
76f5b26322 Fixed: Windows Installer hanging on removing previous service 2023-09-07 22:00:39 -07:00
Bogdan
060be6177a Fixed: macOS version detection 2023-09-07 20:12:46 -04:00
Bogdan
1b3ff64cc5 Fixed: Calculating seed time for qBittorrent 2023-09-07 20:12:20 -04:00
Stevie Robinson
0128dca5ac Fix relative imports for Components and Utilities 2023-09-07 17:11:42 -07:00
Weblate
a63e787220 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: DavidJares <david.jares@me.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Kevin Orel Edry <techg9@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 宿命 <331874545@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/he/
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
2023-09-07 17:11:30 -07:00
Bogdan
447d8cfbb9 Migrate to merged proposals now included in babel/present-env
Bump core-js too.
2023-09-04 10:30:10 -07:00
Bogdan
828b8e0fe4 Bump dotnet to 6.0.21 2023-09-04 10:30:01 -07:00
Stevie Robinson
c39902e58d Fixed: TBA airing network label 2023-09-04 13:29:34 -04:00
Bogdan
229a4bba05 Use not allowed cursor for disabled select options 2023-09-04 13:29:03 -04:00
Stevie Robinson
3f0e8ce863 Translate Frontend Utilities 2023-09-04 13:28:46 -04:00
Mark McDowall
faecdc855f New: Server pushable health checks
Closes #4116
2023-09-01 17:10:07 -07:00
Mark McDowall
276352dda4 Fixed indexer copy translation 2023-09-01 14:36:16 -07:00
Stevie Robinson
e04f36186b translate frontend wanted 2023-09-01 14:36:15 -07:00
Weblate
a0c2d420c7 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: He Zhu <zhuhe202@qq.com>
Co-authored-by: monopolo11 <bernardorn21@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/zh_CN/
Translation: Servarr/Sonarr
2023-08-31 17:50:03 -07:00
Stevie Robinson
d31fcbb2df Translate Frontend Store 2023-08-31 20:49:38 -04:00
Bogdan
467ce70291 Fixed: Increase timeout when downloading updates 2023-08-31 20:49:24 -04:00
randomllama
b76de3987b New: Add Series Status to Kodi .nfo
Closes #5980
2023-08-31 20:48:56 -04:00
Bogdan
6394b3253a Fixed: Showing Grab ID in history details modal 2023-08-31 20:48:23 -04:00
owine
dbb07e2cf6 Add Database to Bug Report template 2023-08-31 17:47:47 -07:00
Stevie Robinson
4c72017412 Fixed: Fallback to English translations if invalid UI language in config 2023-08-31 20:47:38 -04:00
Stevie Robinson
c123596c68 Translate frontend series pages 2023-08-31 20:47:17 -04:00
Bogdan
33c52a7037 Fixed: User check in Authentication Required modal 2023-08-29 16:13:50 -04:00
Mark McDowall
610cc91689 NzbDrone -> Sonarr 2023-08-28 21:51:55 -07:00
Mark McDowall
08939f2fb4 Fixed: Auto Tag required not showing in the UI correctly
Closes #5970
2023-08-28 21:51:55 -07:00
Weblate
7180a002cf Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Albert <zuozl1992@foxmail.com>
Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: ChewyGlitter <lulu3dddsss@gmail.com>
Co-authored-by: DavidJares <david.jares@me.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: He Zhu <zhuhe202@qq.com>
Co-authored-by: Renan da Mota Ciciliato <renanciciliato@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: brokje1988 <brokje1988@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
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/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2023-08-28 21:51:28 -07:00
Bogdan
340740377e Improve messaging in Authentication Required modal
Co-authored-by: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2023-08-28 19:29:07 -07:00
Bogdan
87b3a305e9 Fixed: 'includeSeasonImages' parameter to get single series from API
Closes #5971
2023-08-28 19:28:56 -07:00
Bogdan
f521942301 Fix download tooltip in interactive search 2023-08-28 19:28:14 -07:00
Bogdan
2e9dbfd382 Return original token when missing from translation 2023-08-28 19:28:08 -07:00
Stevie Robinson
ce4ac75941 Fix missing translations and correct some keys 2023-08-28 19:27:47 -07:00
Bogdan
36c7c79b9e Remove duplicate Language interface 2023-08-28 19:27:27 -07:00
Stevie Robinson
936ef9f461 Add info box under health messages
Closes #5958
2023-08-28 19:27:15 -07:00
Bogdan
ec9b29e364 New: Add more information to Select Series Modal
Co-authored-by: Qstick <qstick@gmail.com>
2023-08-28 19:26:38 -07:00
Bogdan
dc6204d377 Fix translations and default values in Interactive Search 2023-08-28 19:26:15 -07:00
Bogdan
5a7f42a63e Prevent health checks warnings for disabled notifications 2023-08-22 18:54:47 -07:00
Weblate
2a9883ade0 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: AlexR-sf <omg.portal.supp@gmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Renan da Mota Ciciliato <renanciciliato@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: deepserket <deepserket@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
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/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ru/
Translation: Servarr/Sonarr
2023-08-22 18:54:33 -07:00
Qstick
7986488c6d Fixed: Ignore case when comparing torrent infohash 2023-08-20 15:25:50 -05:00
Mark McDowall
fc6ac3ddf1 Fixed: Allow Min/Max age to be the same for year auto tagging 2023-08-20 11:16:44 -07:00
Mark McDowall
7be22af865 New: Auto tag based on series status
Closes #5944
2023-08-20 11:16:44 -07:00
Weblate
c0d53671da Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: David Molero <contact@dolvem.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: matt <diabolino7@pm.me>
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/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2023-08-20 13:02:00 -05:00
Mark McDowall
5411863f6a Fixed: Unknown audio language appearing as 'root'
Closes #5602
2023-08-20 00:34:57 -07:00
Mark McDowall
8fbbe21d81 Fixed: Invalid audio language leading to UI error
Closes #5702
2023-08-20 00:34:57 -07:00
Mark McDowall
0274778679 Fixed: Don't reimport the same file from the same release unless grabbed again
Closes #5625
2023-08-20 00:34:57 -07:00
Stevie Robinson
866fbc7f09 Translate Frontend Organize + Rename modal
including changing SeasonNumber component to formatSeason function
2023-08-19 17:03:00 -07:00
Bogdan
0feee19146 New: Async HttpClient 2023-08-19 17:02:48 -07:00
Bogdan
78593f428a New: Use HTTP/2 in HttpClient 2023-08-19 17:02:48 -07:00
Stevie Robinson
be24fab897 tweak customformats check logic 2023-08-19 13:53:19 -07:00
Stevie Robinson
c14fd2b4a3 Translate Frontend Parse modal 2023-08-19 13:53:19 -07:00
Jendrik Weise
2166e4dce4 Prevent exception when renaming after script import 2023-08-19 13:50:33 -07:00
Sonarr
1273656c8e Automated API Docs update
ignore-downstream
2023-08-19 13:49:18 -07:00
Mark McDowall
b271b3b694 Fix tests for ImportListSyncService 2023-08-19 10:52:39 -07:00
Mark McDowall
311cd66fcd New: Show midseason and other finales in episode list
Closes #5719
2023-08-19 01:36:37 -07:00
Sonarr
aceaaa10e1 Automated API Docs update
ignore-downstream
2023-08-19 00:23:13 -07:00
Mark McDowall
7f5ddff568 Fixed: Allow decimals for Custom Format size
Closes #5809
2023-08-19 00:14:59 -07:00
Mark McDowall
566fae9d58 New: Success check mark on blue buttons is now white instead of green 2023-08-19 00:14:59 -07:00
Mark McDowall
7be4840f02 New: Less logging when no import lists are enabled
Closes #5927
2023-08-19 00:14:59 -07:00
Stevie Robinson
d8f3d7d3ea Add info box to Remote Path Mappings Settings 2023-08-19 01:33:57 -04:00
Stevie Robinson
1bcef1b4a5 Fix Typo in QualitySource Enum 2023-08-18 22:33:31 -07:00
Mark McDowall
b20e247feb New: Parse language tags from existing subtitles files
Closes #5890
2023-08-19 01:32:54 -04:00
Mark McDowall
d05cb40088 Fixed: Ignore IOException deleting download folder after import
Closes #5937
2023-08-18 17:11:55 -07:00
Mark McDowall
8aa872edf4 New: Status message when downloading metadata in qBittorrent
Closes #5940
2023-08-18 17:11:55 -07:00
Stevie Robinson
efca704388 Translate Frontend InteractiveSearch 2023-08-17 21:58:45 -07:00
Bogdan
78d4dee461 Replace docker detection for cgroup v2 2023-08-18 00:58:34 -04:00
Mark McDowall
d493f8762f Fixed: Hidden files being ignored 2023-08-17 21:21:46 -07:00
Mark McDowall
d5c6faaf45 Fixed: Files in releases that span multiple TVDB seasons not automatically imported
Closes #5920
2023-08-17 21:14:09 -07:00
Bogdan
cb27b05a6c Fix health link and add translations for notifications status 2023-08-14 19:44:54 -05:00
Qstick
c281a7818a Cleanup other provider status code 2023-08-13 23:36:03 -05:00
Qstick
e354580172 New: Notifications (Connect) Status 2023-08-13 23:36:03 -05:00
Stevie Robinson
060b66aa39 Add translations to frontend/InteractiveImport 2023-08-13 19:28:16 -04:00
Bogdan
16d95ea6bf New: Default name when adding providers 2023-08-13 19:27:59 -04:00
Xabis
465a584486 New: AniList Import List 2023-08-13 19:26:03 -04:00
Stevie Robinson
efd19b6a6d Translation fixes for delete confirmations 2023-08-13 17:05:17 -04:00
Stevie Robinson
e777b70184 Translate Frontend Components, Episode and Helpers 2023-08-13 17:04:18 -04:00
Stevie Robinson
074aa6f445 Translate Updated and Connection Lost Modals in frontend 2023-08-13 17:03:52 -04:00
Bogdan
cc538c4b2d Show warning when using the docker update mechanism 2023-08-13 17:03:18 -04:00
Weblate
6a0dc72808 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: David Molero <contact@dolvem.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: matt <diabolino7@pm.me>
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/fr/
Translation: Servarr/Sonarr
2023-08-13 13:40:09 -07:00
Qstick
3b3bb5971c Fixed: Tag details query broken for Postgres 2023-08-13 13:26:05 -05:00
Mark McDowall
2a7964bc16 New: Auto tag series based on Original Language
Closes #5908
2023-08-13 00:26:37 -07:00
Mark McDowall
c1442535b0 New: Parse episode numbers followed by '.5' as specials
Closes #5893
2023-08-12 23:37:37 -07:00
Stevie Robinson
6245e8a552 Revert translations on defaultProps for QueueStatus.js 2023-08-12 20:17:50 -07:00
Stevie Robinson
bf43453c04 Translate Calendar Frontend 2023-08-12 20:05:44 -07:00
Qstick
b1d12b8ee9 Correctly close connections in UnavailablePendingReleases housekeeper
Regression from PG
2023-08-12 20:59:21 -05:00
Weblate
c423d1e7f8 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Albert <zuozl1992@foxmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Ivan Mazzoli <dreadtank27@gmail.com>
Co-authored-by: Nir Israel Hen <nirisraelh@gmail.com>
Co-authored-by: PerOHaugstad <perohaugstad@gmail.com>
Co-authored-by: TrojanHorsePower <alaa_alahmad@outlook.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: byakurau <byakurau1@gmail.com>
Co-authored-by: jack-mil <mcrajajack@gmail.com>
Co-authored-by: matt <diabolino7@pm.me>
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/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/nl/
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/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
(cherry picked from commit 1e7233ca8f0fd611b9ed1441b71072269b9d5aa9)
2023-08-12 13:29:28 -05:00
Mark McDowall
9c7fab69fd Fix LocalizationService tests 2023-08-12 00:41:27 -07:00
Sonarr
5cc720184b Automated API Docs update
ignore-downstream
2023-08-12 00:35:05 -07:00
Qstick
c57ceac4de Added table identifier to OrderBy to avoid column ambiguity on joins
Co-Authored-By: Richard <1252123+kharenis@users.noreply.github.com>
2023-08-12 00:45:07 -05:00
Robin Dadswell
a13011aa49 New: Postgres Database Support
Co-Authored-By: Qstick <376117+Qstick@users.noreply.github.com>
2023-08-12 00:45:07 -05:00
Qstick
69ddd99eb8 New: Improve performance when adding multiple series at once from lists or import 2023-08-11 23:23:26 -05:00
Qstick
df6c89ea23 New: Improve performance of DeleteBadMediaCovers housekeeper 2023-08-11 23:23:26 -05:00
Bogdan
d8f314ff0e Add one minute back-off level for all providers 2023-08-12 00:19:27 -04:00
Stevie Robinson
901b6d2084 Fix RemoveHelpTextWarning > RemoveFromDownloadClientHelpTextWarning 2023-08-11 21:18:47 -07:00
Mark McDowall
1ae0dc81f7 New: Add additional logging when renaming extra files
Closes #5890
2023-08-09 17:42:09 -07:00
ttran913
6b533ef2f9 New: Season pack searching with 'Anime Standard Format Search' 2023-08-09 20:13:35 -04:00
Bogdan
77a4ba4925 Detect Docker when using control group v2 2023-08-09 19:48:52 -04:00
Bogdan
366b2b8b52 New: Show successful grabs in Interactive Search with green icon 2023-08-09 19:48:38 -04:00
Bogdan
51dc96cb6e Specify in the logs what indexer is lacking capabilities 2023-08-09 19:48:06 -04:00
Stevie Robinson
322836e2b3 Translate Activity pages 2023-08-09 16:47:49 -07:00
Stevie Robinson
02b0710814 Translate frontend/AddSeries 2023-08-09 16:47:42 -07:00
Bogdan
f6c05d4456 Fixed: Ensure failing providers are marked as failed when testing all 2023-08-09 16:47:29 -07:00
Mark McDowall
6103c023de Fixed: Allow Original Language in Custom Format
Closes #5897
2023-08-09 08:21:41 -07:00
Mark McDowall
5a7e34e291 Fixed: Don't block updates under docker unless configured in package_info 2023-08-08 17:35:13 -07:00
Mark McDowall
65323d5e87 Fixed: Allow Unknown Language in Custom Format
Closes #5886
2023-08-07 18:07:09 -07:00
Stevie Robinson
31fe942c96 Fix Anime Episode Format key 2023-08-06 10:20:58 -05:00
Qstick
03d361f553 Filter user issues from Sentry (#5859) 2023-08-05 13:35:50 -05:00
Stevie Robinson
f2c31e92ce Add Translations to Settings Pages 2023-08-04 10:09:10 -07:00
Sonarr
8008610d47 Automated API Docs update
ignore-downstream
2023-08-03 22:26:47 -07:00
Weblate
27e968be20 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: Magnus <magnus.fladvad@gmail.com>
Co-authored-by: Stjepan <stjepstjepanovic@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: stormaac <yxc.frank@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hr/
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/ro/
Translation: Servarr/Sonarr
2023-08-03 22:25:10 -07:00
Mark McDowall
e5aa858410 New: Ignore inaccessible files with getting files
Closes #5818
2023-08-03 22:20:25 -07:00
Mark McDowall
60714eb89a Fix agnostic path in test 2023-08-03 21:35:49 -07:00
Mark McDowall
63a911a9a5 Fix GetBestRootFolderPath tests 2023-08-03 20:12:33 -07:00
Mark McDowall
5f72178445 Fixed: UI loading when series or root folder path is for wrong OS 2023-08-03 17:55:55 -07:00
Mark McDowall
d581de00c9 Fixed: Duplicate searches when Anime Standard Format Search enabled on indexer and series has multiple aliases 2023-08-03 17:55:55 -07:00
Bogdan
377fce6fe1 New: Health check for indexers with invalid download client 2023-08-03 20:38:53 -04:00
Bogdan
551ea18caf Simplify column translations 2023-08-03 20:38:24 -04:00
Stevie Robinson
9188a9971b Update API docs description 2023-08-03 20:38:06 -04:00
Bogdan
5e1b46d2aa Move RootFolderAppState to root AppState 2023-08-03 17:37:43 -07:00
Qstick
45a72c7918 Fixed: Error trying to notify user when process not UserInteractive 2023-08-03 17:37:34 -07:00
Mark McDowall
b7a55daa61 Fixed: Parsing of anime season releases with year after season number 2023-08-03 16:36:07 -07:00
Bogdan
ab821ccba8 Remove unused how to apply tags translation 2023-08-01 17:15:26 -07:00
Bogdan
7893fdde10 Improve messaging for Interactive Search 2023-08-01 17:15:26 -07:00
Bogdan
e8855c312d Add label translations in columns 2023-08-01 17:15:26 -07:00
Bogdan
67dc898797 Fixed: Clear season search results when navigating to another page 2023-08-01 20:02:25 -04:00
Bogdan
a5aab810d7 Convert Root Folders to Typescript 2023-08-01 17:01:14 -07:00
Bogdan
8bd91bd86b New: Add Monitored specification to Auto Tagging 2023-08-01 16:54:40 -07:00
Bogdan
c69b5fc72a New: Add Year specification to Auto Tagging 2023-08-01 16:54:40 -07:00
Bogdan
97e96537f5 Fixed: Ensure validation for Auto Tagging specifications
Co-authored-by: Qstick <qstick@gmail.com>
2023-08-01 16:54:40 -07:00
Bogdan
cd0ea4ce66 Add translations to Auto Tagging
(cherry picked from commit 17a6683dbb7eb914b4732fc310044ec9baa3f141)
2023-08-01 16:54:40 -07:00
Jessica Nguyen
cac101bdee Fixed: Importing additional Anime Types from Simkl
Co-authored-by: iceypotato <nickyjedi@gmail.com>
2023-08-01 19:53:39 -04:00
Weblate
9218962e3c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Albert <zuozl1992@foxmail.com>
Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: SHUAI.W <x@ousui.org>
Co-authored-by: Thirrian <matthiaslantermann@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: aguillement <adrien.guillement@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fr/
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/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_CN/
Translation: Servarr/Sonarr
2023-07-30 13:49:38 -07:00
Bogdan
a57b35a196 Convert store selectors to Typescript 2023-07-30 11:01:50 -07:00
Bogdan
94c6b0fde3 Fixed: Release note text 2023-07-30 14:01:35 -04:00
Michon van Dooren
8e925ac76d Fixed: Include preferred size in quality definition reset 2023-07-30 12:45:50 -04:00
Sonarr
560779cc1e Automated API Docs update
ignore-downstream
2023-07-28 19:09:28 -07:00
Bogdan
b407eba612 Fixed: Ensure failing indexers are marked as failed when testing all 2023-07-28 19:09:06 -07:00
Jendrik Weise
ad0dc01cf7 New: Update matching series path in Jellyfin/Emby library
Closes #5826
2023-07-28 18:40:30 -07:00
Bogdan
aee8579d18 New: More translations for columns 2023-07-28 18:39:06 -07:00
Bogdan
cda9cf726a Fixed: Recalculate Custom Format Score in Manual Import 2023-07-28 18:38:15 -07:00
Bogdan
3937545e15 Rename formatPreferredWordScore to formatCustomFormatScore 2023-07-28 18:38:15 -07:00
Bogdan
ae3dd5730e Fixed: Check only enabled Jackett indexers for '/all' endpoint
Closes #5848
2023-07-28 18:37:21 -07:00
Stevie Robinson
e1c5533efa Extend InlineMarkdown to handle code blocks in backticks 2023-07-28 18:36:06 -07:00
Bogdan
38c717bcef Dedupe releases based on indexer priority 2023-07-28 18:35:50 -07:00
Bogdan
3d6cf24d7c Validation for Custom Format specifications
Co-authored-by: Qstick <qstick@gmail.com>
2023-07-28 18:35:27 -07:00
jack-mil
1a4403e0ab New: Improved Discord add/delete notifications
Closes #5372
2023-07-26 13:38:56 -04:00
Sonarr
14bea16aef Automated API Docs update
ignore-downstream
2023-07-22 17:15:35 -07:00
Weblate
3bcf832676 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/pt_BR/
Translation: Servarr/Sonarr
2023-07-22 17:15:25 -07:00
Bogdan
d9786887f3 Add support for deprecated values in field select options 2023-07-22 17:14:28 -07:00
Stevie Robinson
3c17260c72 New: Update naming examples 2023-07-22 20:13:05 -04:00
Jessica Nguyen
b779c92200 New: Simkl Anime List integration
Co-authored-by: iceypotato <nickyjedi@gmail.com>
Closes #5635
2023-07-22 20:11:22 -04:00
Bogdan
180153cd84 Fixed: Ensure Monitoring Options resets to No Change 2023-07-22 20:09:57 -04:00
Stevie Robinson
98cd933640 New: Add translation for IRC link 2023-07-22 20:08:11 -04:00
Bogdan
028152d732 New: Add hover background color to Series table 2023-07-22 20:07:20 -04:00
PearsonFlyer
d7025a98de New: Ability to skip redownload when marking an item as failed from Activity Queue 2023-07-22 17:03:16 -07:00
Bogdan
38f263931f Cache busting for CSS files 2023-07-22 16:54:06 -07:00
Sonarr
dee8820b1f Automated API Docs update
ignore-downstream
2023-07-19 18:35:32 -07:00
Weblate
bb67c30dd5 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Deamon1333 <deamon133@gmail.com>
Co-authored-by: Godwhitelight <godwhitelight1@gmail.com>
Co-authored-by: Guy Porat <guyporatmail@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Leliene <lhena.gardien@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: liimee <git.taaa@fedora.email>
Co-authored-by: 君禹渊 <taoxu2870@outlook.com>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
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/he/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/id/
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
2023-07-19 18:35:06 -07:00
Bogdan
5f90fdd998 Add missing translations for Reset Quality Definitions modal 2023-07-19 21:22:31 -04:00
Stevie Robinson
93e8ff0ac7 Translate System pages 2023-07-19 21:19:43 -04:00
bakerboy448
360d989cb0 New: Log when testing for matching Remote Path Mapping 2023-07-19 21:11:05 -04:00
Mark McDowall
6d53d2a153 Fixed: Translations for columns 2023-07-19 17:52:33 -07:00
Bogdan
622f820da9 Run API docs workflow on changes to Sonarr.Http 2023-07-19 13:28:45 -07:00
Mark McDowall
73c5ec1da4 Fixed: Improve translation loading 2023-07-18 20:20:27 -07:00
Mark McDowall
bb8fed94eb Fix chunk IDs and source map file names 2023-07-18 09:54:59 -07:00
Bogdan
87021fff43 Update translations for How To Apply Tags 2023-07-18 00:07:08 -04:00
Mark McDowall
3ba7e64cd0 Don't generate API docs for InitializeJson 2023-07-17 21:05:23 -07:00
jack-mil
972e140899 New: Show Custom Format score in Manual Import 2023-07-17 23:46:36 -04:00
Bogdan
5e19478266 Fixed: Error when selecting different Quality Profile 2023-07-17 23:45:46 -04:00
Bogdan
67234222e3 Fixed: Improve quality and episode info output in parse result 2023-07-17 20:43:52 -07:00
Bogdan
bc374f07ce Use 2 spaces indentation for ts/tsx files 2023-07-17 20:43:52 -07:00
Mark McDowall
f0cb5b81f1 UI loading improvements
Fixed: Caching for dynamically loaded JS files
Fixed: Incorrect caching of initialize.js
2023-07-17 20:37:31 -07:00
Mark McDowall
f62bc59a73 Fixed: Translating column names 2023-07-15 21:12:59 -07:00
Stevie Robinson
c206b92912 Translate sidebar strings 2023-07-15 17:37:31 -04:00
Mark McDowall
35e171f7b1 Fixed: Order of Discord grab notification fields 2023-07-15 14:34:43 -07:00
Sonarr
5b3b346b77 Automated API Docs update
ignore-downstream
2023-07-15 10:36:00 -07:00
Bogdan
d6aee683dc New: Show tooltips with Custom Formats in History and Queue 2023-07-15 10:29:47 -07:00
jack-mil
eadd0c4e10 New: Optionally show Custom Format Score for episodes on Series Details 2023-07-15 10:28:38 -07:00
Mark McDowall
ef6ff370ba Fixed: Translating static strings 2023-07-15 09:24:24 -07:00
Mark McDowall
c1f8c7b17b Use named keys for apply tags help text 2023-07-15 09:16:19 -07:00
Mark McDowall
dce6923b00 Fixed: Parsing of anime title that contains multiple 3-digit numbers
Closes #5801
2023-07-14 17:24:05 -07:00
Mark McDowall
ad2721dc55 Fixed: Ensure translations are fetched before loading app 2023-07-14 17:24:05 -07:00
Bogdan
3aa3ac90ed Mark empty bulk endpoints as not implemented 2023-07-11 20:10:20 -07:00
Bogdan
d1466ba589 Move ApplyTags to own file 2023-07-11 20:10:20 -07:00
Bogdan
0d3e9a2196 Prevent NullRef for empty ids in bulk endpoint 2023-07-11 20:10:20 -07:00
Bogdan
2693ada7de Add missing provider characteristics to bulk endpoint response 2023-07-11 20:10:20 -07:00
Bogdan
e641c57ad9 New: Add translations for managing bulk indexers, lists and clients 2023-07-11 20:10:20 -07:00
Bogdan
45336389e6 Fixed: Handling of no results from BTN searches 2023-07-11 20:13:07 -04:00
Jendrik Weise
e7bc145084 New: Option to disable images in Kodi Episode Metadata 2023-07-11 20:12:07 -04:00
Bogdan
dc302bfaa8 Fixed: Clearing parse testing 2023-07-11 20:10:30 -04:00
Bogdan
9854884ed3 Fixed: Queue not loading when it contains unmapped releases 2023-07-11 12:45:54 -04:00
Mark McDowall
c9e3890f73 Fixed: Remove 'Parse Testing' from sidebar 2023-07-11 07:51:03 -07:00
Weblate
e87f853199 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Kevin Orel Edry <techg9@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Tacit <1750630216@qq.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/he/
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
2023-07-10 22:05:57 -07:00
bakerboy448
9713c36960 New: Clarify path used in Kodi update logging 2023-07-11 01:05:03 -04:00
bakerboy448
d2be869d9c Import list logging improvements 2023-07-11 01:04:26 -04:00
Mark McDowall
12c3426c95 Fix circular dependency with ScriptImportDecider, TagService and DownloadClientFactory 2023-07-10 22:03:10 -07:00
Mark McDowall
85e2855981 New: Added UI for parsing release names
Closes #5263
2023-07-10 20:54:16 -07:00
Bogdan
a77ef187af Fixed: Anime standard format search on Nyaa 2023-07-10 23:52:27 -04:00
Qstick
f6ae9fd6c5 New: Download Client Tags
Closes #402
2023-07-10 23:51:14 -04:00
jack-mil
3a9182b6a6 New: Add Custom Format fields to Discord On Grab notifications
Closes #5769
2023-07-10 23:50:46 -04:00
Jendrik Weise
3f0268b79f New: Additional info passed in for Script Import and Custom Script 2023-07-10 23:49:49 -04:00
jack-mil
a6f2db9139 New: Custom Format Score column in queue
Closes #5780
2023-07-10 23:49:00 -04:00
Qstick
96b7aa6585 Fix error in epic fail handler if console input redirected
Eliminates an unhandled InvalidOperationException and loop causing thousands of sentry errors
2023-07-04 12:58:25 -05:00
Qstick
5638f9c0a1 New: Speed up API add by reworking SeriesExistsValidator 2023-07-03 02:05:35 -05:00
Qstick
51d6fd32dc New: Speed up Series Add by reworking SeriesPathValidator 2023-07-03 02:05:35 -05:00
Weblate
4304d80491 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: BeardedWatermelon <periklis.karantonis@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/el/
Translation: Servarr/Sonarr
2023-07-02 22:38:32 -07:00
Qstick
551edb9e65 Fixed: Allow restore to process backups up to ~500MB 2023-07-02 22:35:24 -07:00
Qstick
af8c67a24d Fixed: Correct typing for ImportListExclusions tvdbid column 2023-07-02 22:35:14 -07:00
Bogdan
b6f3bcb309 Add ContentSummary to HDBits requests 2023-07-02 22:34:45 -07:00
Bogdan
aa2b003167 Create overload for ToJson() with Formatting param 2023-07-02 22:34:45 -07:00
Mark McDowall
5c48049702 Fixed: Series added events being sent with series deleted title
Closes #5762
2023-06-27 12:31:24 -07:00
Bogdan
dd096e0fda Fixed: Invalid image URL if Series is missing background image 2023-06-26 18:23:18 -04:00
Weblate
bb952e5ddf Multiple Translations updated by Weblate
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jens <jensmahnke@me.com>
Co-authored-by: KHng0284 <giakhang021109@gmail.com>
Co-authored-by: MoowGlax <matthieu.derouet.pro@gmail.com>
Co-authored-by: Thijs Waalen <contact@thijswaalen.com>
Co-authored-by: Thodoris Kalatzis <teo.kal@hotmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: emacsdias <emacs.dias@gmail.com>
Co-authored-by: liimee <git.taaa@fedora.email>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: splifter <a.strahlke@gmail.com>
Co-authored-by: sutoramon <sutoramon@gmail.com>
Co-authored-by: ted09080037 <ted09080037@gmail.com>
Co-authored-by: Андрей <andryfly7@gmail.com>
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/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/id/
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/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/sonarr/zh_TW/
Translation: Servarr/Sonarr
2023-06-26 15:22:19 -07:00
Bogdan
6816767fad Allow array of string as value in EnhancedSelectInput 2023-06-26 15:18:15 -07:00
Bogdan
ee843259bc New: Improve empty list messaging 2023-06-26 18:18:03 -04:00
Sonarr
5184d995ca Automated API Docs update
ignore-downstream
2023-06-24 15:15:19 -05:00
Bogdan
377e5f7fc7 New: Search library by TheTVDB, TV Maze or IMDB IDs 2023-06-20 19:29:15 -07:00
Bogdan
0a05781aca Remove not implemented endpoints from API docs 2023-06-20 19:26:48 -07:00
Bogdan
82919a8ed1 Convert to 'using' declaration in Housekeeping Tasks 2023-06-20 19:26:21 -07:00
Bogdan
9af6d1b9d9 Close database connections in housekeeping tasks
Co-authored-by: ferencmarkizay <ferencmarkizay@gmail.com>
2023-06-20 19:26:21 -07:00
Bogdan
b48fe6e633 Prevent NullRef when deleting missing backups
(cherry picked from commit 0ff0fe2e68f3abf7b8e4d6bf0c1e9dee4eb68227)
2023-06-20 19:24:19 -07:00
Bogdan
e2f27e0c61 Fixed: Sorting queue by size 2023-06-20 19:16:54 -07:00
Mark McDowall
5601a94016 Add missing imports 2023-06-20 13:02:28 -07:00
Bogdan
1f785dd30d Show loading errors as Alerts (#5736)
New: Improved page loading errors
2023-06-16 10:49:08 -07:00
Bogdan
059a156f4a Fixed: Treat redirects as errors in Sonarr Import List 2023-06-13 21:03:48 -07:00
Bogdan
19b8fbe13b Require ApiKey for all actions in SonarrImport 2023-06-13 21:03:48 -07:00
Bogdan
2603138975 Update translations 2023-06-13 21:01:32 -07:00
Hayden
a6a61a016b Fixed: Limit Discord embed title length to 256 characters
Co-authored-by: HeyBanditoz <7574664+HeyBanditoz@users.noreply.github.com>
2023-06-13 23:59:51 -04:00
Qstick
11bd764a75 Fixed: Correctly handle 302 and 303 redirects in HttpClient
(cherry picked from commit ed7c5a937f4b50fcdf819e8fe347c8c0bc6bd2e7)
2023-06-13 20:58:30 -07:00
Bogdan
0e07d54ee7 Add HelpTextWarning support in FieldDefinition 2023-06-13 20:55:20 -07:00
Bogdan
0b87280335 Check only clients not in failure status in DownloadClientSortingCheck 2023-06-13 20:54:05 -07:00
Bogdan
e5ff4aafa3 Update cleansing rules for RSS TL feed and homedir for Mac 2023-06-13 20:53:20 -07:00
Stevie Robinson
9dc090e15e Update MoreInfo.js with new discord link 2023-06-13 20:52:11 -07:00
bakerboy448
8d8a16225f Fixed: Handle checkingResumeData state form qBittorrent 2023-06-13 23:50:59 -04:00
Qstick
18716a0051 Update Remote Path Mapping delete modal title 2023-06-12 15:24:06 -04:00
Qstick
a8d94773a1 Fixed: Filter series by Tvdb deleted status 2023-06-12 10:07:13 -04:00
Bogdan
dd31c913d2 Use more specific styling for kinds in ProgressBar 2023-06-09 15:00:19 -07:00
Zak Saunders
d44656bca1 New: Remove Rarbg Indexer due to site shutdown 2023-06-09 14:58:06 -07:00
bakerboy448
3b505d8734 New: Indexer Messaging and Error Improvements 2023-06-09 17:54:04 -04:00
Mark McDowall
d606144e00 New: Use major version for installed version on Windows
Closes #5710
2023-06-01 17:46:03 -07:00
Sonarr
474f5f29ca Automated API Docs update
ignore-downstream
2023-05-28 11:46:29 -07:00
Qstick
b050e1d2eb Faster tag view in UI for large libraries 2023-05-28 11:08:31 -07:00
Bogdan
48ee1158ad Fixed: Enforce validation warnings 2023-05-28 11:07:40 -07:00
Bogdan
7343616a47 Simplify ShouldHaveApiKey and HasErrors 2023-05-28 11:07:40 -07:00
Qstick
efab1b0793 Cleanup react warnings from manage modals 2023-05-28 08:37:39 -05:00
Qstick
593652a84a Fix priority input for provider manage edit modal 2023-05-28 08:37:39 -05:00
Bogdan
b06269544c Add minimum length as const in ApiKeyValidationCheck 2023-05-27 17:23:41 -07:00
Bogdan
bb97fbc23f Add missing wiki fragments to health checks 2023-05-27 17:23:41 -07:00
Qstick
560a9b63ca New: Translations support for Health Checks
(cherry picked from commit bfc036178487fe0b692f306a53f2a334cdf7f9d5)
2023-05-27 17:23:41 -07:00
Bogdan
a22f598b0c Minor improvements in health checks 2023-05-27 17:23:41 -07:00
Bogdan
86a7f7bd54 Deserialize asynchronously in LocalizationService 2023-05-27 17:23:41 -07:00
Bogdan
f90bef6934 Fix showing sorting values, add tooltips and translations to SeriesIndexPoster 2023-05-27 16:56:19 -07:00
Bogdan
12374f7f00 Use 'var' instead of explicit type 2023-05-27 16:55:16 -07:00
Bogdan
281add47de Inline 'out' variable declarations 2023-05-27 16:55:16 -07:00
Bogdan
909f2ded6b Standardize variable declaration 2023-05-27 16:55:16 -07:00
Bogdan
6b1e4ef819 Enforce rule IDE0005 on build 2023-05-27 19:53:49 -04:00
Matthew Strapp
8e771f95ad Fixed: Use relative paths instead of absolute paths for webmanifest 2023-05-27 19:34:48 -04:00
Qstick
73ccab53d5 New: Bulk Manage Import Lists, Indexers, Clients 2023-05-27 18:00:49 -05:00
Qstick
5fd543cf8c Ignore API doc commits downstream
ignore-downstream
2023-05-27 16:51:39 -05:00
bakerboy448
e9bbb0b9ba Fixed: Webhook notification error messages 2023-05-26 19:45:53 -07:00
bakerboy448
b510201b43 Fixed: A really important spelling mistake 2023-05-26 19:44:32 -07:00
Mark McDowall
e273f16c39 Fixed: Strip additional domains from release names 2023-05-26 19:36:50 -07:00
Mark McDowall
49fd9c4462 New: Filter SABnzbd queue by category 2023-05-26 17:14:02 -07:00
Mark McDowall
59f2e5b65d Fixed: Don't log handled exceptions in API
Closes #5690
2023-05-26 17:14:02 -07:00
Bogdan
af55e322f1 Fixed: Sorting search releases by language 2023-05-26 16:19:42 -04:00
Sonarr
3ac5edeb09 Automated API Docs update 2023-05-25 10:34:05 -07:00
Mark McDowall
f05405fe1c Fixed: Don't rollback file move if destination already exists
Towards #5610
2023-05-22 22:11:17 -07:00
JeWe37
9f1e215120 New: Option to Import via Script
Closes #791
2023-05-22 23:36:17 -04:00
Bogdan
365a6e77a6 Use project name as relative path in builds
(cherry picked from commit fb908e8e1969e633a50ca000c767a998427363b2)
2023-05-22 20:33:57 -07:00
Mark McDowall
349f7cf4c9 Rename Clearart to Clearlogo, use png for Clearlogo 2023-05-22 10:32:03 -07:00
Mark McDowall
aecc8295c8 Fixed: Don't download unknown artwork 2023-05-22 09:00:36 -07:00
Stevie Robinson
f2ddd4757c Fixed: Parsing Vyndros as release group 2023-05-21 17:05:48 -04:00
Stevie Robinson
bf90c3cbdd New: refresh only selected or filtered series
Closes #5611
2023-05-21 17:05:30 -04:00
Bogdan
a117001de6 New: Improve validation messages 2023-05-21 09:24:59 -07:00
Bogdan
6118afa339 Minor CS improvements in NzbDroneValidation 2023-05-21 09:24:59 -07:00
S0me6uy
59dd3b1127 New: Signal Notifications
Co-authored-by: Your Name <yohoho@testsmsd.com>
2023-05-21 12:22:00 -04:00
Bogdan
de3bfb7c5a Fix spelling "Use languages from Torznab/Newznab attributes if given" 2023-05-21 12:05:18 -04:00
Bogdan
90a9ecbaac Fix tests in IndexerServiceFixture 2023-05-21 09:03:51 -07:00
Bogdan
d492f28645 Fix tests in TorrentDownloadStationFixture 2023-05-21 09:03:51 -07:00
Mark McDowall
d743a8f7e9 Fixed tests in DownloadServiceFixture 2023-05-20 21:15:10 -07:00
Mark McDowall
3cd33d3f44 Fixed: Don't move seeding torrents in Synology Download Station
Closes #3997
2023-05-20 20:56:02 -07:00
Mark McDowall
b38c1255dc Fixed: Don't retry grabbing the same release if download client is unavailable
Closes #3116
2023-05-20 20:51:24 -07:00
Mark McDowall
f946d78153 Fixed: Exception when request to SABnzbd times out 2023-05-20 16:59:06 -07:00
Qstick
9c5a07f62a New: Use languages from Torznab/Newznab attributes if given
Closes #5654
2023-05-20 16:31:30 -07:00
Mark McDowall
7238100145 Add FindByName to IsoLanguage 2023-05-20 16:24:38 -07:00
Mark McDowall
4fe79e9a4e Fixed: Parsing of some additional Chinese anime releases
Closes #5667
2023-05-20 15:15:48 -07:00
Bogdan
2016f11b1c New: Show current tags for Connections 2023-05-19 18:55:44 -04:00
Bogdan
9bdc618366 Fixed: Use indexer errors from response if Content-Type is XML before processing response 2023-05-18 17:32:24 -07:00
Sonarr
4fecd6ed89 Automated API Docs update 2023-05-18 16:43:35 -07:00
Qstick
94a8ef6304 New: Advanced settings toggle in indexer edit/add modal
(cherry picked from commit a570fd2a8f138fb89c5b0ae43ddb7919f6bf26e3)
2023-05-18 16:43:08 -07:00
Qstick
de08d37267 New: Add path mapping for partial library updates in Plex Server Notifications
(cherry picked from commit 24206ad0a3095c4bf5c860af516d8543bd6525d6)
2023-05-18 16:41:06 -07:00
Bogdan
ef0b91b45b Add forceSave to the OpenAPI docs 2023-05-18 16:37:34 -07:00
Bogdan
b5050d02d6 Fixed: Log name of mount point failure 2023-05-17 20:12:06 -04:00
Bogdan
3ece1533d8 Fix checking for SameTorrent when the indexer is null 2023-05-17 17:00:27 -07:00
Bogdan
f32a3cd41c Sort tags by label
(cherry picked from commit bb1ebda753157a96154095e0c1e32703f2a68d1a)

Co-authored-by: Mark McDowall <markus.mcd5@gmail.com>
2023-05-17 16:58:15 -07:00
Sonarr
14411f1f15 Automated API Docs update 2023-05-14 21:23:46 -07:00
Bogdan
3508cb63dc Update UI dependencies 2023-05-14 21:11:16 -07:00
Bogdan
3840e97da2 Update openapi.json with Github Actions 2023-05-14 21:09:03 -07:00
Bogdan
2fecd28001 Fix validation for boolean query parameters 2023-05-14 21:09:03 -07:00
Bogdan
5de7322d60 Add Pull Request Labeler 2023-05-14 10:06:48 -07:00
Bogdan
498722b240 Fixed: Prevent unknown settings implementation from failing to deserialize
(cherry picked from commit 0e2cc7851f556e928e52bb2886c7d60c13b0741e)

Log removal of invalid definitions as warnings

(cherry picked from commit 3d61719a2cc9c87ac3c92b5358bb5034aed4c2ff)
2023-05-14 10:01:55 -07:00
Qstick
eacb619cfb Fixed: Avoid error in CF calculation when release is unparsable 2023-05-13 15:40:27 -05:00
Mark McDowall
711331526b Add missing wiki hashes to health checks 2023-05-12 16:56:00 -07:00
Qstick
ed22bb719d DownloadClientRootFolderCheck Improvements 2023-05-12 16:55:56 -07:00
Qstick
1f20bc63c6 RemotePathMappingCheck Improvements 2023-05-12 16:55:44 -07:00
Qstick
202449c40c Fixed: Provider health checks persist after add until next scheduled check 2023-05-12 16:55:35 -07:00
Mark McDowall
62b948b24c New: Calendar filtering by tags
Closes #5476
2023-05-11 22:36:26 -07:00
Mark McDowall
7c0d344437 New: Calendar month view will scroll to today on load and press
Closes #5574
2023-05-11 20:58:12 -07:00
Mark McDowall
c7d39579b4 New: Log additional information when processing completed torrents from rTorrent
Closes #5638
2023-05-11 17:35:40 -07:00
Bogdan
3af7a6df7d Remove unused field userAgentBuilder in HttpClient 2023-05-10 21:10:36 -07:00
Bogdan
477bfb7835 Minor cleanup in RssImport 2023-05-10 21:10:09 -07:00
Bogdan
c6b543e072 Remove unused imports 2023-05-10 21:08:13 -07:00
Bogdan
f93a016be1 Remove empty constructors 2023-05-10 21:08:13 -07:00
Mark McDowall
f63e060ac4 Use QualityProfile instead of any 2023-05-10 21:01:52 -07:00
Mark McDowall
e882d0f385 Fixed CompletedDownloadService.Process tests 2023-05-09 13:11:12 -07:00
Mark McDowall
0e6f858e65 Fixed tests 2023-05-09 10:03:53 -07:00
Mark McDowall
f56d504816 Fixed: Incorrect event types for interactive import required notifications 2023-05-09 08:09:27 -07:00
Stickie
5ec282750b New: Notifications when Manual Interaction is required for importing
Closes #5193
2023-05-08 16:35:03 -07:00
ta264
63654b99f2 Fixed: Don't buffer update package to memory when downloading 2023-05-08 16:35:03 -07:00
Bogdan
9325140b90 API key improvements
Fixed: Special characters in API key
New: Add heathcheck for API Key
2023-05-07 20:56:26 -07:00
Mark McDowall
eaa4a358e8 Why rename many files when few file do trick 2023-05-07 20:25:55 -07:00
bakerboy448
e72431144b New: Improved maintenance release wording 2023-05-07 18:58:56 -07:00
Mark McDowall
993c69530e GracePeriod not Graceperiod 2023-05-07 18:57:55 -07:00
The Dark
5fdc8514da New: On Health Restored notification
Closes #4262
2023-05-07 18:57:14 -07:00
Bogdan
fbf79c6639 Downgrade rimraf to v4 2023-05-07 18:50:11 -07:00
Bogdan
76f93c8415 Fixed: Ensure indexer errors are handled before processing response 2023-05-07 10:29:51 -07:00
Bogdan
8f482c534f Fixed: custom script error when importing some downloads
Co-authored-by: Qstick <376117+Qstick@users.noreply.github.com>

Closes #5617
2023-05-07 10:23:47 -07:00
Benjamin Staneck
6a49f3989a Fix stylelint runs by pinning string-width to a non ESM-only version
Add `inset` to stylelintrc
2023-05-07 10:20:08 -07:00
Benjamin Staneck
d79f42351f Remove unused babel plugins and fix build with profiling 2023-05-07 10:20:08 -07:00
Benjamin Staneck
4aba540b89 Update all relevant dev tool deps
Delete esformatter

Address lint failures

Delete unknown component property

remove deprecated stylelint rules

Address stylelint violation

Update rimraf
2023-05-07 10:20:08 -07:00
Benjamin Staneck
9ebd2f96ad Add VSCode extension recommendations
To make it easier for new contributors, suggest extensions for the tools we use
2023-05-07 10:20:08 -07:00
Benjamin Staneck
e12c679cd8 Move vscode settings to the frontend folder
Since it applies to all of frontend, I think it makes more sense to have it here instead of src
2023-05-07 10:20:08 -07:00
Benjamin Staneck
0da89478cc Delete various old config files
Delete `jsconfig.json`

This file actually did nothing since we have a `tsconfig.json`. Behavior does not change since `checkJs` is `false` in both.

Delete `.jsbeautifyrc`

Was not used from what I could tell and we have a ESFormatter config file as well and that is basically the successor.

Delete `.csscomb.json`

Was not used from what I could tell, also the project seems dead, last publish 4 years ago. Also we have stylelint in place that covers CSS.
2023-05-07 10:20:08 -07:00
Bogdan
a95317446c Log invalid config file exceptions
(cherry picked from commit e1d0e2c79975a10c12fc8551f5dcd4a79f1c94e7)
2023-05-07 10:18:00 -07:00
Qstick
3a6c078b30 Fixed: Catch InvalidDataException during initial config to prevent boot loop
(cherry picked from commit 9862584611f29ac3f16e0c6ef0afb183ff3f0588)
2023-05-07 10:18:00 -07:00
Mark McDowall
77efc4cc40 Fixed: Timeout when getting root folder details 2023-05-07 09:52:35 -07:00
Mark McDowall
453891e620 New: Only add version header for API requests
Closes #5601
2023-05-06 22:34:22 -07:00
Mark McDowall
95b52e630a Remove duplicated processing of unparsed paths 2023-05-06 21:53:01 -07:00
Bogdan
5bb03a9ddf New: Add token authentication for ntfy.sh notifications
Co-authored-by: KucharczykL <lukas@kucharczyk.xyz>
2023-05-06 21:30:31 -07:00
Bogdan
e3f71ca79c New: Log content for invalid torrent files 2023-05-06 11:22:49 -07:00
Bogdan
ca8b26138e Fix downloading releases without an indexer 2023-05-01 19:28:04 -05:00
Bogdan
b0773ae7e3 Fix loading eslintrc 2023-04-29 21:12:20 -07:00
Bogdan
a0b08f6c6f Build download requests from indexer implementation 2023-04-30 00:09:11 -04:00
Benjamin Staneck
7aa8463438 Fixed some aria violations 2023-04-30 00:05:21 -04:00
Benjamin Staneck
5d873fafec New: Updated button and calendar outline colors for dark theme 2023-04-29 23:58:01 -04:00
Qstick
7ce0d4a9db Fixed: Use augmented languages for queue items 2023-04-29 17:15:39 -05:00
Fabricio Silva
83cee4b00e Fixed: Edit Quality Profile not opening
Closes #5588
2023-04-28 10:46:26 -04:00
Benjamin Staneck
de4cfefde4 Update core-js and use defaults for browserlist 2023-04-27 22:37:38 -07:00
Benjamin Staneck
bb77bb640c Use minified jquery 2023-04-27 10:33:59 -04:00
Benjamin Staneck
8bcaa17e25 Update webpack and webpack-cli 2023-04-27 10:33:10 -04:00
Benjamin Staneck
0d48ebe8de Remove unused gulpFile 2023-04-27 10:32:48 -04:00
Benjamin Staneck
e34d250440 Fix typo in calendarBackgroundColor CSS variable 2023-04-27 10:32:31 -04:00
Lars
3141bf7f9d Fixed: Subtitle tags from existing subtitle files being lost during rename
Closes #5577
2023-04-26 23:18:58 -04:00
Mark McDowall
8c50cd061e New: Report health error if Recycling Bin folder is not writable
Closes #4692
2023-04-24 21:58:51 -07:00
Gabriel Sjöberg
99c4f5b746 Use BuildInfo.AppName for RARBG appId instead of hardcoded value 2023-04-25 00:54:12 -04:00
Lars
ff3327483a New: Filter Sonarr synchronization based on Root Folders
Closes #4835
2023-04-25 00:44:20 -04:00
Mark McDowall
0bc16efe26 Don't clean slashes from folder names 2023-04-24 13:12:35 -07:00
Mark McDowall
b3260ba866 New: Colon replacement naming option 2023-04-24 07:59:36 -07:00
Mark McDowall
d3ad970ecc Use enum for MultiEpisodeStyle property 2023-04-24 07:59:35 -07:00
Bogdan
ed7d99c160 New: Add Apprise notifications 2023-04-22 18:17:24 -07:00
Robin Dadswell
720fc2818f Frontend Placeholders from the Backend
(cherry picked from commit 69f5963f6f1e80e3f598bdb13792b7413fcc13b1)
2023-04-22 18:17:24 -07:00
Mark McDowall
94b5d23094 Fixed TruncatedEpisodeTitlesFixture tests 2023-04-22 18:16:15 -07:00
Mark McDowall
cf48bf3041 Fixed: Ensure first history item when marked as failed is the selected item 2023-04-21 17:45:45 -07:00
Mark McDowall
6fe5573298 Fixed: Override modal not closed after grabbing 2023-04-21 17:45:45 -07:00
Mark McDowall
183b10f79a New: Change default Multi-Episode style to Prefixed Range
Closes #5572
2023-04-21 17:45:45 -07:00
Stevie Robinson
bead56893f Fixed: Border hover colors in dark theme 2023-04-21 20:28:07 -04:00
Mark McDowall
97cf3cee17 New: Don't prevent season searches for Newznab/Torznab if supported by the indexer
Closes #5562
2023-04-19 16:14:09 -07:00
Mark McDowall
764c084987 New: Don't try to analyze disk image files (iso, img, etc)
Closes #5567
2023-04-19 16:14:09 -07:00
Mark McDowall
a989c84260 Fixed: Tag filtering on iCal feed 2023-04-19 16:14:09 -07:00
Stevie Robinson
7ed0407e77 Fixed: Spacing between manual download and override download buttons 2023-04-19 19:14:06 -04:00
Stevie Robinson
3e87870370 Fixed: Hover color on override download button 2023-04-19 13:35:45 -04:00
Bogdan
b303e9c21a New: Serve log files as UTF-8 2023-04-18 15:50:43 -04:00
Michael Peleshenko
2303bff205 Fixed: Return properly formatted episode file for deleted files Webhook 2023-04-16 17:48:59 -07:00
Qstick
5a04602672 Remove mono process detection 2023-04-16 19:21:13 -05:00
Bogdan
6f614b7d47 Rename to FolderChmodValidator to match class name 2023-04-15 12:21:17 -07:00
Stepan Goremykin
6413d212e5 Update signalr to 6.0.15 2023-04-14 16:48:47 -07:00
Stepan Goremykin
40e54685b9 Migrate to FluentValidation 9 2023-04-14 16:48:47 -07:00
Mark McDowall
dec6e14036 New: On Add Series connection event
Closes #3637
2023-04-14 16:48:07 -07:00
Mark McDowall
619ac557f9 Fixed: Importing from Manage Episodes ignoring Analyse video files 2023-04-14 16:48:07 -07:00
Lars
c8933d8124 New: Option to use Telegram topics for notifications
Closes #5486
2023-04-14 19:47:06 -04:00
Mark McDowall
47cf8e6430 New: Updated Rarbg request limits
Closes #5206
2023-04-13 22:54:37 -04:00
Bogdan
ed3d880974 New: Add version and timestamp to backup archive 2023-04-13 22:53:32 -04:00
Qstick
39350ed0de New: Improve video stream formatting 2023-04-13 21:20:01 -05:00
Qstick
b0834015e7 New: Improve primary video stream selection 2023-04-13 21:20:01 -05:00
Bakerboy448
128f62488d Fixed: DrunkenSlug Default URL 2023-04-13 18:48:41 -07:00
Mark McDowall
83a9d15ff8 New: More information on on why hardlinks should be used over copying
Closes #5542
2023-04-11 16:27:44 -07:00
Bogdan
2107635b7e Fixed: Config file settings do not need to be case-sensitive 2023-04-11 14:52:25 -04:00
Mark McDowall
3b5e83670b Appease linter 2023-04-11 08:55:51 -07:00
Mark McDowall
513b746fc3 Fixed: Series selection unselecting on mobile browsers
Closes #5539
2023-04-10 22:54:05 -07:00
Mark McDowall
5ca868b4b2 New: Show error message for pending queue items without episodes
Closes #5541
2023-04-10 22:25:10 -07:00
Mark McDowall
48a82ad711 Fixed: Manual Import multiple episode selection
Closes #5543
2023-04-10 22:04:58 -07:00
Mark McDowall
b2c43fb2a6 Typings cleanup and improvements 2023-04-10 21:38:50 -07:00
Bogdan
5326a102e2 Fixed: Ensure default config file on starting app
(cherry picked from commit e747af9f448368e2add0d2869a3749efa9e93ae0)
2023-04-10 21:37:59 -07:00
Qstick
69ed531850 Fixed: False Positives for RemotePath check with Deluge
(cherry picked from commit b888b044d61c3787ce658963c6e5c3ef6f3323a1)
2023-04-10 21:37:48 -07:00
ta264
66caec31c9 Fixed: False positive in remote path check with transmission
Correctly use the download directory when it's set

(cherry picked from commit e09ca145d125a12016a6bf41a4971148bd2de870)
2023-04-10 21:37:48 -07:00
ta264
8c68dfb8ce Fixed: Handle missing category when getting Qbittorrent download path
Fixes RADARR-7HC
Fixes RADARR-V49

(cherry picked from commit 6f97ca9a55471386454457ca52b93733e18e85e4)
(cherry picked from commit e7a8f6332c43f179d4c95b3a8a0253a235bb6eec)
2023-04-10 21:37:48 -07:00
ta264
68791ea98a Fixed: Use QBittorrent category savepath for healthcheck
(cherry picked from commit 4f281669fcd460efa4191590de31da12c7e4271d)
2023-04-10 21:37:48 -07:00
Mark McDowall
835910843b Fixed: Series index not loading 2023-04-04 12:17:39 -07:00
Mark McDowall
221bb10261 Fixed: Override and Grab release with unknown series
Closes #5533
2023-04-04 10:39:27 -07:00
Mark McDowall
3dce7e729c Fixed: Import mode for manually imported queue items 2023-04-04 10:30:56 -07:00
Mark McDowall
b428bab5ee Fixed: Missing Macedonian and Slovenian languages 2023-04-04 10:29:08 -07:00
Mark McDowall
7fcb6b80b4 Fixed: Override and grab releases with Custom Formats 2023-04-04 10:28:35 -07:00
Mark McDowall
ba3dfdc147 Fixed: Unable to check row in Manual Import if series is not set
Closes #5532
2023-04-04 04:42:08 -07:00
Mark McDowall
103ce3def4 New: Add result to commands to report commands that did not complete successfully
Closes #4759
2023-04-03 22:11:43 -07:00
Mark McDowall
07f0fbf9a5 Override release grab modal
New: Option to override release and grab
New: Option to select download client when multiple of the same type are configured

Closes #4526
Closes #4774
2023-04-03 20:14:44 -07:00
Mark McDowall
defdc84b7e Convert Manual Import to Typescript 2023-04-03 20:14:44 -07:00
Mark McDowall
032d9a720c Extract useSelectState from SelectContext 2023-04-03 20:14:44 -07:00
Mark McDowall
2020e074db Language parsing improvements and more languages
Fixed: Parsing of multiple languages
New: Add Romanian, Latvian, Persian, Catalan, Croatian, Serbian, Bosnian, Estonian, Tamil, Indonesian, Macedonian, Slovenian languages
New: Handle some ISO 639-2/B language codes

Closes #5112
Closes #5440
Closes #5494
2023-04-03 20:00:52 -07:00
Mark McDowall
f4130d96e5 New: Add release info to webhook/custom script import events
Closes #5503
2023-04-02 14:03:05 -07:00
Qstick
f59276881a Convert Notifiarr Payload to JSON, Standardize with Webhook 2023-04-02 14:01:59 -07:00
Mark McDowall
cc46ed56b4 Fixed: Number input changing while scrolling
Closes #5516
2023-04-01 22:08:02 -07:00
Stepan Goremykin
6ea3d8c127 Use MinBy and MaxBy instead of OrderBy + First 2023-04-01 17:37:11 -07:00
bpoxy
7fedfe7423 Fixed: Matching of custom formats during episode file import 2023-04-01 20:03:53 -04:00
Bakerboy448
a776b68574 Fixed: Parse 720p Remux as 720p BluRay
fix bad anime remux no source logic

Fixes #5517
2023-03-30 21:57:14 -07:00
Bakerboy448
9ae647d9d2 QualityParser - Simplify new expression (IDE0090) 2023-03-30 21:57:14 -07:00
Stepan Goremykin
2abbee1032 Update SixLabors.ImageSharp, MailKit, DryIoc libraries 2023-03-31 00:56:54 -04:00
Qstick
2c7eb05b52 Revert a few packages which result in build warnings and conflicts 2023-03-29 11:50:14 -05:00
Mark McDowall
42003ebd72 Reverted Microsoft package updates to 6.x
Closes #5511
2023-03-27 07:52:15 -07:00
Mark McDowall
6007e46746 Fixed: Removed hardcoded dot prefix from the transmission category in status
Closes #5510
2023-03-27 07:38:56 -07:00
Stevie Robinson
11905b99d3 New: Specials monitoring options 2023-03-26 23:40:11 -07:00
Mark McDowall
033936dce7 Fixed IsValidPath usages 2023-03-26 22:47:09 -07:00
Mark McDowall
13a0dfa4ae Fixed: Slow renaming and deleting episodes
Closes #5499
2023-03-26 22:39:18 -07:00
Mark McDowall
5ea1fb9424 New: Parsing of multi-episode files in brackets
Closes #5501
2023-03-26 22:39:18 -07:00
bakerboy448
0f6f681438 New: Various HealthCheck Improvements 2023-03-27 00:30:27 -04:00
Mark McDowall
0321368cc3 New: Improve path validation when handling paths from different OSes 2023-03-26 21:29:17 -07:00
Mark McDowall
ed140dd396 Revert argument exception swallowing for Plex library update 2023-03-26 21:29:07 -07:00
Stepan Goremykin
c35308b32b Update chrome driver and swagger 2023-03-26 21:26:42 -07:00
Stepan Goremykin
e4dde10a3f Update Selenium.Support package 2023-03-26 21:26:42 -07:00
Stepan Goremykin
951a9ade00 Update FluentAssertions 2023-03-26 21:26:42 -07:00
Stepan Goremykin
fd5d279a9e Update SharpZipLib 2023-03-26 21:26:42 -07:00
Stepan Goremykin
028c87d20c Update test packages in build props instead of csproj 2023-03-26 21:26:42 -07:00
Stepan Goremykin
b303dc899a Update Newtonsoft.Json 2023-03-26 21:26:42 -07:00
Stepan Goremykin
cf22208011 Update packages related to auto tests 2023-03-26 21:26:42 -07:00
Stepan Goremykin
3b6cadeb7e Update packages from microsoft 2023-03-26 21:26:42 -07:00
Mark McDowall
0a13a433a9 New: Parsing of more German WEBDL releases
Closes #5507
2023-03-26 21:19:22 -07:00
Mark McDowall
ff2e8ffc37 Fixed: Permissions after installing on Windows and opening Firewall port
Closes #5509
2023-03-26 20:53:30 -07:00
Mark McDowall
34e928ebed Fixed: Agenda view on mobile 2023-03-26 20:45:20 -07:00
Stepan Goremykin
11d91faaad Use Array.Empty and fix a few multiple enumerations 2023-03-26 23:40:51 -04:00
Mark McDowall
c41aec5f77 Fixed: Pushed releases should be stored as pushed release 2023-03-22 17:25:00 -07:00
Mark McDowall
b8dcd75cf5 Fixed: Refreshing Plex library on a different OS 2023-03-22 08:09:16 -07:00
Mark McDowall
cef6d5a99a Fixed: Imports when custom format is a downgrade, but file is an upgrade 2023-03-22 08:06:59 -07:00
lodu
5d09b84b05 New: Add indexer option for Discord on grab notifications 2023-03-21 19:58:47 -04:00
Mark McDowall
3d24e412a6 Better quality revision logging 2023-03-17 07:46:25 -07:00
Mark McDowall
ad79dd4df5 New: Better series type select input
Closes #4796
2023-03-16 22:03:31 -07:00
Mark McDowall
4ff4d32936 New: Improve accepted and rejected release logging
Closes #4965
Closes #4646
2023-03-16 20:58:01 -07:00
Mark McDowall
98308737cf New: Improved Plex library updating 2023-03-16 20:25:31 -07:00
Mark McDowall
f59cc99733 Remove unused imports from SeriesIndexRow 2023-03-16 00:40:12 -07:00
Mark McDowall
b16094a9e3 Fixed: Prevent loss of restrictions when attempting to edit multiple restrictions at once
Closes #4917
2023-03-16 00:36:32 -07:00
Mark McDowall
bd228e88c3 New: Rescan series if destination file already exists during import
Closes #5401
2023-03-15 23:44:09 -07:00
Mark McDowall
978618f041 New: Don't import episodes that don't match grab history
Closes #5073
2023-03-15 23:26:07 -07:00
Zak Saunders
89e363fd14 New: Make Release Group Outline Not Show as Required 2023-03-15 22:28:53 -07:00
Mark McDowall
8d70def088 New: Include series year with custom scripts and webhooks
Closes #5439
2023-03-15 22:09:55 -07:00
Mark McDowall
cb86f4fa50 New: Closing Move Series modal without selecting will cancel save
Closes #5448
2023-03-15 21:55:17 -07:00
Mark McDowall
c80c1db947 New: Parse HBOMaxHD as WEBDL
Closes #5489
2023-03-15 21:01:37 -07:00
Mark McDowall
cfcf1ad1ab Fixed: Page Plex Watchlist results
Closes #5118
2023-03-15 19:55:34 -07:00
Mark McDowall
17b9e4722a New: Parsing of poorly named absolute number-only files in batches
Closes #5488
2023-03-15 19:00:12 -07:00
Mark McDowall
f22998aef3 Use episode runtime for size limits when available
Closes #3482
2023-03-15 19:00:08 -07:00
Qstick
a42f97229a Convert method to static that doesn't use instance data 2023-03-15 19:24:48 -05:00
Qstick
412a36226f Add .globalconfig 2023-03-15 19:24:48 -05:00
Qstick
e8b862a380 Remove Non-Failing Rules 2023-03-15 19:24:48 -05:00
Qstick
2b79fe833b Use Contains(char) instead of Contains(string) for performance 2023-03-15 19:24:48 -05:00
Qstick
4db10e6283 Prefer AsSpan to Substring to avoid unnecessary allocation 2023-03-15 19:24:48 -05:00
Qstick
e8aff90582 Use span-based string.Concat to avoid unnecessary allocation
Calling Substring produces a copy of the extracted substring. By using AsSpan instead of Substring and calling the overload of string.Concat that accepts spans, you can eliminate the unnecessary string allocation.
2023-03-15 19:24:48 -05:00
Qstick
af28bbad52 Use Environment.CurrentManagedThreadId for efficiency
System.Environment.CurrentManagedThreadId is a compact and efficient replacement of the Thread.CurrentThread.ManagedThreadId pattern.
2023-03-15 19:24:48 -05:00
Qstick
f928ee7cad Use Environment.ProcessPath instead of GetCurrentProcess().MainModule.FileName
GetCurrentProcess().MainModule.FileName is expensive, Environment.ProcessPath added in net6
2023-03-15 19:24:48 -05:00
Qstick
7521579bca Use Apend(char) instead of Apend(string) for performance
When calling StringBuilder.Append with a unit length string, consider using a const char rather than a unit length const string to improve performance.
2023-03-15 19:24:48 -05:00
Qstick
e805f61450 Use Length/Count property instead of Count() method to prevent enumerating 2023-03-15 19:24:48 -05:00
Qstick
4fe9daec03 Use Any() in place of Count() to prevent enumerating
This rule flags the Count and LongCount LINQ method calls used to check if the collection has at least one element. These method calls require enumerating the entire collection to compute the count. The same check is faster with the Any method as it avoids enumerating the collection.
2023-03-15 19:24:48 -05:00
Qstick
738dc2c98c Do not use Enumerable methods on indexable collections
This rule flags the Enumerable LINQ method calls on collections of types that have equivalent but more efficient properties to fetch the same data.
2023-03-15 19:24:48 -05:00
Qstick
0ed8ba828d Avoid unnecessary zero-length array allocations 2023-03-15 19:24:48 -05:00
Qstick
b2c2c79a96 Don't compare strings to Empty using Equals
Comparing strings using the String.Length property or the String.IsNullOrEmpty method is faster than using Equals. This is because Equals executes significantly more MSIL instructions than either IsNullOrEmpty or the number of instructions executed to retrieve the Length property value and compare it to zero.
2023-03-15 19:24:48 -05:00
Qstick
08ee2f7e32 Remove unnecessary assignments to default type value
The .NET runtime initializes all fields of reference types to their default values before running the constructor. In most cases, explicitly initializing a field to its default value in a constructor is redundant, adding maintenance costs and potentially degrading performance
2023-03-15 19:24:48 -05:00
Qstick
42e45f93ac Use const where appropriate
The value of a const field is computed at compile time and stored in the metadata, which improves run-time performance when it is compared to a static readonly field.
2023-03-15 19:24:48 -05:00
Qstick
b4d8f0c311 Enable all analyzers and enforce code style on build 2023-03-15 19:24:48 -05:00
Stevie Robinson
21045127cd Fixed: Parsing of multi season packs with only space between the season numbers 2023-03-14 00:32:57 -07:00
Mark McDowall
d496733b31 Fixed: Don't import Custom Format downgrades
Closes #5475
2023-03-14 00:22:37 -07:00
Mark McDowall
b3d1e4f520 Fixed: Multiple Downloaded Episodes Scan commands should not run in parallel 2023-03-13 18:11:17 -07:00
Mark McDowall
cd67671bc1 Fixed: Slow loading of files in Manage Episodes modal
Closes #5449
2023-03-13 00:30:28 -07:00
Mark McDowall
1f619e27f1 New: Season interactive search modal size
Closes #5483
2023-03-12 23:58:37 -07:00
Mark McDowall
ac806a2933 New: Show downloading status for series progress bar
Closes #5474
2023-03-12 23:51:38 -07:00
Mark McDowall
6d88a98282 New: Plex Watchlist RSS support 2023-03-12 23:51:38 -07:00
Stevie Robinson
4f5a183152 Fixed: Color unaired items in agenda view
Closes #5477
2023-03-10 22:37:02 -08:00
cicomalieran
9800bd6b43 Fixed: Processing very long ETA from Transmission
Closes #5444
2023-03-07 16:46:48 -08:00
Mark McDowall
aa938d911b Fixed: Misaligned table border
Closes #5456
2023-03-05 23:41:14 -08:00
Mark McDowall
622e36de96 Fixed: Some posters not showing for new series search results
Closes #5451
2023-03-05 23:41:13 -08:00
Sergey M
255f947860 Fixed: Mapping of parsed titles when one doesn't have an alias
Co-authored-by: Sergey M <msergein>
2023-03-05 17:30:56 -08:00
bakerboy448
92ecb30fab Fixed: Regression in error message logging
Closes #5461
2023-03-01 18:19:16 -05:00
Qstick
6082253166 New: Additional custom filter predicates for strings 2023-02-23 22:46:15 -06:00
bakerboy448
e968919e63 Fixed: Improve some request failure messaging 2023-02-22 17:36:12 -08:00
Mark McDowall
6ec32eb45d Fixed lint error and background for poster select 2023-02-22 17:17:24 -08:00
Mark McDowall
bd3816dac9 Handle null for parent name with clean path is empty 2023-02-20 17:20:07 -08:00
Mark McDowall
95a8f59a32 Fixed: Don't handle images in metadata folder as Roksbox images 2023-02-20 16:42:57 -08:00
Mark McDowall
890f107467 New: Support for .plexmatch series metadata files
Closes #4960
2023-02-20 15:08:26 -08:00
Mark McDowall
6740257135 New: Add Episode Guide option for Kodi MetadataFile
Closes #5415
2023-02-20 12:35:22 -08:00
Mark McDowall
bbd9b1657d Fixed: Don't clean Kodi library if video is playing and Always Update is disabled
Closes #5387
2023-02-20 10:48:49 -08:00
Mark McDowall
d923d3f106 Fixed: Series table not resizing properly when window size changed 2023-02-20 09:59:49 -08:00
Mark McDowall
bf62d4f921 Fixed: Series select not working correctly after stopping/starting or changing sort order 2023-02-20 09:58:11 -08:00
Mark McDowall
cf00fecbe4 Fixed: Don't grab propers/repacks when item in queue meets cutoff and propers/repacks are not downloaded automatically
Closes #1208
2023-02-19 00:32:58 -08:00
Qstick
5a22afc42b Fixed broken path tests 2023-02-18 15:37:35 -08:00
Mark McDowall
75378f7bde Fixed: USB drives mounted to folders are treated as different mounts
Closes #4147
2023-02-16 17:05:39 -08:00
Mark McDowall
37c355da51 Improved UI error messages (stack trace and version) 2023-02-16 16:45:09 -08:00
Mark McDowall
57a64b056a New: Increase clickable area of series select in poster/overview 2023-02-13 17:26:32 -08:00
Mark McDowall
279d3a89b6 Fixed loading series list and custom filters
Fixed: Loading series list
Fixed: Adding new custom filter

Closes #5430
2023-02-13 11:27:16 -08:00
tsubus
492c9e22ba Remove unused ReactDOM import
fixes error with mono: "error  'ReactDOM' is defined but never used  no-unused-vars"
2023-02-13 07:30:14 -08:00
Mark McDowall
f7ce5c7b11 Fixed: File browser 2023-02-12 23:58:50 -08:00
Mark McDowall
997aabbc3c Improve CF calculation for files without scene name
Fixed: Use original filename instead of complete path when calculating CF for existing file without scene name
Closes #5365
2023-02-12 22:33:45 -08:00
Mark McDowall
2c65e4fa41 Fixed: Prevent getting disk space from returning no information when it partially fails
Closes #5247
2023-02-12 20:55:13 -08:00
Qstick
9c1fd7c73e Bump MonoTorrent to 2.0.7
Pulls in fix for parsing torrents when certain values are an empty string
2023-02-12 21:58:44 -06:00
Mark McDowall
ce255b55e6 Add CSS typings 2023-02-12 19:16:07 -08:00
Mark McDowall
6fce6c2bbc Remove Season Pass 2023-02-12 19:16:07 -08:00
Mark McDowall
67232290e5 Remove Series Editor 2023-02-12 19:16:07 -08:00
Mark McDowall
bdcfef80d6 New: Season Pass is now part of series list 2023-02-12 19:16:07 -08:00
Mark McDowall
a18c377466 Switch to eslint for linting 2023-02-12 19:16:07 -08:00
Mark McDowall
a731d24e23 New: Mass Editor is now part of series list 2023-02-12 19:16:07 -08:00
Mark McDowall
815a16d5cf Added series index selection 2023-02-12 19:16:07 -08:00
Mark McDowall
5aad84dba4 Fixed: Restoring scroll position when going back/forward to series list 2023-02-12 19:16:07 -08:00
Mark McDowall
d022679b7d Refactor Series index to use react-window 2023-02-12 19:16:07 -08:00
Mark McDowall
de56862bb9 Add Prettier to format TypeScript files 2023-02-12 19:16:07 -08:00
Mark McDowall
910511dba0 Add typescript 2023-02-12 19:16:07 -08:00
Mark McDowall
27cc551980 Updated API documents 2023-02-12 15:09:00 -08:00
Mark McDowall
d2cd3f7716 Rename LocalizationLanguageResource to avoid collision with LanguageResource 2023-02-12 15:06:51 -08:00
bpoxy
5e761f766c Fixed: Show calculated (rather than stored) custom format score on season and series history, to match episode history 2023-02-12 14:48:23 -08:00
bakerboy448
ddb25b1095 New: Use better page size for Newznab/Torznab (up to 100) when supported by the indexer
Closes #5373
2023-02-12 14:34:04 -08:00
Stevie Robinson
c1e43e9389 Fixed: text color of complete seasons dark mode
the readability of complete seasons on season pass is not great. changed from light gray to dark gray
2023-02-12 14:32:17 -08:00
Mark McDowall
303fc5d786 New: Return static response to requests while app is starting
Closes #5402
2023-02-07 17:31:54 -08:00
Mark McDowall
81435dabc7 Fixed: Creating new Delay Profile
Closes #5419
2023-02-07 17:25:29 -08:00
Qstick
a379d0c403 Fixed: Settings fail to save for some auth setups 2023-02-06 23:09:10 -06:00
Mark McDowall
72b307f4ad Fixed: Using absolute episode number in Standard Format for episode without while renaming 2023-02-06 16:55:04 -08:00
Mark McDowall
69f325b9dd SeriesFolderFormat needs to be OS Agnostic 2023-02-04 16:54:22 -08:00
Mark McDowall
81d2b18ce1 New: Use Series Folder Format to improve unmapped folders within root folders 2023-02-04 15:51:00 -08:00
Mark McDowall
119addd75f Fixed: Migrating case-sensitive Preferred Word REGEX to Custom Formats
Closes #5399
2023-02-04 00:32:48 -08:00
Xavier Xiong
0f111dd066 Fixed: Chinese Anime releases that include a season number 2023-02-04 00:10:13 -08:00
Stevie Robinson
e29470d8cb Fixed: Enable parsing of repacks with revision
Closes #5383
2023-02-04 00:08:35 -08:00
bakerboy448
83f6359063 New: Improve Manual Import logging when not parsing files 2023-02-04 00:06:59 -08:00
Mark McDowall
ad42d4a14c Fixed: Ping endpoint no longer requires authentication
Closes #5396
2023-01-31 23:39:59 -08:00
Qstick
faccfe17a2 Remove debug code in CleanupQualityProfileFormatItems 2023-01-22 13:47:13 -06:00
Qstick
f05e109b50 Fixed: Avoid Sqlite Error when all profiles have lowest quality cutoff 2023-01-21 18:11:09 -06:00
Stevie Robinson
3973571411 New: Added new series title rename tokens without year
Closes #5369
2023-01-21 18:55:00 -05:00
bakerboy448
863d24996c New: Improve messaging when imports are left in queue 2023-01-21 18:28:33 -05:00
Zak Saunders
c897608bab Fixed: Calendar Grouped Series Title 2023-01-21 15:18:26 -08:00
PearsonFlyer
1b599c7e76 Fix notifiation in Ntfy on test from Radarr to Sonarr 2023-01-19 18:19:30 -06:00
Mark McDowall
0fbf61199f Fixed: Parsing of some files with series title aliases 2023-01-18 17:18:55 -08:00
Mark McDowall
b848100693 Fixed: Images for some series not downloading
Closes #5376
2023-01-15 21:21:34 -08:00
Qstick
c08b451564 Bump ImageSharp to 2.1.3 2023-01-15 14:27:08 -06:00
Mark McDowall
71bfa0ff02 Fix use of sizeOnDisk 2023-01-13 18:24:18 -08:00
Mark McDowall
6dcfc661a1 New: Show updated Custom Format Score in history 2023-01-13 17:41:43 -08:00
Mark McDowall
68d026479f New: Add custom format info to episode import notifications 2023-01-13 17:41:43 -08:00
Mark McDowall
899d6ddbab Fixed: Store Custom Format score during import
Closes #5291
2023-01-13 17:41:43 -08:00
Mark McDowall
4ed4ca4804 New: Add bypass if above Custom Format Score to Delay Profile
Closes #5043
2023-01-13 20:40:49 -05:00
Mark McDowall
bc2942c28d New: Don't block imports when release was matched by ID if they were grabbed via interactive search
Closes #5043
2023-01-13 17:40:08 -08:00
Mark McDowall
599ad86657 New: Use file's format title for quality if parsed
Closes #3930
2023-01-13 20:39:29 -05:00
Mark McDowall
3f598ffa6f Fixed: UTC time sent to UI for already imported message
Closes #5366
2023-01-13 17:39:00 -08:00
Mark McDowall
67035b9266 Fixed: Monitoring episodes modal not closing after saving 2023-01-13 17:38:31 -08:00
Mark McDowall
2c5b9e9999 Fixed: Loading Sonarr on OAF browsers
Closes #5363
2023-01-11 17:09:25 -08:00
Mark McDowall
4b4301a076 Fixed: Quality Profiles resetting Custom Format scores during housekeeping
Closes #5359
2023-01-09 12:18:14 -08:00
Mark McDowall
2c004e1f96 Fixed: Unable to load UI if Quality Profiles contain removed Custom Format items 2023-01-09 08:58:25 -08:00
Mark McDowall
ea612e8b78 Revert "Fixed: Unable to load UI if Quality Profiles contain removed Custom Format items"
This reverts commit facf775a43.
2023-01-09 08:57:45 -08:00
Xavier Xiong
f742e1f174 Fixed: Chinese releases with season and absolute episode numbers 2023-01-09 01:57:21 -05:00
Mark McDowall
facf775a43 Fixed: Unable to load UI if Quality Profiles contain removed Custom Format items
Closes #5323
2023-01-08 22:49:56 -08:00
Mark McDowall
4f61a4ab07 New: Fixed truncation on Firefox after renaming Custom Format specification
Closes #5357
2023-01-08 10:26:12 -08:00
Qstick
4a740acb80 New: Simkl List Support (#5313)
* New: Simkl List Support

* fixup! smarter sync

* fixup! comments

* fixup! comments
2023-01-07 12:58:10 -06:00
bakerboy448
e07936fb84 2023 readme fixes 2023-01-05 19:23:04 -05:00
Mark McDowall
1394122842 Fixed: Displaying audio and subtitle languages in UI 2023-01-04 21:24:26 -08:00
Mark McDowall
84e6649724 Cleanup old usages of languageCutoffNotMet 2023-01-04 21:24:26 -08:00
Mark McDowall
fe5c52602a Fixed: Custom Formats upgrading even when profile doesn't allow upgrades
Closes #5330
2023-01-04 16:41:12 -05:00
Stevie Robinson
3316665e93 Fixed: Kodi Metadata Subtitle Language 2023-01-04 16:39:34 -05:00
Mark McDowall
61fa1e5e3f New: Added health check warning if SABnzbd sorting is enabled
Closes #4985
2023-01-03 15:41:12 -08:00
Mark McDowall
48b4cc5f3f New: Improved messaging when qBittorrent fails due to host header rejection 2023-01-02 16:30:00 -08:00
Mark McDowall
396406b217 New: Description for indexer RSS setting 2023-01-01 09:10:00 -08:00
Mark McDowall
09eea0571f Fixed: Delete series
Closes #5333
2023-01-01 08:37:00 -08:00
Mark McDowall
d8f6eaebdc New: Remember add import list exclusion when removing series
Closes #4984
2022-12-31 22:17:50 -08:00
Mark McDowall
2fc76a9ac5 New: Use XEM season number for some releases when mapping episodes
Closes #5195
2022-12-31 21:41:22 -08:00
Mark McDowall
6ec7c3f7a9 Fixed: Parsing of anime that uses standard numbering and includes episode number at end
Closes #5331
2022-12-30 14:59:12 -08:00
Mark McDowall
4baa2a07ba Fixed: End year for series not showing correctly in some cases 2022-12-30 13:21:49 -08:00
Mark McDowall
8fff59ff10 New: Show detailed queue status on Calendar and Series Details
Closes #3775
2022-12-29 23:57:20 -08:00
Zak Saunders
ca61efa57f Fixed: Progress bar text colour in Dark theme 2022-12-29 17:56:29 -08:00
Stevie Robinson
30cbaf06fa Fix comment 2022-12-29 13:12:31 -05:00
Mark McDowall
738a7b38c9 New: Parsing of some Dutch/Flemish/Italian release titles
Closes #2762
2022-12-29 00:49:08 -08:00
Mark McDowall
f504dfcbab New: Missing/Cutoff Unmet searches will search for episodes that haven't been searched recently first
Closes #3067
2022-12-27 23:27:31 -08:00
Mark McDowall
2491da0678 Fixed: Don't try to remove the same item from queue multiple times 2022-12-27 01:07:15 -08:00
Mark McDowall
1f8e1cf582 Fixed: Multiple pushed releases will be processed sequentially
Closes #2975
2022-12-25 23:20:43 -08:00
Mark McDowall
40ce54e165 Upgrade Newtonsoft.Json 2022-12-23 22:33:39 -08:00
Mark McDowall
32544318e1 Updated some JS dependencies 2022-12-23 22:03:17 -08:00
Mark McDowall
e57e68c97a New: Option to include series image for Gotify notifications
Closes #4882
2022-12-22 23:47:05 -08:00
Mark McDowall
ce0388ca99 Fixed: Only log /proc/mounts exception once per process
Closes #4929
2022-12-20 17:18:50 -08:00
Mark McDowall
17bfcdd325 New: Portuguese (Brazil) and Spanish (Latino) languages
Closes #5302
2022-12-20 20:17:47 -05:00
Qstick
a26163b646 Cleanup Trakt implementation 2022-12-20 17:27:41 -06:00
Qstick
0fad20e327 Handle auth options correctly in Security Settings 2022-12-20 11:56:04 -06:00
Mark McDowall
9e694c7b06 New: Added option to filter series by complete missing season
Closes #5037
2022-12-19 22:51:06 -08:00
Qstick
62354dfac8 Fixed: Don't enforce minimum on single list fetch 2022-12-18 18:28:08 -06:00
Mark McDowall
b15b6a0798 Improve handling of releases without video files
New: Show warning in queue if download contains executable or archive file and no video file was detected

Closes #5101
2022-12-18 09:58:03 -08:00
Mark McDowall
4ce4031dd8 New: Reduce size of Custom Formats in responses for most endpoints 2022-12-18 09:57:53 -08:00
Mark McDowall
fc8e6d6f02 Fixed: Manual import when no reprocessing items after selecting series and season 2022-12-17 21:25:18 -08:00
Mark McDowall
b8714d80a1 Fixed: Prevent unexpected data breaking Series Import 2022-12-17 21:25:18 -08:00
Colin Gagnaire
fb76c237bf New: Add support for native Freebox Download Client
Closes #5140
2022-12-16 18:37:21 -08:00
Mark McDowall
5ce8ea8985 New: Parse release group from VARYG releases with junk at the end
Closes #5308
2022-12-16 18:27:11 -08:00
Mark McDowall
ad2557815e New: Allow season information tooltip to display above if unable to display below
Closes #5300
2022-12-14 18:14:06 -08:00
Mark McDowall
ee1ee8f267 New: Rename Emby to Emby / Jellyfin
Closes #5301
2022-12-14 17:47:49 -08:00
Mark McDowall
6c53bf30d5 Fixed: Size on disk calculation including multi-episode files multiple times
Closes #5296
2022-12-14 17:45:43 -08:00
Mark McDowall
f15f08e51a Revert "Fixed: Size on disk calculation including multi-episode files multiple times"
This reverts commit be98862ce0.
2022-12-14 08:01:56 -08:00
Mark McDowall
be98862ce0 Fixed: Size on disk calculation including multi-episode files multiple times
Closes #5296
2022-12-14 00:24:02 -08:00
Mark McDowall
9a96dee49d New: Parsing of releases extra slash in Chinese anime titles
Closes #5299
2022-12-13 23:32:58 -08:00
Mark McDowall
789a8f5301 Fixed: Queue not showing items with conflicting titles 2022-12-12 22:44:08 -08:00
Mark McDowall
530829f8ed Don't copy/pasta kids 2022-12-11 19:42:44 -08:00
Mark McDowall
8bea8a10da Fixed: Skip anime version upgrade check if Proper/Repacks are not preferred
Closes #4468
2022-12-11 18:01:51 -08:00
Mark McDowall
e42edf1d33 New: Add Thai Language
Closes #5170
2022-12-10 16:25:23 -08:00
Mark McDowall
fea66cb7bc Fixed: Quality cutoff updating in UI when adding/removing qualities
Closes #5290
2022-12-10 16:04:06 -08:00
Mark McDowall
7f5abfd87d New: Parsing of Japanese variety shows
Closes #5279
2022-12-10 13:42:41 -08:00
Qstick
356771d139 New: Speed up mass deletes from Series Editor
* New: Speed up mass deletes from Series Editor

* fixup! Additional speed up using GetAllSeriesPaths vs GetAllSeries

* fixup! Tests
2022-12-10 14:19:10 -06:00
Mark McDowall
d08f33ae21 New: Quality Preferred Setting
Co-authored-by: Qstick <qstick@gmail.com>
Closes #724
2022-12-10 09:59:54 -08:00
Mark McDowall
b2b9172c92 Fixed: Custom formats with score of 0 showing 1
Closes #5288
2022-12-10 09:47:12 -08:00
Mark McDowall
60470b653a Fixed: History Since API endpoint 2022-12-10 01:11:20 -08:00
Mark McDowall
d09e5d8eb4 Fixed: Trakt connection auth tokens not being refreshed
Closes #5285
2022-12-10 00:42:46 -08:00
Mark McDowall
041dc659fe Fixed: Custom formats with a total score of zero not showing in some places 2022-12-09 20:55:01 -08:00
Mark McDowall
be02d0ebf7 Fixed: Series/season history loading
Closes #5286
2022-12-09 20:40:51 -08:00
Mark McDowall
b3959e3162 Fixed broken pending release tests 2022-12-09 10:39:16 -08:00
Mark McDowall
e50eb5188e Fixed: Unable to process downloads from client
Closes #5284
2022-12-09 09:19:11 -08:00
Stevie Robinson
05775a9bd0 Fix bug_report.yml description field
field was over 200 chars and apparantely not valid|!
2022-12-09 15:22:54 +01:00
Qstick
779f348f7b Add deprecated sort values to validation
Fixed #5282
2022-12-09 07:47:33 -06:00
Gabriel Patzleiner
b98881c576 Fixed: Absolute episodes followed by a year not getting parsed correctly 2022-12-08 22:37:32 -08:00
Mark McDowall
da4f6b7df9 New: Show Custom Formats on Manual Import / Manage Episodes
Closes #5241
2022-12-08 20:00:02 -08:00
Mark McDowall
6216a71f8c Fixed: Parsing of releases with episode titles that contain languages
Closes #861
2022-12-08 18:59:36 -08:00
Qstick
16e2d130e6 Simplify X-Forwarded-For handling
This happens in asp.net middleware now

Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-12-07 23:03:59 -06:00
Qstick
fd98a179ab New: Improve IPAddress.IsLocal method
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-12-07 23:03:59 -06:00
Mark McDowall
87795708b5 New: Allow Season packs to be grabbed automatically if all episodes will have aired within 24 hours
Closes #5191
2022-12-07 20:26:49 -08:00
Mark McDowall
0450d0b2b6 Remove unused dependency in SeasonPackOnlySpecification 2022-12-07 20:26:49 -08:00
Qstick
e19071da0e Fixed: Avoid path manipulation from receiving to sending for Kodi
Fixes #5260
2022-12-07 21:54:12 -06:00
Qstick
c522cd120d New: Rework List sync interval logic
* New: Rework List sync interval logic

Fixes #5011
2022-12-07 21:09:42 -06:00
Mark McDowall
7675b4bc3b Fixed: Queue failing to load if column was sorted by episode air date or title
#5257
2022-12-07 19:03:51 -08:00
Mark McDowall
1b90fbcf7d New: IPv6 support for connections/indexers/download clients
Closes #4149
2022-12-06 23:11:59 -08:00
Mark McDowall
6bdeafcf8c Fixed: Improve Bind Address validation and help text
Closes #622
2022-12-06 23:11:59 -08:00
Mark McDowall
9e6b32ca3e New: Parsing of 4K GM-TEAM releases 2022-12-06 23:10:25 -08:00
Zak Saunders
4ca5a213fa New: Auto theme option to match OS theme
Co-authored-by: Qstick <qstick@gmail.com>
2022-12-06 02:22:52 -05:00
Mark McDowall
c7d6c0f452 New: Show all options when authentication modal is open 2022-12-05 23:01:09 -08:00
Stevie Robinson
7f5769ab70 Git issue template update 2022-12-06 01:59:36 -05:00
Mark McDowall
335fc05dd1 New: Auto tagging of series
Closes #3870
2022-12-06 01:58:53 -05:00
penggongkui
8eb941d590 Fixed: Parsing of additional GM-Team formats 2022-12-05 10:54:42 -05:00
Mark McDowall
e77be24c7b Fixed: Sending Webhook on upgrade if media info is unavailable
Closes #5272
2022-12-05 01:10:54 -08:00
Qstick
b98ce7fb17 New: Store Task StartTime, Show Duration in UI
Closes #5266
2022-12-04 19:10:56 -08:00
Qstick
11e6e12676 Fixed: Error on EpisodeFile summary modal if CF is null
Fixes #5268
2022-12-04 15:24:22 -06:00
Qstick
78af4823cf Fixed: Imdb lists only return 1 result 2022-12-04 09:35:50 -06:00
Qstick
859e48ff5c Update API Docs 2022-12-03 23:32:54 -06:00
Qstick
7e48ea0231 Fixed: Correct Attribute compare for Id validation 2022-12-03 23:17:50 -06:00
Mark McDowall
8105da33d8 Fixed broken pending release tests 2022-12-03 17:28:11 -08:00
Mark McDowall
df199ce0d8 Fix modal title for Manage Episodes in Season 2022-12-02 23:34:10 -08:00
Mark McDowall
154da57dc5 New: Add Custom Formats to episode details modal 2022-12-02 23:24:00 -08:00
Mark McDowall
998768bcf2 New: Filter by Custom Format Score in Interactive Search 2022-12-02 23:06:08 -08:00
Mark McDowall
0f2ceb85bd New: Parse GM-Team's file names that are different from their release names 2022-12-02 22:43:32 -08:00
Mark McDowall
31198c627f Fixed: Loading queue when there are pending items that were added before upgrading
Closes #5257
2022-12-02 22:42:57 -08:00
Mark McDowall
51b1ba13c1 Fixed: Grab/remove queue actions not showing spinner 2022-12-02 17:27:54 -08:00
Mark McDowall
b76a7c2773 Fixed: Pending items in queue not showing Custom formats
Closes #5248
2022-12-02 17:27:12 -08:00
Qstick
3b10400948 New: FreeBSD Support
Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2022-12-02 16:09:24 -08:00
Qstick
aaaf18aec3 Fixed: Add back LanguageProfiles endpoints and deprecate
* Fixed: Add back LanguageProfiles endpoints and deprecate

* fixup! Fixed: Add back LanguageProfiles endpoints and deprecate
2022-11-30 19:46:27 -06:00
Qstick
c9b483bdf7 Fixed: Use develop logo for Kodi notifications
Fixes #5256
2022-11-29 19:51:20 -06:00
Qstick
095dcac90b Make CF insensitive help text more obvious 2022-11-29 19:51:19 -06:00
Qstick
becc567ff7 Fixed: Use route Id for PUT requests if not passed in body 2022-11-29 19:44:18 -06:00
Qstick
528feb14c9 Prevent NullRef on CustomFormat parse 2022-11-28 22:04:33 -06:00
Mark McDowall
f2b2eb69a3 Fixed: Handle Flood reporting errors for completed and stopped downloads
Closes #5224
2022-11-28 19:04:29 -08:00
Qstick
4c7df31070 New: Add support for Simplepush notifications
Fixes #5108

Co-Authored-By: Timm Schäuble <Timm.Schaeuble@gmail.com>
2022-11-28 20:32:39 -06:00
Qstick
6d142f0b0a Clarify Custom Format regex help text 2022-11-28 18:23:33 -06:00
Qstick
89270ad7a1 Fixed: Original Language failures on Custom Format parsing
Fixes #5240
2022-11-28 18:23:33 -06:00
Mark McDowall
3fdc7c8346 Fix lint error 2022-11-27 18:27:04 -08:00
Mark McDowall
32ebb51634 Fixed some react warnings with ReleaseSceneIndicator 2022-11-27 15:44:24 -08:00
Qstick
651055820a Fixed: Logging for Cutoff and UpgradeAllowed Specs
Fixes #5242
2022-11-27 12:16:36 -06:00
Qstick
3a2a030432 Really fix Original Language in MapSeries
Fixes #5246
2022-11-27 12:14:28 -06:00
Stevie Robinson
ca04c93666 Prevent false positives with HONE releases 2022-11-26 19:37:37 -08:00
Mark McDowall
ed9a47449b Fixed broken tests after updating images 2022-11-26 19:36:49 -08:00
Mark McDowall
264286dcf1 Fixed: Queued downloads not showing on episodes properly 2022-11-26 19:36:49 -08:00
Bruno Garcia
de3cb07c57 Sentry SDK v3.23.1
Co-authored-by: Bruno Garcia <bruno@Brunos-MacBook-Pro.local>
2022-11-26 14:06:08 -08:00
yammes08
cb00ce7c0b New: Add HONE to list of release group exceptions
Closes #5243
2022-11-26 14:05:00 -08:00
Qstick
f47abd0d99 Fix movie reference in PlexListRequestGenerator 2022-11-25 06:31:41 -06:00
Qstick
381834edce New: IMDb List Support 2022-11-25 06:31:41 -06:00
Qstick
ea7af03d69 Fixed: Handle MapSeries when orig language is null 2022-11-24 14:33:12 -06:00
Mark McDowall
99e60196a4 Fixed: Parse year in title from square brackets 2022-11-24 10:12:12 -08:00
Mark McDowall
53a3fc31e2 Fixed: Saving Trakt Popular Import List without Genres 2022-11-24 08:14:23 -08:00
Qstick
08b677ca7d Enforce comment spacing with Stylecop 2022-11-21 16:58:07 -08:00
Qstick
be0fa73129 New: Store and use original Series language 2022-11-21 16:58:07 -08:00
Mark McDowall
5400bce129 Publish ApplicationStartingEvent during startup 2022-11-20 19:09:35 -08:00
Qstick
237e7556c2 Bump Newtonsoft to 13.0.1 2022-11-19 17:17:56 -06:00
Qstick
173f456683 Remove Unity (No longer maintained) 2022-11-19 17:01:57 -06:00
Qstick
908d79f2f6 Revert FFMpegCore wrapper to 4.7 to avoid random failures 2022-11-19 16:41:32 -06:00
Mark McDowall
c43d06628d Add missing eslint-plugin-react-hooks package 2022-11-18 22:47:27 -08:00
Mark McDowall
c8dbbe431a Fixed broken NewznabRequestGenerator tests 2022-11-18 22:33:51 -08:00
Mark McDowall
80af164385 Added SECURITY.md
Closes #4787
2022-11-18 22:05:34 -08:00
Mark McDowall
a1e6a2c530 Fix overzealous regex 2022-11-18 22:05:09 -08:00
Mark McDowall
f9f08cfea2 New: Perform ID based searches for anime if the indexer supports ID searching
Closes #5090
2022-11-16 19:02:57 -08:00
Mark McDowall
ba9651b241 Use string interpolation for Newznab request generation 2022-11-16 19:02:05 -08:00
Mark McDowall
ae306274be New: Improve logging when processing files for import
Closes #5226
2022-11-13 18:36:17 -08:00
Mark McDowall
9bd783d49c Improve page scrollbar
New: Style scrollbar in Firefox
Fixed: Scrolling with click and drag

Closes #5189
2022-11-13 18:04:20 -08:00
Mark McDowall
1c6c9a7960 Replace react-custom-scrollbars 2022-11-13 17:54:35 -08:00
Mark McDowall
8c1fb31b5d Fixed: Searching for monitored episodes in series when all seasons are unmonitored 2022-11-12 11:58:57 -08:00
Mark McDowall
b3fc905481 Fixed: Parsing of some Anime releases with number at the end of the title 2022-11-12 11:25:47 -08:00
Mark McDowall
381d642593 Added react-hooks lint rules 2022-11-12 11:25:47 -08:00
Mark McDowall
b1962c7366 Pin yarn version with volta 2022-11-12 11:25:42 -08:00
Mark McDowall
0e31281828 Fixed: Testing SABnzbd when no categories are configured 2022-11-07 18:58:40 -08:00
Qstick
5e57ffbcf9 New: Base API info endpoint 2022-11-06 17:50:02 -06:00
Qstick
28df29ae8a Fix FFProbe issues with x264/x265 files 2022-11-06 17:48:59 -06:00
jaja123456789
0844cfb635 Fixed: File Size in Custom Formats 2022-11-06 08:39:22 -08:00
bakerboy448
2fb5655789 New: Add Notifiarr connection 2022-11-06 08:23:51 -08:00
Devin Buhl
e5d6e569cf New: Send additional information with Webhook and Custom Scripts
Closes #5059
2022-11-06 08:21:28 -08:00
luz paz
209a250079 Fix various typos
Found via `codespell -q 3`
2022-11-06 08:19:07 -08:00
Qstick
fe476a319e Fixed: Truncate custom format card tags 2022-11-04 11:27:39 -05:00
Qstick
fbc258c092 Fixed: Tag details fails for release profiles with tags 2022-11-04 11:09:59 -05:00
Qstick
25eb0ba816 API Docs update 2022-11-04 10:45:47 -05:00
Qstick
db77c90724 Bump FFProbe for DTS-ES fix 2022-11-04 10:42:51 -05:00
Mark McDowall
26eab7d821 Fixed: Re-downloading of series images
Closes #5209
2022-10-26 17:06:53 -07:00
Dtaggart
00d467314b New: Add indexer name to the download report log 2022-10-17 10:19:26 -07:00
Chris
d1f2a8a948 Fixed: Cleanse Discord Webhook URLs
Closes #5169
2022-10-16 07:42:33 -08:00
Zak Saunders
9e457c25c3 Fix light theme variable 2022-10-16 07:40:58 -08:00
Qstick
88e993001b fixup UpdateService tests 2022-10-15 20:46:10 -05:00
Qstick
47116ea663 New: Include MediaInfo / CF for Webhooks
Fixes #5166
2022-10-15 14:19:05 -05:00
Qstick
4fc043bb72 fix test for update client exe 2022-10-15 13:58:21 -05:00
Qstick
a6ce1ee64c Fixed: Episode title not showing in Cutoff Unmet 2022-10-15 11:35:26 -05:00
Qstick
a645681cc8 Clean dual target code 2022-10-15 10:54:38 -05:00
Qstick
2bf87691bc Fixed: Updater version number logging 2022-10-15 10:15:11 -05:00
Mark McDowall
9458f4c796 Fixed interface name after half baked rename 2022-10-03 18:44:07 -07:00
Bakerboy448
238885371b New: Include CustomFormats for CustomScript on Grab 2022-10-03 10:18:14 -07:00
Bakerboy448
77a7f3ef4f New: Include MediaInfo for CustomScripts OnDownload 2022-10-03 10:18:14 -07:00
bakerboy448
7cd38bba84 Fixed: Improve RarBG Error Handling 2022-10-03 10:17:24 -07:00
Stevie Robinson
743d28b93a Fixed: updated rTorrent download client note 2022-10-03 10:16:46 -07:00
Ultimate
092186dab2 New: Custom import lists
Co-authored-by: TheUltimateCoder <no@e.mail>
2022-10-03 10:15:45 -07:00
Mark McDowall
2a7e2674b7 New: Parse more WEB release names 2022-09-25 21:01:56 -07:00
Mark McDowall
97ad6682f7 Re-order frontend build steps 2022-09-25 00:36:09 -07:00
Mark McDowall
3993ca9ebd New: Parse more BDRemux release names
Closes #5094
2022-09-25 00:26:36 -07:00
Mark McDowall
e9123982f3 New: Parse anime version with a space before 'v'
Closes #5103
2022-09-25 00:17:30 -07:00
Mark McDowall
00dd721d9b New: Parsing of GM-Team releases
Closes #5080
2022-09-25 00:00:37 -07:00
Mark McDowall
6f5467e39e Fixed: Indexer tags
Closes #5150
2022-09-24 23:28:04 -07:00
Mark McDowall
bd937b9dd3 Fixed: Fall back to sorting by release title if series is not matched
Closes #5151
2022-09-24 22:57:07 -07:00
Mark McDowall
80dd4ce3a1 Fixed Slovak language parsing test 2022-09-24 22:54:22 -07:00
Chromo-residuum-opec
d2a23f7bcd Update help text for rTorrent download client options 2022-09-22 09:51:16 -07:00
bakerboy448
04447d9d4d Fixed: Repack Preference Ignored 2022-09-22 09:49:19 -07:00
Stevie Robinson
c98fac65ed New: Torrent Seed Ratio no longer advance settings 2022-09-22 09:48:29 -07:00
Stevie Robinson
96345c0a0b Fixed: Remove non-functional filters for Trakt Lists
Co-authored-by: Qstick <qstick@gmail.com>
2022-09-22 09:48:03 -07:00
Gylesie
3477dfacd0 New: Add Slovak Language 2022-09-22 09:47:19 -07:00
Chris
f6e6bc98f7 Added: Ntfy provider for notifications 2022-09-22 09:46:26 -07:00
Robert Dailey
51eeb4ee0f Fixed: Better error messaging if you try to import an invalid Custom Format 2022-09-22 09:44:45 -07:00
Stevie Robinson
e742eb49d7 Update blocklist help text 2022-09-22 09:42:36 -07:00
Qstick
29d8dc81ca Fixed: Avoid iso-mapping failure with Dutch/Flemish 2022-09-17 21:22:31 -05:00
Qstick
56bb87e55f Clean movie references 2022-09-17 21:20:58 -05:00
Mark McDowall
93bd8543b1 Fixed: Ping plex.tv to keep auth token active
Closes #5154
2022-09-17 17:43:33 -07:00
Mark McDowall
6eed7c8fed Handle redirects for 308 redirects 2022-09-17 17:43:33 -07:00
Mark McDowall
67cf95f6c2 Fixed: Settings page description for Metadata Source
Closes #5141
2022-09-17 17:43:33 -07:00
Mark McDowall
9c73786251 Fixed: Series list jump bar click issues 2022-09-17 17:43:33 -07:00
Mark McDowall
b6417a6f43 Add Volta node config 2022-09-17 17:43:33 -07:00
Mark McDowall
b5439a0661 Improve build pipeline 2022-09-17 17:43:33 -07:00
Qstick
dc44cbcda6 Fixed: Language Augment from Folder and Filename 2022-09-06 19:33:29 -05:00
Qstick
fa1e67a6c8 Fix Language Selection on Manual Import 2022-08-21 13:09:51 -05:00
Qstick
89ee7d4452 Fixed: Fix NullRef in Subtitle Service due to #4924 2022-08-20 17:59:41 -05:00
Qstick
86b895abe0 Fixed: CF Resolution Specification not matching correctly 2022-08-20 17:57:46 -05:00
Mark McDowall
75919cf779 Use correct Branch variable in builds 2022-08-20 15:54:58 -07:00
Mark McDowall
2967c58a4d Set execution bits when packaging builds 2022-08-20 10:29:56 -07:00
Albert Lee
19c9429c7e Fixed: Nyaa episode title search 2022-08-18 23:26:09 -07:00
Mark McDowall
6660e0c3f3 New: Use absolute format if absolute episode number is not required and is missing
Closes #5124
2022-08-18 23:06:49 -07:00
Qstick
89b0b04e08 New: Custom Format Language Condition 2022-08-18 19:52:26 -05:00
Mark McDowall
52760e0908 Don't replace private values that haven't been set 2022-08-15 13:39:24 -07:00
Mark McDowall
549cdbe15a New: Add import date to upgraded episodes in CustomScript and Webhook connections
Closes #3615
2022-08-15 13:31:28 -07:00
Mark McDowall
4b5c8a815f Fixed: Grouped items on calendar ignoring series monitored state
Closes #5117
2022-08-15 13:13:57 -07:00
Mark McDowall
09404bacf3 Build Windows x86 installer 2022-08-12 11:58:04 -07:00
Mark McDowall
ac8f6f339a Metadata attribution for TheTVDB 2022-08-12 00:14:25 -07:00
Mark McDowall
00ab449ebe Fixed: Search for newly added episodes if disk rescanning is disabled after refresh 2022-08-11 17:28:01 -07:00
Mark McDowall
a3e2299011 Debian: Remove mediainfo and mono dependencies 2022-08-08 18:22:36 -07:00
Michael Casey
5938a95abb New: Add UI Localization Framework 2022-08-07 15:24:42 -07:00
Mark McDowall
1977f4aa3c Fixed: Don't process files that don't have a supported media file extension 2022-08-07 15:24:42 -07:00
Mark McDowall
d0efdc6c62 Fixed: Warning for search all 2022-08-07 15:24:42 -07:00
Mark McDowall
1f14276770 Don't block task queue for queued update task when there are longer running tasks executing 2022-08-07 15:24:42 -07:00
Devin Buhl
762042ba97 New: Add application URL to host configuration settings 2022-08-07 15:24:42 -07:00
Qstick
18f77a967b New: API Docs 2022-08-07 15:24:41 -07:00
Mark McDowall
269e72a219 New: Migrate user passwords to Pbkdf2 2022-08-07 15:24:41 -07:00
Mark McDowall
fe293ff4c3 Fixed Windows installer version 2022-08-07 15:24:41 -07:00
Mark McDowall
652027821d Fixed integration test's path to Sonarr executable 2022-08-07 15:24:41 -07:00
Mark McDowall
90d3dc2f98 FileNameBuilderFixture tests should run on Windows 2022-08-07 15:24:41 -07:00
Mark McDowall
35a5462c8f Build under TeamCity 2022-08-07 15:24:41 -07:00
Mark McDowall
ebe9215057 Remove OMG indexer 2022-08-07 15:24:41 -07:00
Mark McDowall
fbe412d847 Cleanup usages of isMono 2022-08-07 15:24:40 -07:00
Mark McDowall
d3018fb501 New: Authentication is now required 2022-08-07 15:24:40 -07:00
Mark McDowall
570be88215 New: Don't return API Keys and Passwords via the API 2022-08-07 15:24:40 -07:00
Mark McDowall
b154b00c61 New: Setting to disable authentication for local addresses 2022-08-07 15:24:40 -07:00
Mark McDowall
05ee4e6449 Sliding expiration for auth cookie and a little clean up 2022-08-07 15:24:40 -07:00
Qstick
b04b4000b8 New: Custom Formats
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:40 -07:00
Qstick
909af6c874 New: Frontend Package and Lint Updates 2022-08-07 15:24:39 -07:00
Qstick
2291f3e00e New: Native Theme Engine
Co-Authored-By: Zak Saunders <thezak48@users.noreply.github.com>
2022-08-07 15:24:38 -07:00
Marty Zalega
e1de523c89 Don't lowercase UrlBase in ConfigFileProvider
UrlBase should honour the case it is given.
2022-08-07 15:24:38 -07:00
Qstick
fa0fc3158b New: MediaInfo -> FFProbe
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:38 -07:00
Qstick
a4232549cb Fix Tray App and Windows Server Restart
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:38 -07:00
Qstick
e65aebdcf8 New: Use native .NET6 socks proxy
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:37 -07:00
Qstick
4c0fe62dda Use modern HttpClient
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:37 -07:00
ta264
bff1fe7890 Update to nugets with osx-arm64 runtimes 2022-08-07 15:24:37 -07:00
Qstick
1169741c54 New: Use ASP.NET Core instead of Nancy
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:37 -07:00
Qstick
b83bb2cade Fixed: Pending Releases Migration 2022-08-07 15:24:36 -07:00
Qstick
f50b54b3f6 New: Use System.Text.Json for Nancy and SignalR
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:36 -07:00
Qstick
2e953a0eb1 Dapper and STJson
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:24:36 -07:00
Qstick
1c22a1ec0d StyleCop 2022-08-07 15:24:35 -07:00
Qstick
878d1561aa Build Sonarr on Net6
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:46 -07:00
Qstick
f79ae77a3a New: Switch to ASPNetCore Kestrel and SignalR
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:43 -07:00
Qstick
4d007855bc Bump NLog to 4.7.14 2022-08-07 15:04:43 -07:00
Qstick
fd5ac3c713 Upgrade FluentMigrator from 1.6.2 to v3
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:43 -07:00
Qstick
e263331880 Fixed: Remove obsolete HttpProvider
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:43 -07:00
Qstick
78eb8b0e6d Fixed: Remove obsolete XBMC HTTP notification API
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:43 -07:00
Qstick
91c9250d9c Fixed: Remove obsolete Plex HomeTheater/Client notifcations
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:43 -07:00
Qstick
d740e995a3 Cleanup OAuth Dep
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:42 -07:00
Qstick
da5716cca2 Net standard XMLRPC
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:42 -07:00
Qstick
2200b02112 Convert Interop.NetFwTypeLib to AnyCPU
Co-Authored-By: ta264 <ta264@users.noreply.github.com>
2022-08-07 15:04:42 -07:00
Qstick
f7c771f467 Use Sqlite from Servarr 2022-08-07 15:04:42 -07:00
Qstick
52d2a5010a Purge Logentries 2022-08-07 15:04:42 -07:00
Qstick
b4ca4908fc Purge V2 API 2022-08-07 15:04:42 -07:00
Qstick
fdecd1fea4 Switch Integration Tests to V3 API 2022-08-07 15:04:42 -07:00
Qstick
b819246655 Revert "New: Updated MediaInfo to 21.09, Sqlite to 3.32.1.0 and added support for mac osx arm64 arch. Deprecated osx x86."
This reverts commit 201004113e.
2022-08-07 15:04:42 -07:00
bakerboy448
c7919f80de Fixed: Improve WebDL and WebRip Parsing 2022-08-07 13:43:04 -07:00
David Newhall
1a1d427c42 Fixed: Logging when series folder is moved successfully 2022-08-07 12:03:27 -07:00
bakerboy448
9263fc1564 New: Improve messaging for rejected quality upgrades 2022-08-07 11:54:15 -07:00
Kevin Richter
8ab040f612 Fixed: Improve moving file to location where another one exists 2022-08-07 11:52:54 -07:00
Dominik Krivohlavek
d6dff451e0 New: Preserve language tags when importing subtitle files
Closes #2570
Closes #3278
2022-08-07 11:47:14 -07:00
C.J. Manca
ac7afc351c New: Add maximum single episode age option (per indexer) 2022-08-07 11:43:18 -07:00
4020 changed files with 112853 additions and 79046 deletions

View File

@@ -2,14 +2,273 @@
# editorconfig.org
root = true
[*.{cs}]
# NOTE: Requires **VS2019 16.3** or later
# Stylecop.ruleset
# Description: Rules for Sonarr
# Code files
[*.cs]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 4
[*.{js,html,js,hbs,less,css}]
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:refactoring
dotnet_style_qualification_for_property = false:refactoring
dotnet_style_qualification_for_method = false:refactoring
dotnet_style_qualification_for_event = false:refactoring
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
# Prefer "var" everywhere
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
csharp_style_var_elsewhere = true
# Prefer "out" variables to be declared inline
csharp_style_inlined_variable_declaration = true
# Using directive is unnecessary.
dotnet_diagnostic.IDE0005.severity = error
# Use var instead of explicit type
dotnet_diagnostic.IDE0007.severity = error
# Inline variable declaration
dotnet_diagnostic.IDE0018.severity = error
# Stylecop Rules
dotnet_diagnostic.SA0001.severity = none
dotnet_diagnostic.SA1025.severity = none
dotnet_diagnostic.SA1101.severity = none
dotnet_diagnostic.SA1116.severity = none
dotnet_diagnostic.SA1118.severity = none
dotnet_diagnostic.SA1122.severity = none
dotnet_diagnostic.SA1201.severity = suggestion
dotnet_diagnostic.SA1202.severity = suggestion
dotnet_diagnostic.SA1204.severity = suggestion
dotnet_diagnostic.SA1300.severity = none
dotnet_diagnostic.SA1303.severity = none
dotnet_diagnostic.SA1304.severity = none
dotnet_diagnostic.SA1306.severity = none
dotnet_diagnostic.SA1309.severity = none
dotnet_diagnostic.SA1310.severity = none
dotnet_diagnostic.SA1401.severity = none
dotnet_diagnostic.SA1402.severity = none
dotnet_diagnostic.SA1404.severity = suggestion
dotnet_diagnostic.SA1405.severity = suggestion
dotnet_diagnostic.SA1406.severity = suggestion
dotnet_diagnostic.SA1410.severity = suggestion
dotnet_diagnostic.SA1411.severity = suggestion
dotnet_diagnostic.SA1413.severity = none
dotnet_diagnostic.SA1512.severity = none
dotnet_diagnostic.SA1516.severity = none
dotnet_diagnostic.SA1600.severity = none
dotnet_diagnostic.SA1601.severity = none
dotnet_diagnostic.SA1602.severity = none
dotnet_diagnostic.SA1604.severity = none
dotnet_diagnostic.SA1605.severity = none
dotnet_diagnostic.SA1606.severity = none
dotnet_diagnostic.SA1607.severity = none
dotnet_diagnostic.SA1608.severity = none
dotnet_diagnostic.SA1610.severity = none
dotnet_diagnostic.SA1611.severity = none
dotnet_diagnostic.SA1612.severity = none
dotnet_diagnostic.SA1613.severity = none
dotnet_diagnostic.SA1614.severity = none
dotnet_diagnostic.SA1615.severity = none
dotnet_diagnostic.SA1616.severity = none
dotnet_diagnostic.SA1617.severity = none
dotnet_diagnostic.SA1618.severity = none
dotnet_diagnostic.SA1619.severity = none
dotnet_diagnostic.SA1620.severity = none
dotnet_diagnostic.SA1621.severity = none
dotnet_diagnostic.SA1622.severity = none
dotnet_diagnostic.SA1623.severity = none
dotnet_diagnostic.SA1624.severity = none
dotnet_diagnostic.SA1625.severity = none
dotnet_diagnostic.SA1626.severity = none
dotnet_diagnostic.SA1627.severity = none
dotnet_diagnostic.SA1629.severity = none
dotnet_diagnostic.SA1633.severity = none
dotnet_diagnostic.SA1634.severity = none
dotnet_diagnostic.SA1635.severity = none
dotnet_diagnostic.SA1636.severity = none
dotnet_diagnostic.SA1637.severity = none
dotnet_diagnostic.SA1638.severity = none
dotnet_diagnostic.SA1640.severity = none
dotnet_diagnostic.SA1641.severity = none
dotnet_diagnostic.SA1642.severity = none
dotnet_diagnostic.SA1643.severity = none
dotnet_diagnostic.SA1648.severity = none
dotnet_diagnostic.SA1649.severity = none
dotnet_diagnostic.SA1651.severity = none
dotnet_diagnostic.SX1309.severity = warning
# Microsoft Analyzers that fail and need to be sorted thru
dotnet_diagnostic.ASP0000.severity = suggestion
dotnet_diagnostic.CA1000.severity = suggestion
dotnet_diagnostic.CA1001.severity = suggestion
dotnet_diagnostic.CA1002.severity = suggestion
dotnet_diagnostic.CA1003.severity = suggestion
dotnet_diagnostic.CA1008.severity = suggestion
dotnet_diagnostic.CA1010.severity = suggestion
dotnet_diagnostic.CA1012.severity = suggestion
dotnet_diagnostic.CA1014.severity = suggestion
dotnet_diagnostic.CA1016.severity = suggestion
dotnet_diagnostic.CA1017.severity = suggestion
dotnet_diagnostic.CA1018.severity = suggestion
dotnet_diagnostic.CA1019.severity = suggestion
dotnet_diagnostic.CA1021.severity = suggestion
dotnet_diagnostic.CA1024.severity = suggestion
dotnet_diagnostic.CA1027.severity = suggestion
dotnet_diagnostic.CA1028.severity = suggestion
dotnet_diagnostic.CA1030.severity = suggestion
dotnet_diagnostic.CA1031.severity = suggestion
dotnet_diagnostic.CA1032.severity = suggestion
dotnet_diagnostic.CA1033.severity = suggestion
dotnet_diagnostic.CA1034.severity = suggestion
dotnet_diagnostic.CA1036.severity = suggestion
dotnet_diagnostic.CA1040.severity = suggestion
dotnet_diagnostic.CA1041.severity = suggestion
dotnet_diagnostic.CA1043.severity = suggestion
dotnet_diagnostic.CA1044.severity = suggestion
dotnet_diagnostic.CA1050.severity = suggestion
dotnet_diagnostic.CA1051.severity = suggestion
dotnet_diagnostic.CA1052.severity = suggestion
dotnet_diagnostic.CA1054.severity = suggestion
dotnet_diagnostic.CA1055.severity = suggestion
dotnet_diagnostic.CA1056.severity = suggestion
dotnet_diagnostic.CA1058.severity = suggestion
dotnet_diagnostic.CA1060.severity = suggestion
dotnet_diagnostic.CA1061.severity = suggestion
dotnet_diagnostic.CA1062.severity = suggestion
dotnet_diagnostic.CA1063.severity = suggestion
dotnet_diagnostic.CA1064.severity = suggestion
dotnet_diagnostic.CA1065.severity = suggestion
dotnet_diagnostic.CA1066.severity = suggestion
dotnet_diagnostic.CA1067.severity = suggestion
dotnet_diagnostic.CA1068.severity = suggestion
dotnet_diagnostic.CA1069.severity = suggestion
dotnet_diagnostic.CA1200.severity = suggestion
dotnet_diagnostic.CA1303.severity = suggestion
dotnet_diagnostic.CA1304.severity = suggestion
dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1308.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = suggestion
dotnet_diagnostic.CA1401.severity = suggestion
dotnet_diagnostic.CA1416.severity = suggestion
dotnet_diagnostic.CA1419.severity = suggestion
dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1508.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1710.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
dotnet_diagnostic.CA1712.severity = suggestion
dotnet_diagnostic.CA1714.severity = suggestion
dotnet_diagnostic.CA1715.severity = suggestion
dotnet_diagnostic.CA1716.severity = suggestion
dotnet_diagnostic.CA1717.severity = suggestion
dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1721.severity = suggestion
dotnet_diagnostic.CA1724.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1806.severity = suggestion
dotnet_diagnostic.CA1810.severity = suggestion
dotnet_diagnostic.CA1812.severity = suggestion
dotnet_diagnostic.CA1813.severity = suggestion
dotnet_diagnostic.CA1814.severity = suggestion
dotnet_diagnostic.CA1815.severity = suggestion
dotnet_diagnostic.CA1816.severity = suggestion
dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion
dotnet_diagnostic.CA2008.severity = suggestion
dotnet_diagnostic.CA2012.severity = suggestion
dotnet_diagnostic.CA2013.severity = suggestion
dotnet_diagnostic.CA2100.severity = suggestion
dotnet_diagnostic.CA2101.severity = suggestion
dotnet_diagnostic.CA2119.severity = suggestion
dotnet_diagnostic.CA2153.severity = suggestion
dotnet_diagnostic.CA2200.severity = suggestion
dotnet_diagnostic.CA2201.severity = suggestion
dotnet_diagnostic.CA2207.severity = suggestion
dotnet_diagnostic.CA2208.severity = suggestion
dotnet_diagnostic.CA2211.severity = suggestion
dotnet_diagnostic.CA2213.severity = suggestion
dotnet_diagnostic.CA2214.severity = suggestion
dotnet_diagnostic.CA2215.severity = suggestion
dotnet_diagnostic.CA2216.severity = suggestion
dotnet_diagnostic.CA2219.severity = suggestion
dotnet_diagnostic.CA2225.severity = suggestion
dotnet_diagnostic.CA2226.severity = suggestion
dotnet_diagnostic.CA2227.severity = suggestion
dotnet_diagnostic.CA2229.severity = suggestion
dotnet_diagnostic.CA2231.severity = suggestion
dotnet_diagnostic.CA2234.severity = suggestion
dotnet_diagnostic.CA2235.severity = suggestion
dotnet_diagnostic.CA2237.severity = suggestion
dotnet_diagnostic.CA2241.severity = suggestion
dotnet_diagnostic.CA2242.severity = suggestion
dotnet_diagnostic.CA2243.severity = suggestion
dotnet_diagnostic.CA2244.severity = suggestion
dotnet_diagnostic.CA2245.severity = suggestion
dotnet_diagnostic.CA2246.severity = suggestion
dotnet_diagnostic.CA2249.severity = suggestion
dotnet_diagnostic.CA2251.severity = suggestion
dotnet_diagnostic.CA3061.severity = suggestion
dotnet_diagnostic.CA3075.severity = suggestion
dotnet_diagnostic.CA3076.severity = suggestion
dotnet_diagnostic.CA3077.severity = suggestion
dotnet_diagnostic.CA3147.severity = suggestion
dotnet_diagnostic.CA5350.severity = suggestion
dotnet_diagnostic.CA5351.severity = suggestion
dotnet_diagnostic.CA5359.severity = suggestion
dotnet_diagnostic.CA5360.severity = suggestion
dotnet_diagnostic.CA5363.severity = suggestion
dotnet_diagnostic.CA5364.severity = suggestion
dotnet_diagnostic.CA5365.severity = suggestion
dotnet_diagnostic.CA5366.severity = suggestion
dotnet_diagnostic.CA5368.severity = suggestion
dotnet_diagnostic.CA5369.severity = suggestion
dotnet_diagnostic.CA5370.severity = suggestion
dotnet_diagnostic.CA5371.severity = suggestion
dotnet_diagnostic.CA5372.severity = suggestion
dotnet_diagnostic.CA5373.severity = suggestion
dotnet_diagnostic.CA5374.severity = suggestion
dotnet_diagnostic.CA5379.severity = suggestion
dotnet_diagnostic.CA5384.severity = suggestion
dotnet_diagnostic.CA5385.severity = suggestion
dotnet_diagnostic.CA5392.severity = suggestion
dotnet_diagnostic.CA5394.severity = suggestion
dotnet_diagnostic.CA5397.severity = suggestion
dotnet_diagnostic.SYSLIB0006.severity = none
[*.{js,html,hbs,less,css,ts,tsx}]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@@ -1,9 +0,0 @@
{
"paths": [
"frontend/src/**/*.js"
],
"ignored": [
"**/node_modules/**/*"
],
"port": 5004
}

View File

@@ -1,13 +1,13 @@
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. Exceptions do not mean you found a bug!'
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. Sonarr v2 is EOL & unsupported.'
labels: ['needs-triage']
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and it is closed as complete it may not yet be in a stable release.
options:
- label: I have searched the existing issues
- label: I have searched the existing open and closed issues
required: true
- type: textarea
attributes:
@@ -42,12 +42,14 @@ body:
- **Docker Install**: Yes
- **Using Reverse Proxy**: No
- **Browser**: Firefox 90 (If UI related)
- **Database**: Sqlite 3.41.2
value: |
- OS:
- Sonarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
- Sonarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
- Database:
render: markdown
validations:
required: true
@@ -74,9 +76,6 @@ body:
label: Anything else?
description: |
Links? Screenshots? References? Anything that will give us more context about the issue you are encountering!
***Generally speaking, all bug reports must have trace logs provided.***
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: true
required: true
required: false

View File

@@ -5,9 +5,9 @@ body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the feature you are requesting.
description: Please search to see if an open or closed issue already exists for the feature you are requesting. If a feature request exists and it is closed as complete it may not yet be in a stable release.
options:
- label: I have searched the existing issues
- label: I have searched the existing open and closed issues
required: true
- type: textarea
attributes:
@@ -32,7 +32,6 @@ body:
label: Anything else?
description: |
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: true
required: false

7
.github/SUPPORT.md vendored
View File

@@ -1,7 +0,0 @@
## Support
There are a number of frequently asked questions that have been answered in our [FAQ](https://wiki.servarr.com/sonarr/faq)
The [wiki](https://wiki.servarr.com/sonarr) contains other information and guides
Please use one of the support channels: [forums](https://forums.sonarr.tv/), [subreddit](https://www.reddit.com/r/sonarr/), [discord ](https://discord.gg/M6BvZn5), or [IRC](https://web.libera.chat/?channels=#sonarr)for support/questions.

17
.github/labeler.yml vendored Normal file
View File

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

58
.github/workflows/api_docs.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: 'API Docs'
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 1'
push:
branches:
- develop
paths:
- ".github/workflows/api_docs.yml"
- "docs.sh"
- "src/Sonarr.Api.*/**"
- "src/Sonarr.Http/**"
- "src/**/*.csproj"
- "src/*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
api_docs:
runs-on: ubuntu-latest
if: github.repository == 'Sonarr/Sonarr'
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- name: Setup dotnet
uses: actions/setup-dotnet@v3
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
- name: Commit API Docs Change
continue-on-error: true
run: |
git config --global user.email "development@sonarr.tv"
git config --global user.name "Sonarr"
git checkout -b api-docs
git add src
if git status | grep -q modified
then
git commit -am 'Automated API Docs update' -m "ignore-downstream"
git push -f --set-upstream origin api-docs
curl -X POST -H "Authorization: Bearer ${{ secrets.OPENAPI_PAT }}" -H "Accept: application/vnd.github+json" https://api.github.com/repos/sonarr/sonarr/pulls -d '{"head":"api-docs","base":"develop","title":"Update API docs"}'
else
echo "No changes since last run"
fi

12
.github/workflows/labeler.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4

25
.gitignore vendored
View File

@@ -84,7 +84,6 @@ TestResults
[Tt]est[Rr]esult*
*.Cache
ClientBin
[Ss]tyle[Cc]op.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
@@ -117,28 +116,48 @@ src/UI/.idea/*
*log.txt
node_modules/
_output*
_artifacts
_rawPackage/
_dotTrace*
_tests*
_publish*
_temp*
*.Result.xml
coverage*.xml
coverage*.json
setup/Output/
*.~is
UI/
#VS outout folders
bin
obj
output/*
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# Packages
Sonarr_*/
Sonarr_*.zip
Sonarr_*.gz
gecko.zip
geckodriver.exe
#OS X metadata files
._*
.DS_Store
_start
_temp_*/**/*
# Windows thumbnail cache files
Thumbs.db
src/.idea/
/distribution/windows/setup/output/*
# API doc generation
.config/

View File

@@ -1,5 +1,10 @@
# <img width="24px" src="./Logo/256.png" alt="Sonarr"></img> Sonarr
[![Translated](https://translate.servarr.com/widgets/servarr/-/sonarr/svg-badge.svg)](https://translate.servarr.com/engage/servarr/)
[![Backers on Open Collective](https://opencollective.com/Sonarr/backers/badge.svg)](#backers)
[![Sponsors on Open Collective](https://opencollective.com/Sonarr/sponsors/badge.svg)](#sponsors)
[![Mega Sponsors on Open Collective](https://opencollective.com/Sonarr/megasponsors/badge.svg)](#mega-sponsors)
Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
## Getting Started
@@ -7,10 +12,11 @@ Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS fee
- [Download/Installation](https://sonarr.tv/#downloads-v3)
- [FAQ](https://wiki.servarr.com/sonarr/faq)
- [Wiki](https://wiki.servarr.com/Sonarr)
- [(WIP) API Documentation](https://github.com/Sonarr/Sonarr/wiki/API)
- [v4 Beta API Documentation](https://sonarr.tv/docs/api)
- [Donate](https://sonarr.tv/donate)
## Support
Note: GitHub Issues are for Bugs and Feature Requests Only
- [Forums](https://forums.sonarr.tv/)
@@ -20,8 +26,6 @@ Note: GitHub Issues are for Bugs and Feature Requests Only
- [Reddit](https://www.reddit.com/r/sonarr)
- [Wiki](https://wiki.servarr.com/sonarr)
## Features
### Current Features
@@ -41,6 +45,7 @@ Note: GitHub Issues are for Bugs and Feature Requests Only
## Contributing
### Development
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
<a href="https://github.com/Sonarr/Sonarr/graphs/contributors"><img src="https://opencollective.com/Sonarr/contributors.svg?width=890&button=false" /></a>
@@ -73,4 +78,4 @@ Thank you to [<img src="/Logo/Jetbrains/jetbrains.svg" alt="JetBrains" width="32
### Licenses
- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2021
- Copyright 2010-2023

9
SECURITY.md Normal file
View File

@@ -0,0 +1,9 @@
# Security Policy
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities on Discord (preferred) to
either markus101
#2148 or Taloth#7357 or via email: security@sonarr.tv. You will receive a response from
us within 72 hours. If the issue is confirmed, we will release a patch as soon
as possible depending on complexity/severity.

679
build.sh
View File

@@ -1,125 +1,60 @@
#! /bin/bash
msBuildVersion='15.0'
outputFolder='./_output'
outputFolderWindows='./_output_windows'
outputFolderLinux='./_output_linux'
outputFolderMacOS='./_output_macos'
outputFolderMacOSApp='./_output_macos_app'
testPackageFolder='./_tests'
testPackageFolderWindows='./_tests_windows'
testPackageFolderLinux='./_tests_linux'
sourceFolder='./src'
slnFile=$sourceFolder/Sonarr.sln
updateSubFolder=Sonarr.Update
#! /usr/bin/env bash
set -e
sqlitePackageDir="$HOME/.nuget/packages/system.data.sqlite.core.servarr/1.0.115.5-18"
nuget='tools/nuget/nuget.exe';
vswhere='tools/vswhere/vswhere.exe';
macho='tools/macho/MachOConverter.exe';
. ./version.sh
CheckExitCode()
{
"$@"
local status=$?
if [ $status -ne 0 ]; then
echo "error with $1" >&2
exit 1
fi
return $status
}
outputFolder='_output'
testPackageFolder='_tests'
artifactsFolder="_artifacts";
ProgressStart()
{
echo "##teamcity[blockOpened name='$1']"
echo "##teamcity[progressStart '$1']"
echo "Start '$1'"
}
ProgressEnd()
{
echo "Finish '$1'"
echo "##teamcity[progressFinish '$1']"
echo "##teamcity[blockClosed name='$1']"
}
UpdateVersionNumber()
{
if [ "$BUILD_NUMBER" != "" ]; then
echo "Updating Version Info"
verMajorMinorRevision=`echo "$buildVersion" | cut -d. -f1,2,3`
verBuild=`echo "${BUILD_NUMBER}" | cut -d. -f4`
BUILD_NUMBER=$verMajorMinorRevision.$verBuild
echo "##teamcity[buildNumber '$BUILD_NUMBER']"
sed -i "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$BUILD_NUMBER<\/AssemblyVersion>/g" ./src/Directory.Build.props
sed -i "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BRANCH:-dev}<\/AssemblyConfiguration>/g" ./src/Directory.Build.props
if [ "$SONARR_VERSION" != "" ]; then
echo "Updating version info to: $SONARR_VERSION"
sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$SONARR_VERSION<\/AssemblyVersion>/g" src/Directory.Build.props
sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BRANCH}<\/AssemblyConfiguration>/g" src/Directory.Build.props
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$SONARR_VERSION<\/string>/g" distribution/macOS/Sonarr.app/Contents/Info.plist
fi
}
CreateReleaseInfo()
EnableExtraPlatformsInSDK()
{
if [ "$BUILD_NUMBER" != "" ]; then
echo "Create Release Info"
echo -e "# Do Not Edit\nReleaseVersion=$BUILD_NUMBER\nBranch=${BRANCH:-dev}" > $outputFolder/release_info
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if grep -q freebsd-x64 "$BUNDLEDVERSIONS"; then
echo "Extra platforms already enabled"
else
echo "Enabling extra platform support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' "$BUNDLEDVERSIONS"
fi
}
CleanFolder()
EnableExtraPlatforms()
{
local path=$1
local keepConfigFiles=$2
find $path -name "*.transform" -exec rm "{}" \;
if [ $keepConfigFiles != true ] ; then
find $path -name "*.dll.config" -exec rm "{}" \;
if grep -qv freebsd-x64 src/Directory.Build.props; then
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
fi
echo "Removing FluentValidation.Resources files"
find $path -name "FluentValidation.resources.dll" -exec rm "{}" \;
find $path -name "App.config" -exec rm "{}" \;
echo "Removing vshost files"
find $path -name "*.vshost.exe" -exec rm "{}" \;
echo "Removing dylib files"
find $path -name "*.dylib" -exec rm "{}" \;
echo "Removing Empty folders"
find $path -depth -empty -type d -exec rm -r "{}" \;
}
BuildWithMSBuild()
{
msBuildPath=`$vswhere -latest -products \* -requires Microsoft.Component.MSBuild -find MSBuild\\\\\*\*\\\\Bin\\\\MSBuild.exe`
msBuildPath=${msBuildPath/C:\\/\/c\/}
msBuildPath=${msBuildPath//\\/\/}
msBuildDir=$(dirname "$msBuildPath")
echo $msBuildDir
export PATH=$msBuildDir:$PATH
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Clean //m
$nuget restore $slnFile
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Build //m //p:AllowedReferenceRelatedFileExtensions=.pdb
}
BuildWithXbuild()
{
export MONO_IOMAP=case
CheckExitCode msbuild /t:Clean $slnFile
mono $nuget restore $slnFile
CheckExitCode msbuild /p:Configuration=Release /p:Platform=x86 /t:Build /p:AllowedReferenceRelatedFileExtensions=.pdb $slnFile
}
LintUI()
{
ProgressStart 'ESLint'
CheckExitCode yarn lint
yarn lint
ProgressEnd 'ESLint'
ProgressStart 'Stylelint'
CheckExitCode yarn stylelint
yarn stylelint
ProgressEnd 'Stylelint'
}
@@ -130,348 +65,392 @@ Build()
rm -rf $outputFolder
rm -rf $testPackageFolder
if [ $runtime = "dotnet" ] ; then
BuildWithMSBuild
slnFile=src/Sonarr.sln
if [ $os = "windows" ]; then
platform=Windows
else
BuildWithXbuild
platform=Posix
fi
CleanFolder $outputFolder false
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
echo "Removing Sonarr.Update/sqlite3.dll"
rm $outputFolder/Sonarr.Update/sqlite3.dll
echo "Removing Mono.Posix.dll"
rm $outputFolder/Mono.Posix.dll
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -t:PublishAllRids
else
dotnet msbuild -restore $slnFile -p:Configuration=Release -p:Platform=$platform -p:RuntimeIdentifiers=$RID -t:PublishAllRids
fi
ProgressEnd 'Build'
}
RunWebpack()
YarnInstall()
{
ProgressStart 'yarn install'
yarn install
yarn install --frozen-lockfile --network-timeout 120000
ProgressEnd 'yarn install'
}
LintUI
RunWebpack()
{
ProgressStart 'Running webpack'
CheckExitCode yarn run build --env production
yarn run build --env production
ProgressEnd 'Running webpack'
}
CreateMdbs()
PackageFiles()
{
local path=$1
if [ $runtime = "dotnet" ] ; then
local pdbFiles=( $(find $path -name "*.pdb") )
for filename in "${pdbFiles[@]}"
do
if [ -e ${filename%.pdb}.dll ] ; then
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.dll
fi
if [ -e ${filename%.pdb}.exe ] ; then
tools/pdb2mdb/pdb2mdb.exe ${filename%.pdb}.exe
fi
done
local folder="$1"
local framework="$2"
local runtime="$3"
rm -rf $folder
mkdir -p $folder
cp -r $outputFolder/$framework/$runtime/publish/* $folder
cp -r $outputFolder/Sonarr.Update/$framework/$runtime/publish $folder/Sonarr.Update
if [ "$FRONTEND" = "YES" ];
then
cp -r $outputFolder/UI $folder
fi
echo "Adding LICENSE"
cp LICENSE.md $folder
}
PatchMono()
PackageLinux()
{
local path=$1
local framework="$1"
local runtime="$2"
# Below we deal with some mono incompatibilities with windows-only dotnet core/standard libs
# See: https://github.com/mono/mono/blob/master/tools/nuget-hash-extractor/download.sh
# That list defines assemblies that are prohibited from being loaded from the appdir, instead loading from mono GAC.
ProgressStart "Creating $runtime Package for $framework"
# We have debian dependencies to get these installed or facades from mono 5.10+
for assembly in System.IO.Compression System.Runtime.InteropServices.RuntimeInformation System.Net.Http System.Globalization.Extensions System.Text.Encoding.CodePages System.Threading.Overlapped
do
if [ -e $path/$assembly.dll ]; then
if [ -e $sourceFolder/Libraries/Mono/$assembly.dll ]; then
echo "Copy Mono-specific facade $assembly.dll (uses win32 interop)"
cp $sourceFolder/Libraries/Mono/$assembly.dll $path/$assembly.dll
else
echo "Remove $assembly.dll (uses win32 interop)"
rm $path/$assembly.dll
fi
fi
done
local folder=$artifactsFolder/$runtime/$framework/Sonarr
# Copy more stable version of Vectors for mono <5.12
if [ -e $path/System.Numerics.Vectors.dll ]; then
packageDir="$HOME/.nuget/packages/system.numerics.vectors/4.5.0"
if [ ! -d "$HOME/.nuget/packages/system.numerics.vectors/4.5.0" ]; then
# May reside in the NuGetFallback folder, which is harder to find
# Download somewhere to get the real cache populated
if [ $runtime = "dotnet" ] ; then
$nuget install System.Numerics.Vectors -Version 4.5.0 -Output ./_temp/System.Numerics.Vectors
else
mono $nuget install System.Numerics.Vectors -Version 4.5.0 -Output ./_temp/System.Numerics.Vectors
fi
rm -rf ./_temp/System.Numerics.Vectors
fi
# Copy the netstandard2.0 version rather than net46
cp "$packageDir/lib/netstandard2.0/System.Numerics.Vectors.dll" $path/
fi
}
PackageMono()
{
ProgressStart 'Creating Mono Package'
rm -rf $outputFolderLinux
echo "Copying Binaries"
cp -r $outputFolder $outputFolderLinux
echo "Creating MDBs"
CreateMdbs $outputFolderLinux
echo "Removing PDBs"
find $outputFolderLinux -name "*.pdb" -exec rm "{}" \;
PackageFiles "$folder" "$framework" "$runtime"
echo "Removing Service helpers"
rm -f $outputFolderLinux/ServiceUninstall.*
rm -f $outputFolderLinux/ServiceInstall.*
echo "Removing native windows binaries Sqlite, MediaInfo"
rm -f $outputFolderLinux/sqlite3.*
rm -f $outputFolderLinux/Sonarr.Update/sqlite3.*
rm -f $outputFolderLinux/MediaInfo.*
PatchMono $outputFolderLinux
echo "Adding Sonarr.Core.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Core/Sonarr.Core.dll.config $outputFolderLinux
# Remove Http binding redirect by renaming it
# We don't need this anymore once our minimum mono version is 5.10
sed -i "s/System.Net.Http/System.Net.Http.Mono/g" $outputFolderLinux/Sonarr.Console.exe.config
echo "Renaming Sonarr.Console.exe to Sonarr.exe"
rm $outputFolderLinux/Sonarr.exe*
for file in $outputFolderLinux/Sonarr.Console.exe*; do
mv "$file" "${file//.Console/}"
done
rm -f $folder/ServiceUninstall.*
rm -f $folder/ServiceInstall.*
echo "Removing Sonarr.Windows"
rm $outputFolderLinux/Sonarr.Windows.*
rm $folder/Sonarr.Windows.*
echo "Adding Sonarr.Mono to UpdatePackage"
cp $outputFolderLinux/Sonarr.Mono.* $outputFolderLinux/$updateSubFolder/
cp $folder/Sonarr.Mono.* $folder/Sonarr.Update
if [ "$framework" = "net6.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Sonarr.Update
cp $folder/libMonoPosixHelper.* $folder/Sonarr.Update
fi
ProgressEnd 'Creating Mono Package'
ProgressEnd "Creating $runtime Package for $framework"
}
PackageMacOS()
{
ProgressStart 'Creating MacOS Package'
local framework="$1"
local runtime="$2"
rm -rf $outputFolderMacOS
mkdir $outputFolderMacOS
echo "Copying Binaries"
cp -r $outputFolderLinux/* $outputFolderMacOS
ProgressStart "Creating $runtime Package for $framework"
echo "Adding Sonarr Launcher"
cp ./distribution/osx/Launcher/dist/Launcher $outputFolderMacOS/
mv $outputFolderMacOS/Sonarr.exe $outputFolderMacOS/Sonarr.exe.bak
mv $outputFolderMacOS/Launcher $outputFolderMacOS/Sonarr
mv $outputFolderMacOS/Sonarr.exe.bak $outputFolderMacOS/Sonarr.exe
chmod +x $outputFolderMacOS/Sonarr
local folder=$artifactsFolder/$runtime/$framework/Sonarr
echo "Adding Sonarr.Update Launcher"
CheckExitCode cp ./distribution/osx/Launcher/dist/Launcher $outputFolderMacOS/Sonarr.Update/
CheckExitCode mv $outputFolderMacOS/Sonarr.Update/Sonarr.Update.exe $outputFolderMacOS/Sonarr.Update/Sonarr.Update.exe.bak
CheckExitCode mv $outputFolderMacOS/Sonarr.Update/Launcher $outputFolderMacOS/Sonarr.Update/Sonarr.Update
CheckExitCode mv $outputFolderMacOS/Sonarr.Update/Sonarr.Update.exe.bak $outputFolderMacOS/Sonarr.Update/Sonarr.Update.exe
chmod +x $outputFolderMacOS/Sonarr.Update/Sonarr.Update
PackageFiles "$folder" "$framework" "$runtime"
echo "Adding sqlite dylib"
CheckExitCode cp "$sqlitePackageDir/runtimes/osx-x64/native/net46"/*.config $outputFolderMacOS/
if [ $runtime = "dotnet" ] ; then
CheckExitCode $macho merge $outputFolderMacOS "$sqlitePackageDir/runtimes/osx-x64/native/net46"/*.dylib "$sqlitePackageDir/runtimes/osx-arm64/native/net46"/*.dylib
else
CheckExitCode mono $macho merge $outputFolderMacOS "$sqlitePackageDir/runtimes/osx-x64/native/net46"/*.dylib "$sqlitePackageDir/runtimes/osx-arm64/native/net46"/*.dylib
echo "Removing Service helpers"
rm -f $folder/ServiceUninstall.*
rm -f $folder/ServiceInstall.*
echo "Removing Sonarr.Windows"
rm $folder/Sonarr.Windows.*
echo "Adding Sonarr.Mono to UpdatePackage"
cp $folder/Sonarr.Mono.* $folder/Sonarr.Update
if [ "$framework" = "net6.0" ]; then
cp $folder/Mono.Posix.NETStandard.* $folder/Sonarr.Update
cp $folder/libMonoPosixHelper.* $folder/Sonarr.Update
fi
echo "Adding MediaInfo dylib"
CheckExitCode cp $sourceFolder/Libraries/MediaInfo/x64/*.dylib $outputFolderMacOS/
ProgressEnd 'Creating MacOS Package'
ProgressEnd "Creating $runtime Package for $framework"
}
PackageMacOSApp()
{
ProgressStart 'Creating macOS App Package'
local framework="$1"
local runtime="$2"
outputFolderMacOSAppBase=$outputFolderMacOSApp/Sonarr.app/Contents/MacOS
outputFolderMacOSAppBin=$outputFolderMacOSAppBase/bin
ProgressStart "Creating $runtime App Package for $framework"
rm -rf $outputFolderMacOSApp
mkdir $outputFolderMacOSApp
cp -r ./distribution/osx/Sonarr.app $outputFolderMacOSApp
mkdir -p $outputFolderMacOSAppBase
local folder=$artifactsFolder/$runtime-app/$framework
echo "Adding Sonarr Launcher"
CheckExitCode cp ./distribution/osx/Launcher/dist/Launcher $outputFolderMacOSAppBase/
CheckExitCode mv $outputFolderMacOSAppBase/Launcher $outputFolderMacOSAppBase/Sonarr
chmod +x $outputFolderMacOSAppBase/Sonarr
rm -rf $folder
mkdir -p $folder
cp -r distribution/macOS/Sonarr.app $folder
mkdir -p $folder/Sonarr.app/Contents/MacOS
echo "Copying Binaries"
mkdir -p $outputFolderMacOSAppBin
CheckExitCode cp -r $outputFolderLinux/* $outputFolderMacOSAppBin
echo "Adding sqlite dylib"
if [ $runtime = "dotnet" ] ; then
CheckExitCode $macho merge $outputFolderMacOSAppBin "$sqlitePackageDir/runtimes/osx-x64/native/net46" "$sqlitePackageDir/runtimes/osx-arm64/native/net46"
else
CheckExitCode mono $macho merge $outputFolderMacOSAppBin "$sqlitePackageDir/runtimes/osx-x64/native/net46" "$sqlitePackageDir/runtimes/osx-arm64/native/net46"
fi
echo "Adding MediaInfo dylib"
CheckExitCode cp $sourceFolder/Libraries/MediaInfo/x64/*.dylib $outputFolderMacOSAppBin/
cp -r $artifactsFolder/$runtime/$framework/Sonarr/* $folder/Sonarr.app/Contents/MacOS
echo "Removing Update Folder"
rm -r $outputFolderMacOSAppBin/Sonarr.Update
echo "# Do Not Edit\nPackageVersion=${BUILD_NUMBER}\nPackageAuthor=[Team Sonarr](https://sonarr.tv)\nReleaseVersion=${BUILD_NUMBER}\nUpdateMethod=$PackageUpdater\nBranch=${Branch:-master}" > $outputFolderMacOSAppBase/package_info
rm -r $folder/Sonarr.app/Contents/MacOS/Sonarr.Update
ProgressEnd 'Creating macOS App Package'
}
PackageTestsMono()
{
ProgressStart 'Creating Mono Test Package'
rm -rf $testPackageFolderLinux
echo "Copying Binaries"
cp -r $testPackageFolder $testPackageFolderLinux
if [ $runtime = "dotnet" ] ; then
$nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolderLinux
else
mono $nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolderLinux
fi
echo "Creating MDBs"
CreateMdbs $testPackageFolderLinux
echo "Removing PDBs"
find $testPackageFolderLinux -name "*.pdb" -exec rm "{}" \;
PatchMono $testPackageFolderLinux
echo "Adding Sonarr.Core.dll.config (for dllmap)"
cp $sourceFolder/NzbDrone.Core/Sonarr.Core.dll.config $testPackageFolderLinux
# Remove Http binding redirect by renaming it
# We don't need this anymore once our minimum mono version is 5.10
sed -i "s/System.Net.Http/System.Net.Http.Mono/g" $testPackageFolderLinux/Sonarr.Common.Test.dll.config
cp ./test.sh $testPackageFolderLinux/
dos2unix $testPackageFolderLinux/test.sh
echo "Removing Sonarr.Windows"
rm $testPackageFolderLinux/Sonarr.Windows.*
rm -f $testPackageFolderLinux/*.log.config
CleanFolder $testPackageFolderLinux true
ProgressEnd 'Creating Linux Test Package'
}
PackageTestsWindows()
{
ProgressStart 'Creating Windows Test Package'
rm -rf $testPackageFolderWindows
echo "Copying Binaries"
cp -r $testPackageFolder $testPackageFolderWindows
if [ $runtime = "dotnet" ] ; then
$nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolderWindows
else
mono $nuget install NUnit.ConsoleRunner -Version 3.10.0 -Output $testPackageFolderWindows
fi
cp ./test.sh $testPackageFolderWindows
echo "Removing Sonarr.Mono"
rm -f $testPackageFolderWindows/Sonarr.Mono.*
rm -f $testPackageFolderWindows/*.log.config
CleanFolder $testPackageFolderWindows true
ProgressEnd 'Creating Windows Test Package'
ProgressEnd "Creating $runtime App Package for $framework"
}
PackageWindows()
{
ProgressStart 'Creating Windows Package'
local framework="$1"
local runtime="$2"
rm -rf $outputFolderWindows
echo "Copying Binaries"
cp -r $outputFolder $outputFolderWindows
ProgressStart "Creating Windows Package for $framework"
local folder=$artifactsFolder/$runtime/$framework/Sonarr
PackageFiles "$folder" "$framework" "$runtime"
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
echo "Removing Sonarr.Mono"
rm -f $outputFolderWindows/Sonarr.Mono.*
rm -f $folder/Sonarr.Mono.*
rm -f $folder/Mono.Posix.NETStandard.*
rm -f $folder/libMonoPosixHelper.*
echo "Adding Sonarr.Windows to UpdatePackage"
cp $outputFolderWindows/Sonarr.Windows.* $outputFolderWindows/$updateSubFolder/
cp $folder/Sonarr.Windows.* $folder/Sonarr.Update
ProgressEnd 'Creating Windows Package'
ProgressEnd "Creating Windows Package for $framework"
}
PublishArtifacts()
Package()
{
ProgressStart 'Publishing Artifacts'
local framework="$1"
local runtime="$2"
local SPLIT
IFS='-' read -ra SPLIT <<< "$runtime"
case "${SPLIT[0]}" in
linux|freebsd*)
PackageLinux "$framework" "$runtime"
;;
win)
PackageWindows "$framework" "$runtime"
;;
osx)
PackageMacOS "$framework" "$runtime"
;;
esac
}
PackageTests()
{
local framework="$1"
local runtime="$2"
ProgressStart "Creating $runtime Test Package for $framework"
cp test.sh "$testPackageFolder/$framework/$runtime/publish"
rm -f $testPackageFolder/$framework/$runtime/*.log.config
ProgressEnd "Creating $runtime Test Package for $framework"
}
UploadTestArtifacts()
{
local framework="$1"
ProgressStart 'Publishing Test Artifacts'
# Tests
echo "##teamcity[publishArtifacts '$testPackageFolderWindows/** => tests.windows.zip']"
echo "##teamcity[publishArtifacts '$testPackageFolderLinux/** => tests.linux.zip']"
for dir in $testPackageFolder/$framework/*
do
local runtime=$(basename "$dir")
echo "##teamcity[publishArtifacts '$testPackageFolder/$framework/$runtime/publish/** => tests.$runtime.zip']"
done
ProgressEnd 'Publishing Test Artifacts'
}
UploadArtifacts()
{
local framework="$1"
ProgressStart 'Publishing Artifacts'
# Releases
echo "##teamcity[publishArtifacts '$outputFolderWindows/** => Sonarr.$BRANCH.$BUILD_NUMBER.windows.zip!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderLinux/** => Sonarr.$BRANCH.$BUILD_NUMBER.linux.tar.gz!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderMacOS/** => Sonarr.$BRANCH.$BUILD_NUMBER.macos.tar.gz!Sonarr']"
echo "##teamcity[publishArtifacts '$outputFolderMacOSApp/** => Sonarr.$BRANCH.$BUILD_NUMBER.macos.zip']"
# Debian Package
for dir in $artifactsFolder/*
do
local runtime=$(basename "$dir")
echo "##teamcity[publishArtifacts '$artifactsFolder/$runtime/$framework/** => Sonarr.$BRANCH.$SONARR_VERSION.$runtime.zip']"
done
# Debian Package / Windows installer / macOS app
echo "##teamcity[publishArtifacts 'distribution/** => distribution.zip']"
ProgressEnd 'Publishing Artifacts'
}
UploadUIArtifacts()
{
local framework="$1"
ProgressStart 'Publishing UI Artifacts'
# UI folder
echo "##teamcity[publishArtifacts '$outputFolder/UI/** => UI.zip']"
ProgressEnd 'Publishing UI Artifacts'
}
# Use mono or .net depending on OS
case "$(uname -s)" in
CYGWIN*|MINGW32*|MINGW64*|MSYS*)
# on windows, use dotnet
runtime="dotnet"
os="windows"
;;
*)
# otherwise use mono
runtime="mono"
os="posix"
;;
esac
UpdateVersionNumber
Build
CreateReleaseInfo
RunWebpack
PackageMono
PackageMacOS
PackageMacOSApp
PackageTestsMono
PackageTestsWindows
PackageWindows
PublishArtifacts
POSITIONAL=()
if [ $# -eq 0 ]; then
echo "No arguments provided, building everything"
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
LINT=YES
ENABLE_EXTRA_PLATFORMS=NO
ENABLE_EXTRA_PLATFORMS_IN_SDK=NO
fi
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
--backend)
BACKEND=YES
shift # past argument
;;
--enable-bsd|--enable-extra-platforms)
ENABLE_EXTRA_PLATFORMS=YES
shift # past argument
;;
--enable-extra-platforms-in-sdk)
ENABLE_EXTRA_PLATFORMS_IN_SDK=YES
shift # past argument
;;
-r|--runtime)
RID="$2"
shift # past argument
shift # past value
;;
-f|--framework)
FRAMEWORK="$2"
shift # past argument
shift # past value
;;
--frontend)
FRONTEND=YES
shift # past argument
;;
--packages)
PACKAGES=YES
shift # past argument
;;
--lint)
LINT=YES
shift # past argument
;;
--all)
BACKEND=YES
FRONTEND=YES
PACKAGES=YES
LINT=YES
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$ENABLE_EXTRA_PLATFORMS_IN_SDK" = "YES" ];
then
EnableExtraPlatformsInSDK
fi
if [ "$BACKEND" = "YES" ];
then
UpdateVersionNumber
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
EnableExtraPlatforms
fi
Build
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
PackageTests "net6.0" "win-x64"
PackageTests "net6.0" "win-x86"
PackageTests "net6.0" "linux-x64"
PackageTests "net6.0" "linux-musl-x64"
PackageTests "net6.0" "osx-x64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
PackageTests "net6.0" "freebsd-x64"
fi
else
PackageTests "$FRAMEWORK" "$RID"
fi
UploadTestArtifacts "net6.0"
fi
if [ "$FRONTEND" = "YES" ];
then
YarnInstall
if [ "$LINT" = "YES" ];
then
LintUI
fi
RunWebpack
UploadUIArtifacts
fi
if [ "$PACKAGES" = "YES" ];
then
UpdateVersionNumber
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
then
Package "net6.0" "win-x64"
Package "net6.0" "win-x86"
Package "net6.0" "linux-x64"
Package "net6.0" "linux-musl-x64"
Package "net6.0" "linux-arm64"
Package "net6.0" "linux-musl-arm64"
Package "net6.0" "linux-arm"
Package "net6.0" "osx-x64"
Package "net6.0" "osx-arm64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
then
Package "net6.0" "freebsd-x64"
fi
else
Package "$FRAMEWORK" "$RID"
fi
UploadArtifacts "net6.0"
fi

View File

@@ -2,8 +2,8 @@ fromdos ./debian/*
chmod ugo-x ./debian/*
cp -r ./debian ./debian_backup
BuildVersion=${dependent_build_number:-3.10.0.999}
BuildBranch=${dependent_build_branch:-master}
BuildVersion=${dependent_build_number:-4.10.0.999}
BuildBranch=${dependent_build_branch:-main}
BootstrapVersion=`echo "$BuildVersion" | cut -d. -f1,2,3`
BootstrapUpdater="BuiltIn"
PackageUpdater="apt"

View File

@@ -5,18 +5,14 @@ Source: sonarr
Homepage: https://sonarr.tv
Vcs-Git: git@github.com:Sonarr/Sonarr.git
Vcs-Browser: https://github.com/Sonarr/Sonarr
Build-Depends: debhelper (>= 9),
dh-systemd (>= 1.5),
mono-devel (>= 5.18),
libmono-cil-dev (>= 5.18),
cli-common-dev (>= 0.9+xamarin5)
Build-Depends: debhelper (>= 9),
dh-systemd (>= 1.5)
Package: sonarr
Architecture: all
Provides: nzbdrone
Conflicts: nzbdrone
Replaces: nzbdrone
Depends: adduser, libsqlite3-0 (>= 3.7), libmediainfo0v5 (>= 0.7.52) | libmediainfo0 (>= 0.7.52), mono-runtime (>= 5.18), ca-certificates-mono, libmono-system-net-http4.0-cil (>= 4.0.0~alpha1), ${cli:Depends}, ${misc:Depends}
Recommends: libmediainfo0v5 (>= 18.03) | libmediainfo0 (>= 18.03)
Suggests: sqlite3 (>= 3.7), mediainfo (>= 0.7.52)
Depends: adduser, libsqlite3-0 (>= 3.7), ${cli:Depends}, ${misc:Depends}
Suggests: sqlite3 (>= 3.7)
Description: Internet PVR

View File

@@ -3,7 +3,7 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
EXCLUDE_MODULEREFS = crypt32 httpapi __Internal ole32.dll libmonosgen-2.0
EXCLUDE_MODULEREFS = crypt32 httpapi __Internal ole32.dll
%:
dh $@ --with=systemd --with=cli

View File

@@ -1,3 +1,2 @@
ignores msbuild
ignores libmediainfo0v5
ignores libc6

View File

@@ -11,7 +11,7 @@ Group=sonarr
UMask=002
Type=simple
ExecStart=/usr/bin/mono --debug /usr/lib/sonarr/bin/Sonarr.exe -nobrowser -data=/var/lib/sonarr
ExecStart=/usr/lib/sonarr/bin/Sonarr -nobrowser -data=/var/lib/sonarr
TimeoutStopSec=20
KillMode=process
Restart=on-failure

View File

@@ -1,459 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS

View File

@@ -1,28 +0,0 @@
Code reused from duplicati, licensed under LGPL 2.1
Modified for Sonarr by Taloth Saldono
see here for the original source: https://github.com/duplicati/duplicati/tree/679981d29f8a6e445d3c1e6d41e72a673ffaa653/Installer/OSX
License
-------
Sonarr as a whole is licensed under GPL 3.0 as specified in the git repository root.
But to preserve the original intent of the duplicati project, the modified versions of the sources in this folder are dual licensed under LGPL 2.1 and GPL 3.0.
Note: This exception can be freely removed in any copy of Sonarr sources as per LGPL/GPL licensing terms.
A copy of the LGPL 2.1 license is included in the LICENSE.LGPL.md file.
Purpose
-------
The Launcher is a bootstrap/shim application that checks if the appropriate version of mono is installed and subsequently use it to execute Sonarr.
By using a separate application, instead of a shell script, this allows the user to assign certain operating system permissions to Sonarr specifically.
Compiling the Launcher
----------------------
You need an OSX installation with xcode
Then run compile.sh in a terminal
The generated dist/Launcher can be renamed to Sonarr and Sonarr.Update to serve as shims to run Sonarr.exe and Sonarr.Update.exe respectively.

Binary file not shown.

View File

@@ -1,32 +0,0 @@
#import "run-with-mono.h"
#import "PFMoveApplication.h"
int const MONO_VERSION_MAJOR = 5;
int const MONO_VERSION_MINOR = 20;
int main() {
@autoreleasepool {
// Use our own executable name so the same compiled binary to be used for forks
NSString * const FileName = NSProcessInfo.processInfo.arguments[0].lastPathComponent;
// Sonarr.Update.exe
NSString * const ASSEMBLY = [NSString stringWithFormat:@"%@.exe", FileName];
// Sonarr Update
NSString * const APP_NAME = [FileName stringByReplacingOccurrencesOfString:@"." withString:@" "];
// -sonarrupdate
NSString * const PROCESS_NAME = [NSString stringWithFormat:@"-%@", [FileName stringByReplacingOccurrencesOfString:@"." withString:@""].lowercaseString];
@try
{
PFMoveToApplicationsFolderIfNecessary();
}
@catch (NSException * ex)
{
NSLog(@"Translocation/Quarantine check failed, starting normally. Reason: %@", ex.reason);
}
return [RunWithMono runAssemblyWithMono:APP_NAME procnamesuffix:PROCESS_NAME assembly:ASSEMBLY major:MONO_VERSION_MAJOR minor:MONO_VERSION_MINOR];
}
}

View File

@@ -1,32 +0,0 @@
//
// PFMoveApplication.h, version 1.24
// LetsMove
//
// Created by Andy Kim at Potion Factory LLC on 9/17/09
//
// The contents of this file are dedicated to the public domain.
#ifdef __cplusplus
extern "C" {
#endif
#import <Foundation/Foundation.h>
/**
Moves the running application to ~/Applications or /Applications if the former does not exist.
After the move, it relaunches app from the new location.
DOES NOT work for sandboxed applications.
Call from \c NSApplication's delegate method \c -applicationWillFinishLaunching: method. */
void PFMoveToApplicationsFolderIfNecessary(void);
/**
Check whether an app move is currently in progress.
Returns YES if LetsMove is currently in-progress trying to move the app to the Applications folder, or NO otherwise.
This can be used to work around a crash with apps that terminate after last window is closed.
See https://github.com/potionfactory/LetsMove/issues/64 for details. */
BOOL PFMoveIsInProgress(void);
#ifdef __cplusplus
}
#endif

View File

@@ -1,565 +0,0 @@
//
// PFMoveApplication.m, version 1.24
// LetsMove
//
// Created by Andy Kim at Potion Factory LLC on 9/17/09
//
// The contents of this file are dedicated to the public domain.
#import "PFMoveApplication.h"
#import <AppKit/AppKit.h>
#import <Security/Security.h>
#import <dlfcn.h>
#import <sys/mount.h>
@interface LetsMove : NSObject
@end
@implementation LetsMove
+ (NSBundle *)bundle {
return [NSBundle bundleForClass:self];
}
@end
// Strings
// These are macros to be able to use custom i18n tools
#define _I10NS(nsstr) NSLocalizedStringFromTableInBundle(nsstr, @"MoveApplication", [LetsMove bundle], nil)
#define kStrMoveApplicationCouldNotMove _I10NS(@"Could not move to Applications folder")
#define kStrMoveApplicationQuestionTitle _I10NS(@"Move to Applications folder?")
#define kStrMoveApplicationQuestionTitleHome _I10NS(@"Move to Applications folder in your Home folder?")
#define kStrMoveApplicationQuestionMessage _I10NS(@"I can move myself to the Applications folder if you'd like.")
#define kStrMoveApplicationButtonMove _I10NS(@"Move to Applications Folder")
#define kStrMoveApplicationButtonDoNotMove _I10NS(@"Do Not Move")
#define kStrMoveApplicationQuestionInfoWillRequirePasswd _I10NS(@"Note that this will require an administrator password.")
#define kStrMoveApplicationQuestionInfoInDownloadsFolder _I10NS(@"This will keep your Downloads folder uncluttered.")
// Needs to be defined for compiling under 10.5 SDK
#ifndef NSAppKitVersionNumber10_5
#define NSAppKitVersionNumber10_5 949
#endif
// By default, we use a small control/font for the suppression button.
// If you prefer to use the system default (to match your other alerts),
// set this to 0.
#define PFUseSmallAlertSuppressCheckbox 1
static NSString *AlertSuppressKey = @"moveToApplicationsFolderAlertSuppress";
static BOOL MoveInProgress = NO;
// Helper functions
static NSString *PreferredInstallLocation(BOOL *isUserDirectory);
static BOOL IsInApplicationsFolder(NSString *path);
static BOOL IsInDownloadsFolder(NSString *path);
static BOOL IsApplicationAtPathRunning(NSString *path);
static BOOL IsApplicationAtPathNested(NSString *path);
static NSString *ContainingDiskImageDevice(NSString *path);
static BOOL Trash(NSString *path);
static BOOL DeleteOrTrash(NSString *path);
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled);
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath);
static NSString *ShellQuotedString(NSString *string);
static void Relaunch(NSString *destinationPath);
// Main worker function
void PFMoveToApplicationsFolderIfNecessary(void) {
// Make sure to do our work on the main thread.
// Apparently Electron apps need this for things to work properly.
if (![NSThread isMainThread]) {
dispatch_async(dispatch_get_main_queue(), ^{
PFMoveToApplicationsFolderIfNecessary();
});
return;
}
// Skip if user suppressed the alert before
if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return;
// Path of the bundle
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
// Check if the bundle is embedded in another application
BOOL isNestedApplication = IsApplicationAtPathNested(bundlePath);
// Skip if the application is already in some Applications folder,
// unless it's inside another app's bundle.
if (IsInApplicationsFolder(bundlePath) && !isNestedApplication) return;
// OK, looks like we'll need to do a move - set the status variable appropriately
MoveInProgress = YES;
// File Manager
NSFileManager *fm = [NSFileManager defaultManager];
// Are we on a disk image?
NSString *diskImageDevice = ContainingDiskImageDevice(bundlePath);
// Since we are good to go, get the preferred installation directory.
BOOL installToUserApplications = NO;
NSString *applicationsDirectory = PreferredInstallLocation(&installToUserApplications);
NSString *bundleName = [bundlePath lastPathComponent];
NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName];
// Check if we need admin password to write to the Applications directory
BOOL needAuthorization = ([fm isWritableFileAtPath:applicationsDirectory] == NO);
// Check if the destination bundle is already there but not writable
needAuthorization |= ([fm fileExistsAtPath:destinationPath] && ![fm isWritableFileAtPath:destinationPath]);
// Setup the alert
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
{
NSString *informativeText = nil;
[alert setMessageText:(installToUserApplications ? kStrMoveApplicationQuestionTitleHome : kStrMoveApplicationQuestionTitle)];
informativeText = kStrMoveApplicationQuestionMessage;
if (needAuthorization) {
informativeText = [informativeText stringByAppendingString:@" "];
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoWillRequirePasswd];
}
else if (IsInDownloadsFolder(bundlePath)) {
// Don't mention this stuff if we need authentication. The informative text is long enough as it is in that case.
informativeText = [informativeText stringByAppendingString:@" "];
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoInDownloadsFolder];
}
[alert setInformativeText:informativeText];
// Add accept button
[alert addButtonWithTitle:kStrMoveApplicationButtonMove];
// Add deny button
NSButton *cancelButton = [alert addButtonWithTitle:kStrMoveApplicationButtonDoNotMove];
[cancelButton setKeyEquivalent:[NSString stringWithFormat:@"%C", 0x1b]]; // Escape key
// Setup suppression button
[alert setShowsSuppressionButton:YES];
if (PFUseSmallAlertSuppressCheckbox) {
NSCell *cell = [[alert suppressionButton] cell];
[cell setControlSize:NSSmallControlSize];
[cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
}
}
// Activate app -- work-around for focus issues related to "scary file from internet" OS dialog.
if (![NSApp isActive]) {
[NSApp activateIgnoringOtherApps:YES];
}
if ([alert runModal] == NSAlertFirstButtonReturn) {
NSLog(@"INFO -- Moving myself to the Applications folder");
// Move
if (needAuthorization) {
BOOL authorizationCanceled;
if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) {
if (authorizationCanceled) {
NSLog(@"INFO -- Not moving because user canceled authorization");
MoveInProgress = NO;
return;
}
else {
NSLog(@"ERROR -- Could not copy myself to /Applications with authorization");
goto fail;
}
}
}
else {
// If a copy already exists in the Applications folder, put it in the Trash
if ([fm fileExistsAtPath:destinationPath]) {
// But first, make sure that it's not running
if (IsApplicationAtPathRunning(destinationPath)) {
// Give the running app focus and terminate myself
NSLog(@"INFO -- Switching to an already running version");
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit];
MoveInProgress = NO;
exit(0);
}
else {
if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName]))
goto fail;
}
}
if (!CopyBundle(bundlePath, destinationPath)) {
NSLog(@"ERROR -- Could not copy myself to %@", destinationPath);
goto fail;
}
}
// Trash the original app. It's okay if this fails.
// NOTE: This final delete does not work if the source bundle is in a network mounted volume.
// Calling rm or file manager's delete method doesn't work either. It's unlikely to happen
// but it'd be great if someone could fix this.
if (!isNestedApplication && diskImageDevice == nil && !DeleteOrTrash(bundlePath)) {
NSLog(@"WARNING -- Could not delete application after moving it to Applications folder");
}
// Relaunch.
Relaunch(destinationPath);
// Launched from within a disk image? -- unmount (if no files are open after 5 seconds,
// otherwise leave it mounted).
if (diskImageDevice && !isNestedApplication) {
NSString *script = [NSString stringWithFormat:@"(/bin/sleep 5 && /usr/bin/hdiutil detach %@) &", ShellQuotedString(diskImageDevice)];
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
}
MoveInProgress = NO;
exit(0);
}
// Save the alert suppress preference if checked
else if ([[alert suppressionButton] state] == NSOnState) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
}
MoveInProgress = NO;
return;
fail:
{
// Show failure message
alert = [[[NSAlert alloc] init] autorelease];
[alert setMessageText:kStrMoveApplicationCouldNotMove];
[alert runModal];
MoveInProgress = NO;
}
}
BOOL PFMoveIsInProgress() {
return MoveInProgress;
}
#pragma mark -
#pragma mark Helper Functions
static NSString *PreferredInstallLocation(BOOL *isUserDirectory) {
// Return the preferred install location.
// Assume that if the user has a ~/Applications folder, they'd prefer their
// applications to go there.
NSFileManager *fm = [NSFileManager defaultManager];
/*
NSArray *userApplicationsDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
if ([userApplicationsDirs count] > 0) {
NSString *userApplicationsDir = [userApplicationsDirs objectAtIndex:0];
BOOL isDirectory;
if ([fm fileExistsAtPath:userApplicationsDir isDirectory:&isDirectory] && isDirectory) {
// User Applications directory exists. Get the directory contents.
NSArray *contents = [fm contentsOfDirectoryAtPath:userApplicationsDir error:NULL];
// Check if there is at least one ".app" inside the directory.
for (NSString *contentsPath in contents) {
if ([[contentsPath pathExtension] isEqualToString:@"app"]) {
if (isUserDirectory) *isUserDirectory = YES;
return [userApplicationsDir stringByResolvingSymlinksInPath];
}
}
}
}
*/
// No user Applications directory in use. Return the machine local Applications directory
if (isUserDirectory) *isUserDirectory = NO;
return [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByResolvingSymlinksInPath];
}
static BOOL IsInApplicationsFolder(NSString *path) {
// Check all the normal Application directories
NSArray *applicationDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES);
for (NSString *appDir in applicationDirs) {
if ([path hasPrefix:appDir]) return YES;
}
// Also, handle the case that the user has some other Application directory (perhaps on a separate data partition).
if ([[path pathComponents] containsObject:@"Applications"]) return YES;
return NO;
}
static BOOL IsInDownloadsFolder(NSString *path) {
NSArray *downloadDirs = NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSAllDomainsMask, YES);
for (NSString *downloadsDirPath in downloadDirs) {
if ([path hasPrefix:downloadsDirPath]) return YES;
}
return NO;
}
static BOOL IsApplicationAtPathRunning(NSString *bundlePath) {
bundlePath = [bundlePath stringByStandardizingPath];
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
// Use the new API on 10.6 or higher to determine if the app is already running
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
NSString *runningAppBundlePath = [[[runningApplication bundleURL] path] stringByStandardizingPath];
if ([runningAppBundlePath isEqualToString:bundlePath]) {
return YES;
}
}
return NO;
}
#endif
// Use the shell to determine if the app is already running on systems 10.5 or lower
NSString *script = [NSString stringWithFormat:@"/bin/ps ax -o comm | /usr/bin/grep %@/ | /usr/bin/grep -v grep >/dev/null", ShellQuotedString(bundlePath)];
NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
[task waitUntilExit];
// If the task terminated with status 0, it means that the final grep produced 1 or more lines of output.
// Which means that the app is already running
return [task terminationStatus] == 0;
}
static BOOL IsApplicationAtPathNested(NSString *path) {
NSString *containingPath = [path stringByDeletingLastPathComponent];
NSArray *components = [containingPath pathComponents];
for (NSString *component in components) {
if ([[component pathExtension] isEqualToString:@"app"]) {
return YES;
}
}
return NO;
}
static NSString *ContainingDiskImageDevice(NSString *path) {
NSString *containingPath = [path stringByDeletingLastPathComponent];
struct statfs fs;
if (statfs([containingPath fileSystemRepresentation], &fs) || (fs.f_flags & MNT_ROOTFS))
return nil;
NSString *device = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:fs.f_mntfromname length:strlen(fs.f_mntfromname)];
NSTask *hdiutil = [[[NSTask alloc] init] autorelease];
[hdiutil setLaunchPath:@"/usr/bin/hdiutil"];
[hdiutil setArguments:[NSArray arrayWithObjects:@"info", @"-plist", nil]];
[hdiutil setStandardOutput:[NSPipe pipe]];
[hdiutil launch];
[hdiutil waitUntilExit];
NSData *data = [[[hdiutil standardOutput] fileHandleForReading] readDataToEndOfFile];
NSDictionary *info = nil;
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
info = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:NULL];
}
else {
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
info = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL];
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
}
#endif
if (![info isKindOfClass:[NSDictionary class]]) return nil;
NSArray *images = (NSArray *)[info objectForKey:@"images"];
if (![images isKindOfClass:[NSArray class]]) return nil;
for (NSDictionary *image in images) {
if (![image isKindOfClass:[NSDictionary class]]) return nil;
id systemEntities = [image objectForKey:@"system-entities"];
if (![systemEntities isKindOfClass:[NSArray class]]) return nil;
for (NSDictionary *systemEntity in systemEntities) {
if (![systemEntity isKindOfClass:[NSDictionary class]]) return nil;
NSString *devEntry = [systemEntity objectForKey:@"dev-entry"];
if (![devEntry isKindOfClass:[NSString class]]) return nil;
if ([devEntry isEqualToString:device])
return device;
}
}
return nil;
}
static BOOL Trash(NSString *path) {
BOOL result = NO;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_8) {
result = [[NSFileManager defaultManager] trashItemAtURL:[NSURL fileURLWithPath:path] resultingItemURL:NULL error:NULL];
}
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
if (!result) {
result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
source:[path stringByDeletingLastPathComponent]
destination:@""
files:[NSArray arrayWithObject:[path lastPathComponent]]
tag:NULL];
}
#endif
// As a last resort try trashing with AppleScript.
// This allows us to trash the app in macOS Sierra even when the app is running inside
// an app translocation image.
if (!result) {
NSAppleScript *appleScript = [[[NSAppleScript alloc] initWithSource:
[NSString stringWithFormat:@"\
set theFile to POSIX file \"%@\" \n\
tell application \"Finder\" \n\
move theFile to trash \n\
end tell", path]] autorelease];
NSDictionary *errorDict = nil;
NSAppleEventDescriptor *scriptResult = [appleScript executeAndReturnError:&errorDict];
if (scriptResult == nil) {
NSLog(@"Trash AppleScript error: %@", errorDict);
}
result = (scriptResult != nil);
}
if (!result) {
NSLog(@"ERROR -- Could not trash '%@'", path);
}
return result;
}
static BOOL DeleteOrTrash(NSString *path) {
NSError *error;
if ([[NSFileManager defaultManager] removeItemAtPath:path error:&error]) {
return YES;
}
else {
// Don't log warning if on Sierra and running inside App Translocation path
if ([path rangeOfString:@"/AppTranslocation/"].location == NSNotFound)
NSLog(@"WARNING -- Could not delete '%@': %@", path, [error localizedDescription]);
return Trash(path);
}
}
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled) {
if (canceled) *canceled = NO;
// Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf'
// so we really don't want to fuck this up.
if (![[dstPath pathExtension] isEqualToString:@"app"]) return NO;
// Do some more checks
if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
int pid, status;
AuthorizationRef myAuthorizationRef;
// Get the authorization
OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef);
if (err != errAuthorizationSuccess) return NO;
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights myRights = {1, &myItems};
AuthorizationFlags myFlags = (AuthorizationFlags)(kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize);
err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL);
if (err != errAuthorizationSuccess) {
if (err == errAuthorizationCanceled && canceled)
*canceled = YES;
goto fail;
}
static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool,
AuthorizationFlags options, char * const *arguments,
FILE **communicationsPipe) = NULL;
if (!security_AuthorizationExecuteWithPrivileges) {
// On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no
// good alternative (without requiring code signing). We'll look up the function through dyld and fail
// if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If
// they keep the function and throw some sort of exception, this won't fail gracefully, but that's a
// risk we'll have to take for now.
security_AuthorizationExecuteWithPrivileges = (OSStatus (*)(AuthorizationRef, const char*,
AuthorizationFlags, char* const*,
FILE **)) dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
}
if (!security_AuthorizationExecuteWithPrivileges) goto fail;
// Delete the destination
{
char *args[] = {"-rf", (char *)[dstPath fileSystemRepresentation], NULL};
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
if (err != errAuthorizationSuccess) goto fail;
// Wait until it's done
pid = wait(&status);
if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist
}
// Copy
{
char *args[] = {"-pR", (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL};
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
if (err != errAuthorizationSuccess) goto fail;
// Wait until it's done
pid = wait(&status);
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail;
}
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
return YES;
fail:
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
return NO;
}
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath) {
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = nil;
if ([fm copyItemAtPath:srcPath toPath:dstPath error:&error]) {
return YES;
}
else {
NSLog(@"ERROR -- Could not copy '%@' to '%@' (%@)", srcPath, dstPath, error);
return NO;
}
}
static NSString *ShellQuotedString(NSString *string) {
return [NSString stringWithFormat:@"'%@'", [string stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]];
}
static void Relaunch(NSString *destinationPath) {
// The shell script waits until the original app process terminates.
// This is done so that the relaunched app opens as the front-most app.
int pid = [[NSProcessInfo processInfo] processIdentifier];
// Command run just before running open /final/path
NSString *preOpenCmd = @"";
NSString *quotedDestinationPath = ShellQuotedString(destinationPath);
// OS X >=10.5:
// Before we launch the new app, clear xattr:com.apple.quarantine to avoid
// duplicate "scary file from the internet" dialog.
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
// Add the -r flag on 10.6
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine %@", quotedDestinationPath];
}
else {
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine %@", quotedDestinationPath];
}
NSString *script = [NSString stringWithFormat:@"(while /bin/kill -0 %d >&/dev/null; do /bin/sleep 0.1; done; %@; /usr/bin/open %@) &", pid, preOpenCmd, quotedDestinationPath];
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
}

View File

@@ -1,16 +0,0 @@
#!/bin/bash
# -fobjc-arc: enables ARC
# -fmodules: enables modules so you can import with `@import AppKit;`
# -mmacosx-version-min=10.6: support older OS X versions, this might increase the binary size
if [ ! -d "../dist" ]; then mkdir ../dist; fi
clang PFMoveApplication.m -fno-objc-arc -fmodules -mmacosx-version-min=10.6 -c -o PFMoveApplication.o
clang run-with-mono.m Launcher.m PFMoveApplication.o -fobjc-arc -fmodules -mmacosx-version-min=10.6 -o ../dist/Launcher
rm PFMoveApplication.o
if [ "$1" == "install" ] && [ "$2" != "" ]; then
echo "Installing to $2"
cp ../dist/Launcher $2
chmod +x $2
fi

View File

@@ -1,11 +0,0 @@
@import Foundation;
@import AppKit;
@interface RunWithMono : NSObject {
}
+ (void) openDownloadLink:(NSButton*)button;
+ (bool) showDownloadMonoDialog:(NSString *)appName major:(int)major minor:(int)minor;
+ (int) runAssemblyWithMono:(NSString *)appName procnamesuffix:(NSString *)procnamesuffix assembly:(NSString *)assembly major:(int) major minor:(int) minor;
@end

View File

@@ -1,258 +0,0 @@
#import "run-with-mono.h"
@import Foundation;
@import AppKit;
NSString * const VERSION_TITLE = @"Cannot launch %@";
NSString * const VERSION_MSG = @"%@ requires the Mono Framework version %d.%d or later.";
NSString * const DOWNLOAD_URL = @"http://www.mono-project.com/download/stable/#download-mac";
// Helper method to see if the user has requested debug output
bool D() {
NSString* v = [[[NSProcessInfo processInfo]environment]objectForKey:@"DEBUG"];
if (v == nil || v.length == 0 || [v isEqual:@"0"] || [v isEqual:@"false"] || [v isEqual:@"f"])
return false;
return true;
}
// Wrapper method to invoke commandline operations and return the string output
NSString *runCommand(NSString *program, NSArray<NSString *> *arguments) {
NSPipe *pipe = [NSPipe pipe];
NSFileHandle *file = pipe.fileHandleForReading;
NSTask *task = [[NSTask alloc] init];
task.launchPath = program;
task.arguments = arguments;
task.standardOutput = pipe;
[task launch];
NSData *data = [file readDataToEndOfFile];
[file closeFile];
[task waitUntilExit];
NSString *cmdOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
if (cmdOutput == nil || cmdOutput.length == 0)
return nil;
return [cmdOutput stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
// Checks if the Mono version is greater than or equal to the desired version
bool isValidMono(NSString *mono, int major, int minor) {
NSFileManager *fileManager = [NSFileManager defaultManager];
if (mono == nil)
return false;
if (![fileManager fileExistsAtPath:mono] || ![fileManager isExecutableFileAtPath:mono])
return false;
NSString *versionInfo = runCommand(mono, @[@"--version"]);
NSRange rg = [versionInfo rangeOfString:@"Mono JIT compiler version \\d+\\.\\d+" options:NSRegularExpressionSearch];
if (rg.location != NSNotFound) {
versionInfo = [versionInfo substringWithRange:rg];
if (D()) NSLog(@"Matched version: %@", versionInfo);
rg = [versionInfo rangeOfString:@"\\d+\\.\\d+" options:NSRegularExpressionSearch];
if (rg.location != NSNotFound) {
versionInfo = [versionInfo substringWithRange:rg];
if (D()) NSLog(@"Matched version: %@", versionInfo);
NSArray<NSString *> *versionComponents = [versionInfo componentsSeparatedByString:@"."];
if ([versionComponents[0] intValue] < major)
return false;
if ([versionComponents[0] intValue] == major && [versionComponents[1] intValue] < minor)
return false;
return true;
}
}
return false;
}
// Attempts to locate a mono with a valid version
NSString *findMono(int major, int minor) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *currentMono = runCommand(@"/usr/bin/which", @[@"mono"]);
if (D()) NSLog(@"which mono: %@", currentMono);
if (isValidMono(currentMono, major, minor)) {
if (D()) NSLog(@"Found mono with: %@", currentMono);
return currentMono;
}
NSArray *probepaths = @[@"/usr/local/bin/mono", @"/Library/Frameworks/Mono.framework/Versions/Current/bin/mono", @"/opt/local/bin/mono"];
for(NSString* probepath in probepaths) {
if (D()) NSLog(@"Trying mono with: %@", probepath);
if (isValidMono(probepath, major, minor)) {
if (D()) NSLog(@"Found mono with: %@", probepath);
return probepath;
}
}
if (D()) NSLog(@"Failed to find Mono, returning: %@", nil);
return nil;
}
// Check Bundle for quarantine
void checkBundle() {
NSString * const bundlePath = [[NSBundle mainBundle] bundlePath];
NSString * const attributes = runCommand(@"/usr/bin/xattr", @[@"-l", bundlePath]);
if (D()) NSLog(@"Attributes: %@", attributes);
if ([attributes containsString:@"com.apple.quarantine:"]) {
runCommand(@"/usr/bin/xattr", @[@"-dr", @"com.apple.quarantine", bundlePath]);
NSLog(@"Removed quarantine attribute from bundle");
}
}
@implementation RunWithMono
+ (void) openDownloadLink:(NSButton*)button {
if (D()) NSLog(@"Clicked Download");
runCommand(@"/usr/bin/open", @[DOWNLOAD_URL]);
}
// Shows the download dialog, prompting to download Mono
+ (bool) showDownloadMonoDialog:(NSString *)appName major:(int)major minor:(int)minor {
NSAlert *alert = [[NSAlert alloc] init];
[alert setInformativeText:[NSString stringWithFormat:VERSION_MSG, appName, major, minor]];
[alert setMessageText:[NSString stringWithFormat:VERSION_TITLE, appName]];
[alert addButtonWithTitle:@"Cancel"];
[alert addButtonWithTitle:@"Retry"];
[alert addButtonWithTitle:@"Download"];
NSButton *downloadButton = [[alert buttons] objectAtIndex:2];
[downloadButton setTarget:self];
[downloadButton setAction:@selector(openDownloadLink:)];
NSModalResponse btn = [alert runModal];
if (btn == NSAlertFirstButtonReturn) {
if (D()) NSLog(@"Clicked Cancel");
return true;
}
else if (btn == NSAlertSecondButtonReturn) {
if (D()) NSLog(@"Clicked Retry");
return false;
}
return true;
}
// Top-level method, finds Mono with an appropriate version and launches the assembly
+ (int) runAssemblyWithMono: (NSString *)appName procnamesuffix:(NSString *)procnamesuffix assembly:(NSString *)assembly major:(int) major minor:(int) minor {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *assemblyPath;
bool found = false;
NSString *localPath = NSProcessInfo.processInfo.arguments[0].stringByDeletingLastPathComponent;
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
NSArray *paths = @[
localPath,
[NSString pathWithComponents:@[localPath, @"bin"]],
resourcePath,
[NSString pathWithComponents:@[resourcePath, @"bin"]]
];
for (NSString* entryFolder in paths) {
if (D()) NSLog(@"Checking folder: %@", entryFolder);
assemblyPath = [NSString pathWithComponents:@[entryFolder, assembly]];
if ([fileManager fileExistsAtPath:assemblyPath]) {
found = true;
break;
}
}
if (!found) {
NSLog(@"Assembly file not found");
return 1;
}
if (D()) NSLog(@"assemblyPath: %@", assemblyPath);
checkBundle();
NSString *currentMono = findMono(major, minor);
while (currentMono == nil) {
NSLog(@"No valid mono found!");
bool close = [self showDownloadMonoDialog:appName major:major minor:minor];
if (close)
return 1;
currentMono = findMono(major, minor);
}
// Setup dylib fallback loading
NSMutableArray * dylibPath = [NSMutableArray arrayWithObject:assemblyPath.stringByDeletingLastPathComponent];
// Update the PATH to use the specified mono version
if ([currentMono hasPrefix:@"/"])
{
NSString * curMonoBinDir = currentMono.stringByDeletingLastPathComponent;
NSString * curMonoDir = curMonoBinDir.stringByDeletingLastPathComponent;
NSString * curMonoLibDir = [NSString pathWithComponents:@[curMonoDir, @"lib"]];
NSString * curEnvPath = [NSString stringWithUTF8String:getenv("PATH")];
NSString * newEnvPath = [NSString stringWithFormat:@"%@:%@", curMonoBinDir, curEnvPath];
setenv("PATH", newEnvPath.UTF8String, 1);
[dylibPath addObject:curMonoLibDir];
NSLog(@"Added %@ to PATH", curMonoBinDir);
}
// Setup libsqlite?
/* if [[ -f '/opt/local/lib/libsqlite3.0.dylib' ]]; then
export DYLD_FALLBACK_LIBRARY_PATH="/opt/local/lib:$DYLD_FALLBACK_LIBRARY_PATH"
fi
*/
[dylibPath addObjectsFromArray:@[@"$HOME/lib", @"/usr/local/lib", @"/lib", @"/usr/lib"]];
setenv("DYLD_FALLBACK_LIBRARY_PATH", [dylibPath componentsJoinedByString:@":"].UTF8String, 1);
if (D()) NSLog(@"Running %@ --debug %@", currentMono, assemblyPath);
// Copy commandline arguments
NSMutableArray* arguments = [[NSMutableArray alloc] init];
// Disabled suffix for now coz it's confusing and not preserved on in-app restart
[arguments addObject:currentMono];
//[arguments addObject:[currentMono stringByAppendingString:procnamesuffix]];
[arguments addObject:@"--debug"];
[arguments addObjectsFromArray:[[NSProcessInfo processInfo] arguments]];
// replace the executable-path with the assembly path
[arguments replaceObjectAtIndex:2 withObject:assemblyPath];
// Try switch to mono using execv
char * cPath = strdup([currentMono UTF8String]);
char ** cArgs;
char ** pArgNext = cArgs = malloc(sizeof(*cArgs) * ([arguments count] + 1));
for (NSString *s in arguments) {
*pArgNext++ = strdup([s UTF8String]);
}
*pArgNext = NULL;
int ret = execv(cPath, cArgs);
if (ret != 0)
NSLog(@"Failed execv with errno @d", errno);
// execv failed, cleanup
pArgNext = cArgs;
for (NSString *s in arguments) {
free(*pArgNext++);
}
free(cArgs);
free(cPath);
return -1;
}
@end

View File

@@ -1,62 +0,0 @@
#!/bin/sh
#get the bundle's MacOS directory full path
DIR=$(cd "$(dirname "$0")"; pwd)
#change these values to match your app
EXE_PATH="$DIR/Sonarr.exe"
APPNAME="Sonarr"
#set up environment
if [[ -x '/opt/local/bin/mono' ]]; then
# Macports and mono-supplied installer path
export PATH="/opt/local/bin:$PATH"
elif [[ -x '/usr/local/bin/mono' ]]; then
# Homebrew-supplied path to mono
export PATH="/usr/local/bin:$PATH"
fi
export DYLD_FALLBACK_LIBRARY_PATH="$DIR"
if [ -e /Library/Frameworks/Mono.framework ]; then
MONO_FRAMEWORK_PATH=/Library/Frameworks/Mono.framework/Versions/Current
export PATH="$MONO_FRAMEWORK_PATH/bin:$PATH"
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$MONO_FRAMEWORK_PATH/lib"
fi
if [[ -f '/opt/local/lib/libsqlite3.0.dylib' ]]; then
export DYLD_FALLBACK_LIBRARY_PATH="/opt/local/lib:$DYLD_FALLBACK_LIBRARY_PATH"
fi
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$HOME/lib:/usr/local/lib:/lib:/usr/lib"
#mono version check
REQUIRED_MAJOR=4
REQUIRED_MINOR=6
VERSION_TITLE="Cannot launch $APPNAME"
VERSION_MSG="$APPNAME requires Mono Runtime Environment(MRE) $REQUIRED_MAJOR.$REQUIRED_MINOR or later."
DOWNLOAD_URL="http://www.mono-project.com/download/#download-mac"
MONO_VERSION="$(mono --version | grep 'Mono JIT compiler version ' | cut -f5 -d\ )"
# if [[ -o DEBUG ]]; then osascript -e "display dialog \"MONO_VERSION: $MONO_VERSION\""; fi
MONO_VERSION_MAJOR="$(echo $MONO_VERSION | cut -f1 -d.)"
MONO_VERSION_MINOR="$(echo $MONO_VERSION | cut -f2 -d.)"
if [ -z "$MONO_VERSION" ] \
|| [ $MONO_VERSION_MAJOR -lt $REQUIRED_MAJOR ] \
|| [ $MONO_VERSION_MAJOR -eq $REQUIRED_MAJOR -a $MONO_VERSION_MINOR -lt $REQUIRED_MINOR ]
then
osascript \
-e "set question to display dialog \"$VERSION_MSG\" with title \"$VERSION_TITLE\" buttons {\"Cancel\", \"Download...\"} default button 2" \
-e "if button returned of question is equal to \"Download...\" then open location \"$DOWNLOAD_URL\""
echo "$VERSION_TITLE"
echo "$VERSION_MSG"
exit 1
fi
MONO_EXEC="exec mono --debug"
#run app using mono
$MONO_EXEC "$EXE_PATH"

View File

@@ -1,7 +1,10 @@
REM SET BUILD_NUMBER=1
REM SET BRANCH=develop
@REM SET SONARR_MAJOR_VERSION=4
@REM SET SONARR_VERSION=4.0.0.5
@REM SET BRANCH=develop
@REM SET FRAMEWORK=net6.0
@REM SET RUNTIME=win-x64
echo ##teamcity[progressStart 'Building setup file']
inno\ISCC.exe sonarr.iss
echo ##teamcity[progressFinish 'Building setup file']
echo ##teamcity[publishArtifacts 'distribution\windows\setup\output\*.exe']
echo ##teamcity[publishArtifacts 'distribution\windows\setup\output\*%RUNTIME%*.exe']

View File

@@ -6,17 +6,20 @@
#define AppURL "https://sonarr.tv/"
#define ForumsURL "https://forums.sonarr.tv/"
#define AppExeName "Sonarr.exe"
#define BuildNumber "3.0"
#define BuildNumber GetEnv('BUILD_NUMBER')
#define BuildNumber "4.0"
#define BuildNumber GetEnv('SONARR_VERSION')
#define MajorVersion GetEnv('SONARR_MAJOR_VERSION')
#define BranchName GetEnv('BRANCH')
#define Framework GetEnv('FRAMEWORK')
#define Runtime GetEnv('RUNTIME')
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; NOTE: The value of AppId uniquely identifies this appl ication.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{56C1065D-3523-4025-B76D-6F73F67F7F71}
AppName={#AppName}
AppVersion=3.0
AppVersion={#MajorVersion}
AppPublisher={#AppPublisher}
AppPublisherURL={#AppURL}
AppSupportURL={#ForumsURL}
@@ -26,7 +29,7 @@ DefaultDirName={commonappdata}\Sonarr\bin
DisableDirPage=yes
DefaultGroupName={#AppName}
DisableProgramGroupPage=yes
OutputBaseFilename=Sonarr.{#BranchName}.{#BuildNumber}.windows
OutputBaseFilename=Sonarr.{#BranchName}.{#BuildNumber}.{#Runtime}-installer
SolidCompression=yes
AppCopyright=Creative Commons 3.0 License
AllowUNCPath=False
@@ -35,9 +38,10 @@ DisableReadyPage=True
CompressionThreads=2
Compression=lzma2/normal
AppContact={#ForumsURL}
VersionInfoVersion={#BuildNumber}
VersionInfoVersion={#MajorVersion}
SetupLogging=yes
OutputDir=output
AppverName={#AppName}
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -49,8 +53,8 @@ Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
[Files]
Source: "..\..\..\_output_windows\Sonarr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\..\..\_output_windows\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Sonarr\Sonarr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Sonarr\*"; Excludes: "Sonarr.Update"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
@@ -80,26 +84,3 @@ begin
Exec('net', 'stop nzbdrone', '', 0, ewWaitUntilTerminated, ResultCode)
Exec('sc', 'delete nzbdrone', '', 0, ewWaitUntilTerminated, ResultCode)
end;
function Framework472IsNotInstalled(): Boolean;
var
bSuccess: Boolean;
regVersion: Cardinal;
begin
Result := True;
bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', regVersion);
if (True = bSuccess) and (regVersion >= 461808) then begin
Result := False;
end;
end;
function InitializeSetup(): Boolean;
begin
if Framework472IsNotInstalled() then begin
MsgBox('Sonarr requires Microsoft .NET Framework 4.7.2 or higher.'#13#13
'Please use Windows Update to install this version'#13
'or download it from https://dotnet.microsoft.com/download/dotnet-framework.', mbInformation, MB_OK);
result := false;
end else
result := true;
end;

41
docs.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
set -e
PLATFORM=$1
if [ "$PLATFORM" = "Windows" ]; then
RUNTIME="win-x64"
elif [ "$PLATFORM" = "Linux" ]; then
RUNTIME="linux-x64"
elif [ "$PLATFORM" = "Mac" ]; then
RUNTIME="osx-x64"
else
echo "Platform must be provided as first argument: Windows, Linux or Mac"
exit 1
fi
outputFolder='_output'
testPackageFolder='_tests'
rm -rf $outputFolder
rm -rf $testPackageFolder
slnFile=src/Sonarr.sln
platform=Posix
dotnet clean $slnFile -c Debug
dotnet clean $slnFile -c Release
dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p:RuntimeIdentifiers=$RUNTIME -t:PublishAllRids
dotnet new tool-manifest
dotnet tool install --version 6.5.0 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Sonarr.Api.V3/openapi.json "$outputFolder/net6.0/$RUNTIME/Sonarr.dll" v3 &
sleep 30
kill %1
exit 0

View File

@@ -1,25 +0,0 @@
{
"remove-empty-rulesets": true,
"always-semicolon": true,
"color-case": "lower",
"block-indent": " ",
"color-shorthand": false,
"element-case": "lower",
"eof-newline": true,
"leading-zero": true,
"quotes": "double",
"sort-order-fallback": "abc",
"space-before-colon": "",
"space-after-colon": " ",
"space-before-combinator": " ",
"space-after-combinator": " ",
"space-between-declarations": "\n",
"space-before-opening-brace": " ",
"space-after-opening-brace": "\n",
"space-after-selector-delimiter": " ",
"space-before-selector-delimiter": "",
"space-before-closing-brace": "\n",
"strip-spaces": true,
"tab-size": true,
"unitless-zero": false
}

View File

@@ -1,335 +0,0 @@
{
"indent": {
"value": " ",
"FunctionExpression": 1,
"ArrayExpression": 1,
"ObjectExpression": 1
},
"lineBreak": {
"value": "\n",
"before": {
"ArrayPatternClosing": 0,
"ArrayPatternComma": 0,
"ArrayPatternOpening": 0,
"ArrowFunctionExpressionArrow": 0,
"ArrowFunctionExpressionClosingBrace": ">=1",
"ArrowFunctionExpressionOpeningBrace": 0,
"AssignmentExpression": ">=1",
"AssignmentOperator": 0,
"BlockStatement": 0,
"BreakKeyword": ">=1",
"CallExpression": -1,
"CallExpressionClosingParentheses": -1,
"CallExpressionOpeningParentheses": 0,
"CatchClosingBrace": ">=1",
"CatchKeyword": 0,
"CatchOpeningBrace": 0,
"ClassDeclaration": ">=1",
"ClassDeclarationClosingBrace": ">=1",
"ClassDeclarationOpeningBrace": 0,
"ConditionalExpression": ">=1",
"DeleteOperator": ">=1",
"DoWhileStatement": ">=1",
"DoWhileStatementClosingBrace": ">=1",
"DoWhileStatementOpeningBrace": 0,
"ElseIfStatement": 0,
"ElseIfStatementClosingBrace": ">=1",
"ElseIfStatementOpeningBrace": 0,
"ElseStatement": 0,
"ElseStatementClosingBrace": ">=1",
"ElseStatementOpeningBrace": 0,
"EmptyStatement": -1,
"EndOfFile": -1,
"FinallyClosingBrace": ">=1",
"FinallyKeyword": -1,
"FinallyOpeningBrace": 0,
"ForInStatement": ">=1",
"ForInStatementClosingBrace": ">=1",
"ForInStatementExpressionClosing": 0,
"ForInStatementExpressionOpening": 0,
"ForInStatementOpeningBrace": 0,
"ForStatement": ">=1",
"ForStatementClosingBrace": ">=1",
"ForStatementExpressionClosing": "<2",
"ForStatementExpressionOpening": 0,
"ForStatementOpeningBrace": 0,
"FunctionDeclaration": ">=1",
"FunctionDeclarationClosingBrace": ">=1",
"FunctionDeclarationOpeningBrace": 0,
"FunctionExpression": 0,
"FunctionExpressionClosingBrace": 1,
"FunctionExpressionOpeningBrace":0,
"IIFEClosingParentheses": 0,
"IfStatement": ">=1",
"IfStatementClosingBrace": ">=1",
"IfStatementOpeningBrace": 0,
"LogicalExpression": -1,
"MemberExpressionClosing": 0,
"MemberExpressionOpening": 0,
"MemberExpressionPeriod": -1,
"MethodDefinition": ">=1",
"ObjectExpressionClosingBrace": "<=1",
"ObjectPatternClosingBrace": 0,
"ObjectPatternComma": 0,
"ObjectPatternOpeningBrace": 0,
"ParameterDefault": 0,
"Property": "<=2",
"PropertyValue": 0,
"ReturnStatement": -1,
"SwitchClosingBrace": ">=1",
"SwitchOpeningBrace": 0,
"ThisExpression": -1,
"ThrowStatement": ">=1",
"TryClosingBrace": ">=1",
"TryKeyword": -1,
"TryOpeningBrace": 0,
"VariableDeclaration": ">=1",
"VariableDeclarationSemiColon": 0,
"VariableDeclarationWithoutInit": ">=1",
"VariableName": ">=1",
"VariableValue": 0,
"WhileStatement": ">=1",
"WhileStatementClosingBrace": ">=1",
"WhileStatementOpeningBrace": 0
},
"after": {
"ArrayPatternClosing": 0,
"ArrayPatternComma": 0,
"ArrayPatternOpening": 0,
"ArrowFunctionExpressionArrow": 0,
"ArrowFunctionExpressionClosingBrace": -1,
"ArrowFunctionExpressionOpeningBrace": ">=1",
"AssignmentExpression": ">=1",
"AssignmentOperator": 0,
"BlockStatement": 0,
"BreakKeyword": -1,
"CallExpression": -1,
"CallExpressionClosingParentheses": -1,
"CallExpressionOpeningParentheses": -1,
"CatchClosingBrace": ">=0",
"CatchKeyword": 0,
"CatchOpeningBrace": ">=1",
"ClassDeclaration": ">=1",
"ClassDeclarationClosingBrace": ">=1",
"ClassDeclarationOpeningBrace": ">=1",
"ConditionalExpression": ">=1",
"DeleteOperator": ">=1",
"DoWhileStatement": ">=1",
"DoWhileStatementClosingBrace": 0,
"DoWhileStatementOpeningBrace": ">=1",
"ElseIfStatement": ">=1",
"ElseIfStatementClosingBrace": ">=1",
"ElseIfStatementOpeningBrace": ">=1",
"ElseStatement": ">=1",
"ElseStatementClosingBrace": ">=1",
"ElseStatementOpeningBrace": ">=1",
"EmptyStatement": -1,
"FinallyClosingBrace": ">=1",
"FinallyKeyword": -1,
"FinallyOpeningBrace": ">=1",
"ForInStatement": ">=1",
"ForInStatementClosingBrace": ">=1",
"ForInStatementExpressionClosing": -1,
"ForInStatementExpressionOpening": "<2",
"ForInStatementOpeningBrace": ">=1",
"ForStatement": ">=1",
"ForStatementClosingBrace": ">=1",
"ForStatementExpressionClosing": -1,
"ForStatementExpressionOpening": "<2",
"ForStatementOpeningBrace": ">=1",
"FunctionDeclaration": ">=1",
"FunctionDeclarationClosingBrace": ">=1",
"FunctionDeclarationOpeningBrace": ">=1",
"FunctionExpression": 0,
"FunctionExpressionClosingBrace": -1,
"FunctionExpressionOpeningBrace": 1,
"IIFEOpeningParentheses": 0,
"IfStatement": ">=1",
"IfStatementClosingBrace": ">=1",
"IfStatementOpeningBrace": ">=1",
"LogicalExpression": -1,
"MemberExpressionClosing": 0,
"MemberExpressionOpening": 0,
"MemberExpressionPeriod": 0,
"MethodDefinition": ">=1",
"ObjectExpressionOpeningBrace": "<=1",
"ObjectPatternClosingBrace": 0,
"ObjectPatternComma": 0,
"ObjectPatternOpeningBrace": 0,
"ParameterDefault": 0,
"Property": -1,
"PropertyName": 0,
"ReturnStatement": -1,
"SwitchCaseColon": ">=1",
"SwitchClosingBrace": ">=1",
"SwitchOpeningBrace": ">=1",
"ThisExpression": 0,
"ThrowStatement": ">=1",
"TryClosingBrace": 0,
"TryKeyword": -1,
"TryOpeningBrace": ">=1",
"VariableDeclaration": ">=1",
"VariableDeclarationSemiColon": ">=1",
"VariableValue": -1,
"WhileStatement": ">=1",
"WhileStatementClosingBrace": ">=1",
"WhileStatementOpeningBrace": ">=1"
}
},
"whiteSpace": {
"value": " ",
"removeTrailing": 1,
"before": {
"ArgumentComma": 0,
"ArgumentList": 0,
"ArgumentListArrayExpression": 0,
"ArgumentListFunctionExpression": 1,
"ArgumentListObjectExpression": 0,
"ArrayExpressionClosing": 0,
"ArrayExpressionComma": 0,
"ArrayExpressionOpening": 1,
"AssignmentOperator": 1,
"BinaryExpression": 0,
"BinaryExpressionOperator": 1,
"BlockComment": 1,
"CallExpression": 1,
"CatchClosingBrace": 1,
"CatchKeyword": 1,
"CatchOpeningBrace": 1,
"CatchParameterList": 0,
"CommaOperator": 0,
"ConditionalExpressionAlternate": 1,
"ConditionalExpressionConsequent": 1,
"DoWhileStatementClosingBrace": 1,
"DoWhileStatementConditional": 1,
"DoWhileStatementOpeningBrace": 1,
"ElseIfStatementClosingBrace": 1,
"ElseIfStatementOpeningBrace": 1,
"ElseStatementClosingBrace": 1,
"ElseStatementOpeningBrace": 1,
"EmptyStatement": 0,
"ExpressionClosingParentheses": 0,
"FinallyClosingBrace": 1,
"FinallyKeyword": -1,
"FinallyOpeningBrace": 1,
"ForInStatement": 1,
"ForInStatementClosingBrace": 1,
"ForInStatementExpressionClosing": 0,
"ForInStatementExpressionOpening": 1,
"ForInStatementOpeningBrace": 1,
"ForStatement": 1,
"ForStatementClosingBrace": 1,
"ForStatementExpressionClosing": 0,
"ForStatementExpressionOpening": 1,
"ForStatementOpeningBrace": 1,
"ForStatementSemicolon": 0,
"FunctionDeclarationClosingBrace": 1,
"FunctionDeclarationOpeningBrace": 1,
"FunctionExpressionClosingBrace": 1,
"FunctionExpressionOpeningBrace": 1,
"IfStatementClosingBrace": 1,
"IfStatementConditionalClosing": 0,
"IfStatementConditionalOpening": 1,
"IfStatementOpeningBrace": 1,
"LineComment": 1,
"LogicalExpressionOperator": 1,
"MemberExpressionClosing": 0,
"ObjectExpressionClosingBrace": 1,
"ParameterComma": 0,
"ParameterList": 0,
"Property": 1,
"PropertyName": 1,
"PropertyValue": 1,
"SwitchDiscriminantClosing": 0,
"SwitchDiscriminantOpening": 1,
"ThrowKeyword": 1,
"TryClosingBrace": 1,
"TryKeyword": -1,
"TryOpeningBrace": 1,
"UnaryExpressionOperator": 0,
"VariableName": 1,
"VariableValue": 1,
"WhileStatementClosingBrace": 1,
"WhileStatementConditionalClosing": 0,
"WhileStatementConditionalOpening": 1,
"WhileStatementOpeningBrace": 1
},
"after": {
"ArgumentComma": 1,
"ArgumentList": 0,
"ArgumentListArrayExpression": 1,
"ArgumentListFunctionExpression": 1,
"ArgumentListObjectExpression": 0,
"ArrayExpressionClosing": 0,
"ArrayExpressionComma": 1,
"ArrayExpressionOpening": 0,
"AssignmentOperator": 1,
"BinaryExpression": 0,
"BinaryExpressionOperator": 1,
"BlockComment": 1,
"CallExpression": 0,
"CatchClosingBrace": 1,
"CatchKeyword": 1,
"CatchOpeningBrace": 1,
"CatchParameterList": 0,
"CommaOperator": 1,
"ConditionalExpressionConsequent": 1,
"ConditionalExpressionTest": 1,
"DoWhileStatementBody": 1,
"DoWhileStatementClosingBrace": 1,
"DoWhileStatementOpeningBrace": 1,
"ElseIfStatementClosingBrace": 1,
"ElseIfStatementOpeningBrace": 1,
"ElseStatementClosingBrace": 1,
"ElseStatementOpeningBrace": 1,
"EmptyStatement": 0,
"ExpressionOpeningParentheses": 0,
"FinallyClosingBrace": 1,
"FinallyKeyword": -1,
"FinallyOpeningBrace": 1,
"ForInStatement": 1,
"ForInStatementClosingBrace": 1,
"ForInStatementExpressionClosing": 1,
"ForInStatementExpressionOpening": 0,
"ForInStatementOpeningBrace": 1,
"ForStatement": 1,
"ForStatementClosingBrace": 1,
"ForStatementExpressionClosing": 1,
"ForStatementExpressionOpening": 0,
"ForStatementOpeningBrace": 1,
"ForStatementSemicolon": 1,
"FunctionDeclarationClosingBrace": 0,
"FunctionDeclarationOpeningBrace": 0,
"FunctionExpressionClosingBrace": 0,
"FunctionExpressionOpeningBrace": 0,
"FunctionName": 0,
"FunctionReservedWord": 0,
"IfStatementClosingBrace": 1,
"IfStatementConditionalClosing": 0,
"IfStatementConditionalOpening": 0,
"IfStatementOpeningBrace": 1,
"LogicalExpressionOperator": 1,
"MemberExpressionOpening": 0,
"ObjectExpressionClosingBrace": 0,
"ObjectExpressionOpeningBrace": 1,
"ParameterComma": 1,
"ParameterList": 0,
"PropertyName": 0,
"PropertyValue": 0,
"SwitchDiscriminantClosing": 1,
"SwitchDiscriminantOpening": 0,
"ThrowKeyword": 1,
"TryClosingBrace": 1,
"TryKeyword": -1,
"TryOpeningBrace": 1,
"UnaryExpressionOperator": 0,
"VariableName": 1,
"WhileStatementClosingBrace": 1,
"WhileStatementConditionalClosing": 1,
"WhileStatementConditionalOpening": 0,
"WhileStatementOpeningBrace": 1
}
}
}

View File

@@ -1 +1,2 @@
**/JsLibraries/**
**/*.css.d.ts

View File

@@ -1,293 +0,0 @@
{
"parser": "babel-eslint",
"env": {
"browser": true,
"commonjs": true,
"node": true,
"es6": true
},
"globals": {
"expect": false,
"chai": false,
"sinon": false
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"modules": true,
"impliedStrict": true
}
},
"plugins": [
"filenames",
"react"
],
"settings": {
"react": {
"version": "detect"
}
},
"rules": {
"filenames/match-exported": ["error"],
# ECMAScript 6
"arrow-body-style": [0],
"arrow-parens": ["error", "always"],
"arrow-spacing": ["error", { "before": true, "after": true }],
"constructor-super": "error",
"generator-star-spacing": "off",
"no-class-assign": "error",
"no-confusing-arrow": "error",
"no-const-assign": "error",
"no-dupe-class-members": "error",
"no-duplicate-imports": "error",
"no-new-symbol": "error",
"no-this-before-super": "error",
"no-useless-escape": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-var": "warn",
"object-shorthand": ["error", "properties"],
"prefer-arrow-callback": "error",
"prefer-const": "warn",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "warn",
"prefer-template": "error",
"require-yield": "off",
"template-curly-spacing": ["error", "never"],
"yield-star-spacing": "off",
# Possible Errors
"comma-dangle": "error",
"no-cond-assign": "error",
"no-console": "off",
"no-constant-condition": "warn",
"no-control-regex": "error",
"no-debugger": "off",
"no-dupe-args": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "warn",
"no-empty-character-class": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": ["error", "functions"],
"no-extra-semi": "error",
"no-func-assign": "error",
"no-inner-declarations": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-negated-in-lhs": "error",
"no-obj-calls": "error",
"no-regex-spaces": "error",
"no-sparse-arrays": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "warn",
"no-unsafe-finally": "error",
"use-isnan": "error",
"valid-jsdoc": "off",
"valid-typeof": "error",
# Best Practices
"accessor-pairs": "off",
"array-callback-return": "warn",
"block-scoped-var": "warn",
"consistent-return": "off",
"curly": "error",
"default-case": "error",
"dot-location": ["error", "property"],
"dot-notation": "error",
"eqeqeq": ["error", "smart"],
"guard-for-in": "error",
"no-alert": "warn",
"no-caller": "error",
"no-case-declarations": "error",
"no-div-regex": "error",
"no-else-return": "error",
"no-empty-function": ["error", {"allow": ["arrowFunctions"]}],
"no-empty-pattern": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-implicit-coercion": ["error", {
"boolean": false,
"number": true,
"string": true,
"allow": [/* "!!", "~", "*", "+" */]
}],
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-invalid-this": "off",
"no-iterator": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-loop-func": "error",
"no-magic-numbers": ["off", {"ignoreArrayIndexes": true, "ignore": [0, 1] }],
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-native-reassign": ["error", {"exceptions": ["console"]}],
"no-new": "off",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-process-env": "off",
"no-proto": "error",
"no-redeclare": "error",
"no-return-assign": "warn",
"no-script-url": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"no-void": "error",
"no-warning-comments": "off",
"no-with": "error",
"radix": ["error", "as-needed"],
"vars-on-top": "off",
"wrap-iife": ["error", "inside"],
"yoda": "error",
# Strict Mode
"strict": ["error", "never"],
# Variables
"init-declarations": ["error", "always"],
"no-catch-shadow": "error",
"no-delete-var": "error",
"no-label-var": "error",
"no-restricted-globals": "off",
"no-shadow": "error",
"no-shadow-restricted-names": "error",
"no-undef": "error",
"no-undef-init": "off",
"no-undefined": "off",
"no-unused-vars": ["error", { "args": "none", "ignoreRestSiblings": true }],
"no-use-before-define": "error",
# Node.js and CommonJS
"callback-return": "warn",
"global-require": "error",
"handle-callback-err": "warn",
"no-mixed-requires": "error",
"no-new-require": "error",
"no-path-concat": "error",
"no-process-exit": "error",
# Stylistic Issues
"array-bracket-spacing": ["error", "never"],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
"camelcase": "off",
"comma-spacing": ["error", {"before": false, "after": true}],
"comma-style": ["error", "last"],
"computed-property-spacing": ["error", "never"],
"consistent-this": ["error", "self"],
"eol-last": "error",
"func-names": "off",
"func-style": ["error", "declaration"],
"indent": ["error", 2, {"SwitchCase": 1}],
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
"keyword-spacing": ["error", { "before": true, "after": true}],
"lines-around-comment": ["error", { "beforeBlockComment": true, "afterBlockComment": false }],
"max-depth": ["error", {"maximum": 5}],
"max-nested-callbacks": ["error", 4],
"max-statements": "off",
"max-statements-per-line": ["error", { "max": 1 }],
"new-cap": ["error", {"capIsNewExceptions": ["$.Deferred", "DragDropContext", "DragLayer", "DragSource", "DropTarget"]}],
"new-parens": "error",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "off",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-continue": "error",
"no-inline-comments": "off",
"no-lonely-if": "warn",
"no-mixed-spaces-and-tabs": "error",
"no-multiple-empty-lines": ["error", { "max": 1 }],
"no-negated-condition": "warn",
"no-nested-ternary": "error",
"no-new-object": "error",
"no-plusplus": "off",
"no-restricted-syntax": "off",
"no-spaced-func": "error",
"no-ternary": "off",
"no-trailing-spaces": "error",
"no-underscore-dangle": ["error", { "allowAfterThis": true }],
"no-unneeded-ternary": "error",
"no-whitespace-before-property": "error",
"object-curly-spacing": ["error", "always"],
"one-var": ["error", "never"],
"one-var-declaration-per-line": ["error", "always"],
"operator-assignment": ["off", "never"],
"operator-linebreak": ["error", "after"],
"quote-props": ["error", "as-needed"],
"quotes": ["error", "single"],
"require-jsdoc": "off",
"semi": "error",
"semi-spacing": ["error", { "before": false, "after": true }],
"sort-vars": "off",
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", "never"],
"space-in-parens": "off",
"space-infix-ops": "off",
"space-unary-ops": "off",
"spaced-comment": "error",
"wrap-regex": "error",
# React
"react/jsx-boolean-value": [2, "always"],
"react/jsx-uses-vars": 2,
"react/jsx-closing-bracket-location": 2,
"react/jsx-tag-spacing": ["error"],
"react/jsx-curly-spacing": [2, "never"],
"react/jsx-equals-spacing": [2, "never"],
"react/jsx-indent-props": [2, 2],
"react/jsx-indent": [2, 2],
"react/jsx-key": 2,
"react/jsx-no-bind": [2, { "allowArrowFunctions": true }],
"react/jsx-no-duplicate-props": [2, { "ignoreCase": true }],
"react/jsx-max-props-per-line": [2, { "maximum": 2 }],
"react/jsx-handler-names": [2, { "eventHandlerPrefix": "(on|dispatch)", "eventHandlerPropPrefix": "on" }],
"react/jsx-no-undef": 2,
"react/jsx-pascal-case": 2,
"react/jsx-uses-react": 2,
// Explicitly disabled in case we want to enable them again
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 0,
"react/no-direct-mutation-state": 2,
"react/no-multi-comp": [2, { "ignoreStateless": true }],
"react/no-unknown-property": 2,
"react/prefer-es6-class": 2,
"react/prop-types": 2,
"react/react-in-jsx-scope": 2,
"react/self-closing-comp": 2,
"react/sort-comp": 2,
"react/jsx-wrap-multilines": 2
}
}

393
frontend/.eslintrc.js Normal file
View File

@@ -0,0 +1,393 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const typescriptEslintRecommended = require('@typescript-eslint/eslint-plugin').configs.recommended;
const frontendFolder = __dirname;
const dirs = fs
.readdirSync(path.join(frontendFolder, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name)
.join('|');
module.exports = {
root: true,
parser: '@babel/eslint-parser',
env: {
browser: true,
commonjs: true,
node: true,
es6: true
},
globals: {
expect: false,
chai: false,
sinon: false,
JSX: true
},
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
babelOptions: {
configFile: `${frontendFolder}/babel.config.js`
},
ecmaFeatures: {
modules: true,
impliedStrict: true
}
},
plugins: [
'filenames',
'react',
'react-hooks',
'simple-import-sort',
'import',
'@typescript-eslint',
'prettier'
],
settings: {
react: {
version: 'detect'
}
},
rules: {
'filenames/match-exported': ['error'],
// ECMAScript 6
'arrow-body-style': [0],
'arrow-parens': ['error', 'always'],
'arrow-spacing': ['error', { before: true, after: true }],
'constructor-super': 'error',
'generator-star-spacing': 'off',
'no-class-assign': 'error',
'no-confusing-arrow': 'error',
'no-const-assign': 'error',
'no-dupe-class-members': 'error',
'no-duplicate-imports': 'error',
'no-new-symbol': 'error',
'no-this-before-super': 'error',
'no-useless-escape': 'error',
'no-useless-computed-key': 'error',
'no-useless-constructor': 'error',
'no-var': 'warn',
'object-shorthand': ['error', 'properties'],
'prefer-arrow-callback': 'error',
'prefer-const': 'warn',
'prefer-reflect': 'off',
'prefer-rest-params': 'off',
'prefer-spread': 'warn',
'prefer-template': 'error',
'require-yield': 'off',
'template-curly-spacing': ['error', 'never'],
'yield-star-spacing': 'off',
// Possible Errors
'comma-dangle': 'error',
'no-cond-assign': 'error',
'no-console': 'off',
'no-constant-condition': 'warn',
'no-control-regex': 'error',
'no-debugger': 'off',
'no-dupe-args': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': 'warn',
'no-empty-character-class': 'error',
'no-ex-assign': 'error',
'no-extra-boolean-cast': 'error',
'no-extra-parens': ['error', 'functions'],
'no-extra-semi': 'error',
'no-func-assign': 'error',
'no-inner-declarations': 'error',
'no-invalid-regexp': 'error',
'no-irregular-whitespace': 'error',
'no-negated-in-lhs': 'error',
'no-obj-calls': 'error',
'no-regex-spaces': 'error',
'no-sparse-arrays': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'warn',
'no-unsafe-finally': 'error',
'use-isnan': 'error',
'valid-jsdoc': 'off',
'valid-typeof': 'error',
// Best Practices
'accessor-pairs': 'off',
'array-callback-return': 'warn',
'block-scoped-var': 'warn',
'consistent-return': 'off',
curly: 'error',
'default-case': 'error',
'dot-location': ['error', 'property'],
'dot-notation': 'error',
eqeqeq: ['error', 'smart'],
'guard-for-in': 'error',
'no-alert': 'warn',
'no-caller': 'error',
'no-case-declarations': 'error',
'no-div-regex': 'error',
'no-else-return': 'error',
'no-empty-function': ['error', { allow: ['arrowFunctions'] }],
'no-empty-pattern': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-fallthrough': 'error',
'no-floating-decimal': 'error',
'no-implicit-coercion': ['error', {
boolean: false,
number: true,
string: true,
allow: [/* "!!", "~", "*", "+" */]
}],
'no-implicit-globals': 'error',
'no-implied-eval': 'error',
'no-invalid-this': 'off',
'no-iterator': 'error',
'no-labels': 'error',
'no-lone-blocks': 'error',
'no-loop-func': 'error',
'no-magic-numbers': ['off', { ignoreArrayIndexes: true, ignore: [0, 1] }],
'no-multi-spaces': 'error',
'no-multi-str': 'error',
'no-native-reassign': ['error', { exceptions: ['console'] }],
'no-new': 'off',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-param-reassign': 'off',
'no-process-env': 'off',
'no-proto': 'error',
'no-redeclare': 'error',
'no-return-assign': 'warn',
'no-script-url': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-throw-literal': 'error',
'no-unmodified-loop-condition': 'error',
'no-unused-expressions': 'error',
'no-unused-labels': 'error',
'no-useless-call': 'error',
'no-useless-concat': 'error',
'no-void': 'error',
'no-warning-comments': 'off',
'no-with': 'error',
radix: ['error', 'as-needed'],
'vars-on-top': 'off',
'wrap-iife': ['error', 'inside'],
yoda: 'error',
// Strict Mode
strict: ['error', 'never'],
// Variables
'init-declarations': ['error', 'always'],
'no-catch-shadow': 'error',
'no-delete-var': 'error',
'no-label-var': 'error',
'no-restricted-globals': 'off',
'no-shadow': 'error',
'no-shadow-restricted-names': 'error',
'no-undef': 'error',
'no-undef-init': 'off',
'no-undefined': 'off',
'no-unused-vars': ['error', { args: 'none', ignoreRestSiblings: true }],
'no-use-before-define': 'error',
// Node.js and CommonJS
'callback-return': 'warn',
'global-require': 'error',
'handle-callback-err': 'warn',
'no-mixed-requires': 'error',
'no-new-require': 'error',
'no-path-concat': 'error',
'no-process-exit': 'error',
// Stylistic Issues
'array-bracket-spacing': ['error', 'never'],
'block-spacing': ['error', 'always'],
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
camelcase: 'off',
'comma-spacing': ['error', { before: false, after: true }],
'comma-style': ['error', 'last'],
'computed-property-spacing': ['error', 'never'],
'consistent-this': ['error', 'self'],
'eol-last': 'error',
'func-names': 'off',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
indent: ['error', 2, { SwitchCase: 1 }],
'key-spacing': ['error', { beforeColon: false, afterColon: true }],
'keyword-spacing': ['error', { before: true, after: true }],
'lines-around-comment': ['error', { beforeBlockComment: true, afterBlockComment: false }],
'max-depth': ['error', { maximum: 5 }],
'max-nested-callbacks': ['error', 4],
'max-statements': 'off',
'max-statements-per-line': ['error', { max: 1 }],
'new-cap': ['error', { capIsNewExceptions: ['$.Deferred', 'DragDropContext', 'DragLayer', 'DragSource', 'DropTarget'] }],
'new-parens': 'error',
'newline-after-var': 'off',
'newline-before-return': 'off',
'newline-per-chained-call': 'off',
'no-array-constructor': 'error',
'no-bitwise': 'error',
'no-continue': 'error',
'no-inline-comments': 'off',
'no-lonely-if': 'warn',
'no-mixed-spaces-and-tabs': 'error',
'no-multiple-empty-lines': ['error', { max: 1 }],
'no-negated-condition': 'warn',
'no-nested-ternary': 'error',
'no-new-object': 'error',
'no-plusplus': 'off',
'no-restricted-syntax': 'off',
'no-spaced-func': 'error',
'no-ternary': 'off',
'no-trailing-spaces': 'error',
'no-underscore-dangle': ['error', { allowAfterThis: true }],
'no-unneeded-ternary': 'error',
'no-whitespace-before-property': 'error',
'object-curly-spacing': ['error', 'always'],
'one-var': ['error', 'never'],
'one-var-declaration-per-line': ['error', 'always'],
'operator-assignment': ['off', 'never'],
'operator-linebreak': ['error', 'after'],
'quote-props': ['error', 'as-needed'],
quotes: ['error', 'single'],
'require-jsdoc': 'off',
semi: 'error',
'semi-spacing': ['error', { before: false, after: true }],
'sort-vars': 'off',
'space-before-blocks': ['error', 'always'],
'space-before-function-paren': ['error', 'never'],
'space-in-parens': 'off',
'space-infix-ops': 'off',
'space-unary-ops': 'off',
'spaced-comment': 'error',
'wrap-regex': 'error',
// ImportSort
'simple-import-sort/imports': 'error',
'import/newline-after-import': 'error',
// React
'react/jsx-boolean-value': [2, 'always'],
'react/jsx-uses-vars': 2,
'react/jsx-closing-bracket-location': 2,
'react/jsx-tag-spacing': ['error'],
'react/jsx-curly-spacing': [2, 'never'],
'react/jsx-equals-spacing': [2, 'never'],
'react/jsx-indent-props': [2, 2],
'react/jsx-indent': [2, 2, { indentLogicalExpressions: true }],
'react/jsx-key': 2,
'react/jsx-no-bind': [2, { allowArrowFunctions: true }],
'react/jsx-no-duplicate-props': [2, { ignoreCase: true }],
'react/jsx-max-props-per-line': [2, { maximum: 2 }],
'react/jsx-handler-names': [2, { eventHandlerPrefix: '(on|dispatch)', eventHandlerPropPrefix: 'on' }],
'react/jsx-no-undef': 2,
'react/jsx-pascal-case': 2,
'react/jsx-uses-react': 2,
// Explicitly disabled in case we want to enable them again
'react/no-did-mount-set-state': 0,
'react/no-did-update-set-state': 0,
'react/no-direct-mutation-state': 2,
'react/no-multi-comp': [2, { ignoreStateless: true }],
'react/no-unknown-property': 2,
'react/prefer-es6-class': 2,
'react/prop-types': 2,
'react/react-in-jsx-scope': 2,
'react/self-closing-comp': 2,
'react/sort-comp': 2,
'react/jsx-wrap-multilines': 2,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error'
},
overrides: [
{
files: [
'*.js'
],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
// Packages
// Absolute Paths
// Relative Paths
// Css
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
]
}
]
}
},
{
files: [
'*.ts',
'*.tsx'
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json'
},
extends: [
'prettier'
],
rules: Object.assign(typescriptEslintRecommended.rules, {
'no-shadow': 'off',
// These should be enabled after cleaning things up
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
'react/prop-types': 'off',
'prettier/prettier': 'error',
'simple-import-sort/imports': [
'error',
{
groups: [
// Packages
// Absolute Paths
// Relative Paths
// Css
['^@?\\w', `^(${dirs})(/.*|$)`, '^\\.', '^\\..*css$']
]
}
]
})
},
{
files: [
'*.css.d.ts'
],
rules: {
'filenames/match-exported': 'off',
'init-declarations': 'off',
'prettier/prettier': 'off'
}
}
]
};

View File

@@ -1,12 +0,0 @@
{
"js": {
"indent_size": 2,
"indent_char": " ",
"indent_level": 2,
"indent_with_tabs": false,
"preserve_newlines": true,
"brace_style": "collapse",
"max_preserve_newlines": 2,
"jslint_happy": true
}
}

10
frontend/.prettierignore Normal file
View File

@@ -0,0 +1,10 @@
# Ignore everything recursively
*
# But not the .ts files
!*.ts*
*css.d.ts
# Check subdirectories too
!*/

View File

@@ -0,0 +1,6 @@
{
"arrowParens": "always",
"endOfLine": "auto",
"singleQuote": true,
"trailingComma": "es5"
}

View File

@@ -1,12 +1,12 @@
{
"plugins": [
"stylelint-order"
],
"ignoreFiles": [
"frontend/src/Styles/scaffolding.css",
"**/*.js"
],
"rules": {
"plugins": [
"stylelint-order"
],
"ignoreFiles": [
"frontend/src/Styles/scaffolding.css",
"**/*.js"
],
"rules": {
"at-rule-empty-line-before": [
"always",
{
@@ -15,96 +15,46 @@
]
}
],
"at-rule-name-case": "lower",
"at-rule-name-newline-after": "always-multi-line",
"at-rule-name-space-after": "always",
"at-rule-no-unknown": [
true,
{
"ignoreAtRules": [
"/^add\\-mixin$/",
"/^define\\-mixin$/"
]
]
}
],
"at-rule-no-vendor-prefix": true,
"at-rule-semicolon-newline-after": "always",
"at-rule-semicolon-space-before": "never",
"block-closing-brace-empty-line-before": "never",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always",
"block-closing-brace-space-after": "always-single-line",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always",
"block-opening-brace-newline-before": "never-single-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": "lower",
"color-hex-length": "short",
"color-named": "never",
"color-no-invalid-hex": true,
"comment-whitespace-inside": "always",
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-duplicate-properties": [
true,
{
"ignoreProperties": [
"composes"
"composes"
]
}
],
"declaration-block-no-redundant-longhand-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-semicolon-newline-after": "always",
"declaration-block-semicolon-newline-before": "never-multi-line",
"declaration-block-semicolon-space-before": "never",
"declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always",
"declaration-colon-space-after": "always",
"declaration-colon-space-before": "never",
"font-family-name-quotes": "always-unless-keyword",
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "never-multi-line",
"function-comma-newline-before": "never-multi-line",
"function-comma-space-after": "always",
"function-comma-space-before": "never",
"function-linear-gradient-no-nonstandard-direction": true,
"function-name-case": "lower",
"function-parentheses-newline-inside": "never-multi-line",
"function-parentheses-space-inside": "never",
"function-url-quotes": "always",
"function-url-scheme-disallowed-list": [
"data"
],
"function-whitespace-after": "always",
"indentation": 2,
"keyframe-declaration-no-important": true,
"length-zero-no-unit": true,
"max-empty-lines": 1,
"max-line-length": [
100,
{
"ignore": [
"non-comments"
]
}
],
"max-nesting-depth": 2,
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-name-case": "lower",
"media-feature-name-no-vendor-prefix": true,
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"no-empty-source": true,
"no-eol-whitespace": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"no-missing-end-of-source-newline": true,
"number-leading-zero": "always",
"number-no-trailing-zeros": true,
"order/order": [
"custom-properties",
"dollar-variables",
@@ -132,6 +82,7 @@
"right",
"bottom",
"left",
"inset",
"z-index",
"display",
"visibility",
@@ -343,54 +294,33 @@
]
}
],
"property-case": "lower",
"property-no-vendor-prefix": true,
"rule-empty-line-before": [
"always",
{
"except": [
"first-nested"
"first-nested"
],
"ignore": [
"after-comment"
"after-comment"
]
}
],
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-attribute-quotes": "never",
"selector-class-pattern": "^[A-Za-z0-9]+$",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-descendant-combinator-no-non-space": true,
"selector-list-comma-newline-after": "always",
"selector-list-comma-newline-before": "never-multi-line",
"selector-list-comma-space-before": "never",
"selector-max-attribute": 0,
"selector-max-class": 3,
"selector-max-compound-selectors": 3,
"selector-max-empty-lines": 0,
"selector-max-id": 0,
"selector-max-universal": 0,
"selector-pseudo-class-case": "lower",
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"shorthand-property-no-redundant-values": true,
"string-no-newline": true,
"string-quotes": "single",
"time-min-milliseconds": 100,
"unit-case": "lower",
"unit-no-unknown": true,
"value-list-comma-newline-after": "never-multi-line",
"value-list-comma-newline-before": "never-multi-line",
"value-list-comma-space-after": "always",
"value-list-comma-space-before": "never",
"value-list-max-empty-lines": 0,
"value-no-vendor-prefix": true
}
}
}

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

@@ -0,0 +1,7 @@
{
"recommendations": [
"stylelint.vscode-stylelint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

23
frontend/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,23 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.insertFinalNewline": true,
"files.exclude": {
"**/node_modules": true,
"**/*.d.css": true
},
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"typescript.preferences.quoteStyle": "single",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
}

View File

@@ -4,20 +4,21 @@ module.exports = {
plugins: [
// Stage 1
'@babel/plugin-proposal-export-default-from',
['@babel/plugin-proposal-optional-chaining', { loose }],
['@babel/plugin-proposal-nullish-coalescing-operator', { loose }],
['@babel/plugin-transform-optional-chaining', { loose }],
['@babel/plugin-transform-nullish-coalescing-operator', { loose }],
// Stage 2
'@babel/plugin-proposal-export-namespace-from',
'@babel/plugin-transform-export-namespace-from',
// Stage 3
['@babel/plugin-proposal-class-properties', { loose }],
['@babel/plugin-transform-class-properties', { loose }],
'@babel/plugin-syntax-dynamic-import'
],
env: {
development: {
presets: [
['@babel/preset-react', { development: true }]
['@babel/preset-react', { development: true }],
'@babel/preset-typescript'
],
plugins: [
'babel-plugin-inline-classnames'
@@ -25,7 +26,8 @@ module.exports = {
},
production: {
presets: [
'@babel/preset-react'
'@babel/preset-react',
'@babel/preset-typescript'
],
plugins: [
'babel-plugin-transform-react-remove-prop-types'

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const webpack = require('webpack');
const FileManagerPlugin = require('filemanager-webpack-plugin');
@@ -5,6 +6,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const LiveReloadPlugin = require('webpack-livereload-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = (env) => {
const uiFolder = 'UI';
@@ -34,41 +36,54 @@ module.exports = (env) => {
},
entry: {
index: 'index.js'
index: 'index.ts'
},
resolve: {
extensions: [
'.ts',
'.tsx',
'.js'
],
modules: [
srcFolder,
path.join(srcFolder, 'Shims'),
'node_modules'
],
alias: {
jquery: 'jquery/src/jquery',
jquery: 'jquery/dist/jquery.min',
'react-middle-truncate': 'react-middle-truncate/lib/react-middle-truncate'
},
fallback: {
buffer: false,
http: false,
https: false,
url: false,
util: false,
net: false
}
},
output: {
path: distFolder,
publicPath: '/',
filename: '[name].js',
filename: '[name]-[contenthash].js',
sourceMapFilename: '[file].map'
},
optimization: {
moduleIds: 'deterministic',
chunkIds: 'named',
splitChunks: {
chunks: 'initial',
name: 'vendors'
}
chunkIds: isProduction ? 'deterministic' : 'named'
},
performance: {
hints: false
},
experiments: {
topLevelAwait: true
},
plugins: [
new webpack.DefinePlugin({
__DEV__: !isProduction,
@@ -76,13 +91,15 @@ module.exports = (env) => {
}),
new MiniCssExtractPlugin({
filename: 'Content/styles.css'
filename: 'Content/styles.css',
chunkFilename: 'Content/[id]-[chunkhash].css'
}),
new HtmlWebpackPlugin({
template: 'frontend/src/index.ejs',
filename: 'index.html',
publicPath: '/'
publicPath: '/',
inject: false
}),
new FileManagerPlugin({
@@ -123,6 +140,8 @@ module.exports = (env) => {
}
}),
new ForkTsCheckerWebpackPlugin(),
new LiveReloadPlugin()
],
@@ -146,7 +165,7 @@ module.exports = (env) => {
}
},
{
test: /\.js?$/,
test: [/\.jsx?$/, /\.tsx?$/],
exclude: /(node_modules|JsLibraries)/,
use: [
{
@@ -177,6 +196,7 @@ module.exports = (env) => {
exclude: /(node_modules|globals.css)/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-modules-typescript-loader' },
{
loader: 'css-loader',
options: {
@@ -245,18 +265,19 @@ module.exports = (env) => {
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
config.optimization.minimizer = [
new TerserPlugin({
cache: true,
parallel: true,
sourceMap: true, // Must be set to true if using source-maps in production
terserOptions: {
mangle: false,
keep_classnames: true,
keep_fnames: true
}
})
];
config.optimization = {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
sourceMap: true, // Must be set to true if using source-maps in production
mangle: false,
keep_classnames: true,
keep_fnames: true
}
})
]
};
}
return config;

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line filenames/match-exported
const loaderUtils = require('loader-utils');
module.exports = function cssVariablesLoader(source) {

View File

@@ -1,20 +0,0 @@
{
"compilerOptions": {
"target": "es6",
"checkJs": false,
"baseUrl": "src",
"jsx": "react",
"module": "commonjs",
"moduleResolution": "node",
"paths": {
"*": [
"*"
]
}
},
"include": [
"./src/**/*"
],
"exclude": [
]
}

View File

@@ -1,7 +1,6 @@
const reload = require('require-nocache')(module);
const cssVarsFiles = [
'./src/Styles/Variables/colors',
'./src/Styles/Variables/dimensions',
'./src/Styles/Variables/fonts',
'./src/Styles/Variables/animations',

View File

@@ -1,4 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.insertFinalNewline": true
}

View File

@@ -1,23 +1,25 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
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 { align, icons, kinds } from 'Helpers/Props';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
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 BlocklistRowConnector from './BlocklistRowConnector';
class Blocklist extends Component {
@@ -34,6 +36,7 @@ class Blocklist extends Component {
lastToggled: null,
selectedState: {},
isConfirmRemoveModalOpen: false,
isConfirmClearModalOpen: false,
items: props.items
};
}
@@ -60,33 +63,46 @@ class Blocklist extends Component {
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
}
};
//
// Listeners
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
}
};
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
}
};
onRemoveSelectedPress = () => {
this.setState({ isConfirmRemoveModalOpen: true });
}
};
onRemoveSelectedConfirmed = () => {
this.props.onRemoveSelected(this.getSelectedIds());
this.setState({ isConfirmRemoveModalOpen: false });
}
};
onConfirmRemoveModalClose = () => {
this.setState({ isConfirmRemoveModalOpen: false });
}
};
onClearBlocklistPress = () => {
this.setState({ isConfirmClearModalOpen: true });
};
onClearBlocklistConfirmed = () => {
this.props.onClearBlocklistPress();
this.setState({ isConfirmClearModalOpen: false });
};
onConfirmClearModalClose = () => {
this.setState({ isConfirmClearModalOpen: false });
};
//
// Render
@@ -101,7 +117,6 @@ class Blocklist extends Component {
totalRecords,
isRemoving,
isClearingBlocklistExecuting,
onClearBlocklistPress,
...otherProps
} = this.props;
@@ -109,17 +124,18 @@ class Blocklist extends Component {
allSelected,
allUnselected,
selectedState,
isConfirmRemoveModalOpen
isConfirmRemoveModalOpen,
isConfirmClearModalOpen
} = this.state;
const selectedIds = this.getSelectedIds();
return (
<PageContent title="Blocklist">
<PageContent title={translate('Blocklist')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Remove Selected"
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={!selectedIds.length}
isSpinning={isRemoving}
@@ -127,10 +143,11 @@ class Blocklist extends Component {
/>
<PageToolbarButton
label="Clear"
label={translate('Clear')}
iconName={icons.CLEAR}
isDisabled={!items.length}
isSpinning={isClearingBlocklistExecuting}
onPress={onClearBlocklistPress}
onPress={this.onClearBlocklistPress}
/>
</PageToolbarSection>
@@ -140,7 +157,7 @@ class Blocklist extends Component {
columns={columns}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
@@ -150,67 +167,79 @@ class Blocklist extends Component {
<PageContentBody>
{
isFetching && !isPopulated &&
<LoadingIndicator />
<LoadingIndicator />
}
{
!isFetching && !!error &&
<div>Unable to load blocklist</div>
<Alert kind={kinds.DANGER}>
{translate('BlocklistLoadError')}
</Alert>
}
{
isPopulated && !error && !items.length &&
<div>
No history blocklist
</div>
<Alert kind={kinds.INFO}>
{translate('NoHistoryBlocklist')}
</Alert>
}
{
isPopulated && !error && !!items.length &&
<div>
<Table
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
columns={columns}
{...otherProps}
onSelectAllChange={this.onSelectAllChange}
>
<TableBody>
{
items.map((item) => {
return (
<BlocklistRowConnector
key={item.id}
isSelected={selectedState[item.id] || false}
columns={columns}
{...item}
onSelectedChange={this.onSelectedChange}
/>
);
})
}
</TableBody>
</Table>
<div>
<Table
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
columns={columns}
{...otherProps}
onSelectAllChange={this.onSelectAllChange}
>
<TableBody>
{
items.map((item) => {
return (
<BlocklistRowConnector
key={item.id}
isSelected={selectedState[item.id] || false}
columns={columns}
{...item}
onSelectedChange={this.onSelectedChange}
/>
);
})
}
</TableBody>
</Table>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
<TablePager
totalRecords={totalRecords}
isFetching={isFetching}
{...otherProps}
/>
</div>
}
</PageContentBody>
<ConfirmModal
isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER}
title="Remove Selected"
message={'Are you sure you want to remove the selected items from the blocklist?'}
confirmLabel="Remove Selected"
title={translate('RemoveSelected')}
message={translate('RemoveSelectedBlocklistMessageText')}
confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose}
/>
<ConfirmModal
isOpen={isConfirmClearModalOpen}
kind={kinds.DANGER}
title={translate('ClearBlocklist')}
message={translate('ClearBlocklistMessageText')}
confirmLabel={translate('Clear')}
onConfirm={this.onClearBlocklistConfirmed}
onCancel={this.onConfirmClearModalClose}
/>
</PageContent>
);
}

View File

@@ -2,12 +2,12 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import * as blocklistActions from 'Store/Actions/blocklistActions';
import { executeCommand } from 'Store/Actions/commandActions';
import * as commandNames from 'Commands/commandNames';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import Blocklist from './Blocklist';
function createMapStateToProps() {
@@ -65,49 +65,41 @@ class BlocklistConnector extends Component {
repopulate = () => {
this.props.fetchBlocklist();
}
};
//
// Listeners
onFirstPagePress = () => {
this.props.gotoBlocklistFirstPage();
}
};
onPreviousPagePress = () => {
this.props.gotoBlocklistPreviousPage();
}
};
onNextPagePress = () => {
this.props.gotoBlocklistNextPage();
}
};
onLastPagePress = () => {
this.props.gotoBlocklistLastPage();
}
};
onPageSelect = (page) => {
this.props.gotoBlocklistPage({ page });
}
};
onRemoveSelected = (ids) => {
this.props.removeBlocklistItems({ ids });
}
};
onSortPress = (sortKey) => {
this.props.setBlocklistSort({ sortKey });
}
onTableOptionChange = (payload) => {
this.props.setBlocklistTableOption(payload);
if (payload.pageSize) {
this.props.gotoBlocklistFirstPage();
}
}
};
onClearBlocklistPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
}
};
onTableOptionChange = (payload) => {
this.props.setBlocklistTableOption(payload);
@@ -115,7 +107,7 @@ class BlocklistConnector extends Component {
if (payload.pageSize) {
this.props.gotoBlocklistFirstPage();
}
}
};
//
// Render

View File

@@ -1,13 +1,14 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Button from 'Components/Link/Button';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
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 translate from 'Utilities/String/translate';
class BlocklistDetailsModal extends Component {
@@ -39,19 +40,19 @@ class BlocklistDetailsModal extends Component {
<ModalBody>
<DescriptionList>
<DescriptionListItem
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
<DescriptionListItem
title="Protocol"
title={translate('Protocol')}
data={protocol}
/>
{
!!message &&
<DescriptionListItem
title="Indexer"
title={translate('Indexer')}
data={indexer}
/>
}
@@ -59,7 +60,7 @@ class BlocklistDetailsModal extends Component {
{
!!message &&
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/>
}
@@ -68,7 +69,7 @@ class BlocklistDetailsModal extends Component {
<ModalFooter>
<Button onPress={onModalClose}>
Close
{translate('Close')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,4 +1,4 @@
.language,
.languages,
.quality {
composes: cell from '~Components/Table/Cells/TableRowCell.css';

View File

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

View File

@@ -1,14 +1,16 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { icons, kinds } from 'Helpers/Props';
import IconButton from 'Components/Link/IconButton';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRow from 'Components/Table/TableRow';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import EpisodeLanguage from 'Episode/EpisodeLanguage';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import EpisodeFormats from 'Episode/EpisodeFormats';
import EpisodeLanguages from 'Episode/EpisodeLanguages';
import EpisodeQuality from 'Episode/EpisodeQuality';
import { icons, kinds } from 'Helpers/Props';
import SeriesTitleLink from 'Series/SeriesTitleLink';
import translate from 'Utilities/String/translate';
import BlocklistDetailsModal from './BlocklistDetailsModal';
import styles from './BlocklistRow.css';
@@ -30,11 +32,11 @@ class BlocklistRow extends Component {
onDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
}
};
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
}
};
//
// Render
@@ -44,8 +46,9 @@ class BlocklistRow extends Component {
id,
series,
sourceTitle,
language,
languages,
quality,
customFormats,
date,
protocol,
indexer,
@@ -94,14 +97,14 @@ class BlocklistRow extends Component {
);
}
if (name === 'language') {
if (name === 'languages') {
return (
<TableRowCell
key={name}
className={styles.language}
className={styles.languages}
>
<EpisodeLanguage
language={language}
<EpisodeLanguages
languages={languages}
/>
</TableRowCell>
);
@@ -120,6 +123,16 @@ class BlocklistRow extends Component {
);
}
if (name === 'customFormats') {
return (
<TableRowCell key={name}>
<EpisodeFormats
formats={customFormats}
/>
</TableRowCell>
);
}
if (name === 'date') {
return (
<RelativeDateCellConnector
@@ -152,7 +165,7 @@ class BlocklistRow extends Component {
/>
<IconButton
title="Remove from blocklist"
title={translate('RemoveFromBlocklist')}
name={icons.REMOVE}
kind={kinds.DANGER}
onPress={onRemovePress}
@@ -183,8 +196,9 @@ BlocklistRow.propTypes = {
id: PropTypes.number.isRequired,
series: PropTypes.object.isRequired,
sourceTitle: PropTypes.string.isRequired,
language: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
date: PropTypes.string.isRequired,
protocol: PropTypes.string.isRequired,
indexer: PropTypes.string,

View File

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

View File

@@ -1,13 +1,14 @@
import PropTypes from 'prop-types';
import React from 'react';
import formatAge from 'Utilities/Number/formatAge';
import formatDateTime from 'Utilities/Date/formatDateTime';
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
import Link from 'Components/Link/Link';
import DescriptionList from 'Components/DescriptionList/DescriptionList';
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
import DescriptionListItemDescription from 'Components/DescriptionList/DescriptionListItemDescription';
import DescriptionListItemTitle from 'Components/DescriptionList/DescriptionListItemTitle';
import Link from 'Components/Link/Link';
import formatDateTime from 'Utilities/Date/formatDateTime';
import formatAge from 'Utilities/Number/formatAge';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import translate from 'Utilities/String/translate';
import styles from './HistoryDetails.css';
function HistoryDetails(props) {
@@ -15,6 +16,7 @@ function HistoryDetails(props) {
eventType,
sourceTitle,
data,
downloadId,
shortDateFormat,
timeFormat
} = props;
@@ -23,12 +25,11 @@ function HistoryDetails(props) {
const {
indexer,
releaseGroup,
preferredWordScore,
seriesMatchType,
customFormatScore,
nzbInfoUrl,
downloadClient,
downloadClientName,
downloadId,
age,
ageHours,
ageMinutes,
@@ -41,14 +42,14 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
indexer ?
<DescriptionListItem
title="Indexer"
title={translate('Indexer')}
data={indexer}
/> :
null
@@ -58,17 +59,17 @@ function HistoryDetails(props) {
releaseGroup ?
<DescriptionListItem
descriptionClassName={styles.description}
title="Release Group"
title={translate('ReleaseGroup')}
data={releaseGroup}
/> :
null
}
{
preferredWordScore && preferredWordScore !== '0' ?
customFormatScore && customFormatScore !== '0' ?
<DescriptionListItem
title="Preferred Word Score"
data={formatPreferredWordScore(preferredWordScore)}
title={translate('CustomFormatScore')}
data={formatCustomFormatScore(customFormatScore)}
/> :
null
}
@@ -77,7 +78,7 @@ function HistoryDetails(props) {
seriesMatchType ?
<DescriptionListItem
descriptionClassName={styles.description}
title="Series Match Type"
title={translate('SeriesMatchType')}
data={seriesMatchType}
/> :
null
@@ -87,7 +88,7 @@ function HistoryDetails(props) {
nzbInfoUrl ?
<span>
<DescriptionListItemTitle>
Info URL
{translate('InfoUrl')}
</DescriptionListItemTitle>
<DescriptionListItemDescription>
@@ -100,7 +101,7 @@ function HistoryDetails(props) {
{
downloadClientNameInfo ?
<DescriptionListItem
title="Download Client"
title={translate('DownloadClient')}
data={downloadClientNameInfo}
/> :
null
@@ -109,7 +110,7 @@ function HistoryDetails(props) {
{
downloadId ?
<DescriptionListItem
title="Grab ID"
title={translate('GrabId')}
data={downloadId}
/> :
null
@@ -118,7 +119,7 @@ function HistoryDetails(props) {
{
age || ageHours || ageMinutes ?
<DescriptionListItem
title="Age (when grabbed)"
title={translate('AgeWhenGrabbed')}
data={formatAge(age, ageHours, ageMinutes)}
/> :
null
@@ -127,7 +128,7 @@ function HistoryDetails(props) {
{
publishedDate ?
<DescriptionListItem
title="Published Date"
title={translate('PublishedDate')}
data={formatDateTime(publishedDate, shortDateFormat, timeFormat, { includeSeconds: true })}
/> :
null
@@ -145,14 +146,23 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
downloadId ?
<DescriptionListItem
title={translate('GrabId')}
data={downloadId}
/> :
null
}
{
message ?
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/> :
null
@@ -163,7 +173,7 @@ function HistoryDetails(props) {
if (eventType === 'downloadFolderImported') {
const {
preferredWordScore,
customFormatScore,
droppedPath,
importedPath
} = data;
@@ -172,7 +182,7 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
@@ -180,7 +190,7 @@ function HistoryDetails(props) {
droppedPath ?
<DescriptionListItem
descriptionClassName={styles.description}
title="Source"
title={translate('Source')}
data={droppedPath}
/> :
null
@@ -190,17 +200,17 @@ function HistoryDetails(props) {
importedPath ?
<DescriptionListItem
descriptionClassName={styles.description}
title="Imported To"
title={translate('ImportedTo')}
data={importedPath}
/> :
null
}
{
preferredWordScore && preferredWordScore !== '0' ?
customFormatScore && customFormatScore !== '0' ?
<DescriptionListItem
title="Preferred Word Score"
data={formatPreferredWordScore(preferredWordScore)}
title={translate('CustomFormatScore')}
data={formatCustomFormatScore(customFormatScore)}
/> :
null
}
@@ -211,20 +221,20 @@ function HistoryDetails(props) {
if (eventType === 'episodeFileDeleted') {
const {
reason,
preferredWordScore
customFormatScore
} = data;
let reasonMessage = '';
switch (reason) {
case 'Manual':
reasonMessage = 'File was deleted by via UI';
reasonMessage = translate('DeletedReasonManual');
break;
case 'MissingFromDisk':
reasonMessage = 'Sonarr was unable to find the file on disk so the file was unlinked from the episode in the database';
reasonMessage = translate('DeletedReasonEpisodeMissingFromDisk');
break;
case 'Upgrade':
reasonMessage = 'File was deleted to import an upgrade';
reasonMessage = translate('DeletedReasonUpgrade');
break;
default:
reasonMessage = '';
@@ -233,20 +243,20 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
<DescriptionListItem
title="Reason"
title={translate('Reason')}
data={reasonMessage}
/>
{
preferredWordScore && preferredWordScore !== '0' ?
customFormatScore && customFormatScore !== '0' ?
<DescriptionListItem
title="Preferred Word Score"
data={formatPreferredWordScore(preferredWordScore)}
title={translate('CustomFormatScore')}
data={formatCustomFormatScore(customFormatScore)}
/> :
null
}
@@ -265,22 +275,22 @@ function HistoryDetails(props) {
return (
<DescriptionList>
<DescriptionListItem
title="Source Path"
title={translate('SourcePath')}
data={sourcePath}
/>
<DescriptionListItem
title="Source Relative Path"
title={translate('SourceRelativePath')}
data={sourceRelativePath}
/>
<DescriptionListItem
title="Destination Path"
title={translate('DestinationPath')}
data={path}
/>
<DescriptionListItem
title="Destination Relative Path"
title={translate('DestinationRelativePath')}
data={relativePath}
/>
</DescriptionList>
@@ -296,14 +306,23 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
{
downloadId ?
<DescriptionListItem
title={translate('GrabId')}
data={downloadId}
/> :
null
}
{
message ?
<DescriptionListItem
title="Message"
title={translate('Message')}
data={message}
/> :
null
@@ -316,7 +335,7 @@ function HistoryDetails(props) {
<DescriptionList>
<DescriptionListItem
descriptionClassName={styles.description}
title="Name"
title={translate('Name')}
data={sourceTitle}
/>
</DescriptionList>
@@ -327,6 +346,7 @@ HistoryDetails.propTypes = {
eventType: PropTypes.string.isRequired,
sourceTitle: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,
downloadId: PropTypes.string,
shortDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired
};

View File

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

View File

@@ -1,32 +1,33 @@
import PropTypes from 'prop-types';
import React from 'react';
import { kinds } from 'Helpers/Props';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import Modal from 'Components/Modal/Modal';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
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 { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import HistoryDetails from './HistoryDetails';
import styles from './HistoryDetailsModal.css';
function getHeaderTitle(eventType) {
switch (eventType) {
case 'grabbed':
return 'Grabbed';
return translate('Grabbed');
case 'downloadFailed':
return 'Download Failed';
return translate('DownloadFailed');
case 'downloadFolderImported':
return 'Episode Imported';
return translate('EpisodeImported');
case 'episodeFileDeleted':
return 'Episode File Deleted';
return translate('EpisodeFileDeleted');
case 'episodeFileRenamed':
return 'Episode File Renamed';
return translate('EpisodeFileRenamed');
case 'downloadIgnored':
return 'Download Ignored';
return translate('DownloadIgnored');
default:
return 'Unknown';
return translate('Unknown');
}
}
@@ -36,6 +37,7 @@ function HistoryDetailsModal(props) {
eventType,
sourceTitle,
data,
downloadId,
isMarkingAsFailed,
shortDateFormat,
timeFormat,
@@ -58,6 +60,7 @@ function HistoryDetailsModal(props) {
eventType={eventType}
sourceTitle={sourceTitle}
data={data}
downloadId={downloadId}
shortDateFormat={shortDateFormat}
timeFormat={timeFormat}
/>
@@ -72,14 +75,14 @@ function HistoryDetailsModal(props) {
isSpinning={isMarkingAsFailed}
onPress={onMarkAsFailedPress}
>
Mark as Failed
{translate('MarkAsFailed')}
</SpinnerButton>
}
<Button
onPress={onModalClose}
>
Close
{translate('Close')}
</Button>
</ModalFooter>
</ModalContent>
@@ -92,6 +95,7 @@ HistoryDetailsModal.propTypes = {
eventType: PropTypes.string.isRequired,
sourceTitle: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,
downloadId: PropTypes.string,
isMarkingAsFailed: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired,

View File

@@ -1,18 +1,21 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { align, icons } from 'Helpers/Props';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import FilterMenu from 'Components/Menu/FilterMenu';
import { align, icons, kinds } from 'Helpers/Props';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
import HistoryFilterModal from './HistoryFilterModal';
import HistoryRowConnector from './HistoryRowConnector';
class History extends Component {
@@ -50,6 +53,7 @@ class History extends Component {
columns,
selectedFilterKey,
filters,
customFilters,
totalRecords,
isEpisodesFetching,
isEpisodesPopulated,
@@ -64,11 +68,11 @@ class History extends Component {
const hasError = error || episodesError;
return (
<PageContent title="History">
<PageContent title={translate('History')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label="Refresh"
label={translate('Refresh')}
iconName={icons.REFRESH}
isSpinning={isFetching}
onPress={onFirstPagePress}
@@ -81,7 +85,7 @@ class History extends Component {
columns={columns}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
@@ -90,7 +94,8 @@ class History extends Component {
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={[]}
customFilters={customFilters}
filterModalConnectorComponent={HistoryFilterModal}
onFilterSelect={onFilterSelect}
/>
</PageToolbarSection>
@@ -104,7 +109,9 @@ class History extends Component {
{
!isFetchingAny && hasError &&
<div>Unable to load history</div>
<Alert kind={kinds.DANGER}>
{translate('HistoryLoadError')}
</Alert>
}
{
@@ -112,9 +119,9 @@ class History extends Component {
// wait for the episodes to populate because they are never coming.
isPopulated && !hasError && !items.length &&
<div>
No history found
</div>
<Alert kind={kinds.INFO}>
{translate('NoHistoryFound')}
</Alert>
}
{
@@ -159,8 +166,9 @@ History.propTypes = {
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
selectedFilterKey: PropTypes.string.isRequired,
selectedFilterKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
totalRecords: PropTypes.number,
isEpisodesFetching: PropTypes.bool.isRequired,
isEpisodesPopulated: PropTypes.bool.isRequired,

View File

@@ -2,24 +2,27 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import withCurrentPage from 'Components/withCurrentPage';
import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions';
import { clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import * as historyActions from 'Store/Actions/historyActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import withCurrentPage from 'Components/withCurrentPage';
import * as historyActions from 'Store/Actions/historyActions';
import { fetchEpisodes, clearEpisodes } from 'Store/Actions/episodeActions';
import { clearEpisodeFiles } from 'Store/Actions/episodeFileActions';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import History from './History';
function createMapStateToProps() {
return createSelector(
(state) => state.history,
(state) => state.episodes,
(history, episodes) => {
createCustomFiltersSelector('history'),
(history, episodes, customFilters) => {
return {
isEpisodesFetching: episodes.isFetching,
isEpisodesPopulated: episodes.isPopulated,
episodesError: episodes.error,
customFilters,
...history
};
}
@@ -78,38 +81,38 @@ class HistoryConnector extends Component {
repopulate = () => {
this.props.fetchHistory();
}
};
//
// Listeners
onFirstPagePress = () => {
this.props.gotoHistoryFirstPage();
}
};
onPreviousPagePress = () => {
this.props.gotoHistoryPreviousPage();
}
};
onNextPagePress = () => {
this.props.gotoHistoryNextPage();
}
};
onLastPagePress = () => {
this.props.gotoHistoryLastPage();
}
};
onPageSelect = (page) => {
this.props.gotoHistoryPage({ page });
}
};
onSortPress = (sortKey) => {
this.props.setHistorySort({ sortKey });
}
};
onFilterSelect = (selectedFilterKey) => {
this.props.setHistoryFilter({ selectedFilterKey });
}
};
onTableOptionChange = (payload) => {
this.props.setHistoryTableOption(payload);
@@ -117,7 +120,7 @@ class HistoryConnector extends Component {
if (payload.pageSize) {
this.props.gotoHistoryFirstPage();
}
}
};
//
// Render

View File

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

View File

@@ -1,8 +1,9 @@
import PropTypes from 'prop-types';
import React from 'react';
import { icons, kinds } from 'Helpers/Props';
import Icon from 'Components/Icon';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './HistoryEventTypeCell.css';
function getIconName(eventType) {
@@ -38,21 +39,21 @@ function getIconKind(eventType) {
function getTooltip(eventType, data) {
switch (eventType) {
case 'grabbed':
return `Episode grabbed from ${data.indexer} and sent to ${data.downloadClient}`;
return translate('EpisodeGrabbedTooltip', { indexer: data.indexer, downloadClient: data.downloadClient });
case 'seriesFolderImported':
return 'Episode imported from series folder';
return translate('SeriesFolderImportedTooltip');
case 'downloadFolderImported':
return 'Episode downloaded successfully and picked up from download client';
return translate('EpisodeImportedTooltip');
case 'downloadFailed':
return 'Episode download failed';
return translate('DownloadFailedEpisodeTooltip');
case 'episodeFileDeleted':
return 'Episode file deleted';
return translate('EpisodeFileDeletedTooltip');
case 'episodeFileRenamed':
return 'Episode file renamed';
return translate('EpisodeFileRenamedTooltip');
case 'downloadIgnored':
return 'Episode Download Ignored';
return translate('DownloadIgnoredEpisodeTooltip');
default:
return 'Unknown event';
return translate('UnknownEventTooltip');
}
}

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 { setHistoryFilter } from 'Store/Actions/historyActions';
function createHistorySelector() {
return createSelector(
(state: AppState) => state.history.items,
(queueItems) => {
return queueItems;
}
);
}
function createFilterBuilderPropsSelector() {
return createSelector(
(state: AppState) => state.history.filterBuilderProps,
(filterBuilderProps) => {
return filterBuilderProps;
}
);
}
interface HistoryFilterModalProps {
isOpen: boolean;
}
export default function HistoryFilterModal(props: HistoryFilterModalProps) {
const sectionItems = useSelector(createHistorySelector());
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
const customFilterType = 'history';
const dispatch = useDispatch();
const dispatchSetFilter = useCallback(
(payload: unknown) => {
dispatch(setHistoryFilter(payload));
},
[dispatch]
);
return (
<FilterModal
// TODO: Don't spread all the props
{...props}
sectionItems={sectionItems}
filterBuilderProps={filterBuilderProps}
customFilterType={customFilterType}
dispatchSetFilter={dispatchSetFilter}
/>
);
}

View File

@@ -10,7 +10,7 @@
width: 80px;
}
.preferredWordScore {
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;

View File

@@ -0,0 +1,11 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'customFormatScore': string;
'details': string;
'downloadClient': string;
'indexer': string;
'releaseGroup': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,19 +1,21 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
import { icons } from 'Helpers/Props';
import IconButton from 'Components/Link/IconButton';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRow from 'Components/Table/TableRow';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import Tooltip from 'Components/Tooltip/Tooltip';
import episodeEntities from 'Episode/episodeEntities';
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import EpisodeLanguage from 'Episode/EpisodeLanguage';
import EpisodeFormats from 'Episode/EpisodeFormats';
import EpisodeLanguages from 'Episode/EpisodeLanguages';
import EpisodeQuality from 'Episode/EpisodeQuality';
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
import { icons, tooltipPositions } from 'Helpers/Props';
import SeriesTitleLink from 'Series/SeriesTitleLink';
import HistoryEventTypeCell from './HistoryEventTypeCell';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import HistoryDetailsModal from './Details/HistoryDetailsModal';
import HistoryEventTypeCell from './HistoryEventTypeCell';
import styles from './HistoryRow.css';
class HistoryRow extends Component {
@@ -44,11 +46,11 @@ class HistoryRow extends Component {
onDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
}
};
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
}
};
//
// Render
@@ -58,14 +60,16 @@ class HistoryRow extends Component {
episodeId,
series,
episode,
language,
languageCutoffNotMet,
languages,
quality,
customFormats,
customFormatScore,
qualityCutoffNotMet,
eventType,
sourceTitle,
date,
data,
downloadId,
isMarkingAsFailed,
columns,
shortDateFormat,
@@ -128,7 +132,7 @@ class HistoryRow extends Component {
);
}
if (name === 'episodeTitle') {
if (name === 'episodes.title') {
return (
<TableRowCell key={name}>
<EpisodeTitleLink
@@ -142,13 +146,10 @@ class HistoryRow extends Component {
);
}
if (name === 'language') {
if (name === 'languages') {
return (
<TableRowCell key={name}>
<EpisodeLanguage
language={language}
isCutoffMet={languageCutoffNotMet}
/>
<EpisodeLanguages languages={languages} />
</TableRowCell>
);
}
@@ -164,6 +165,16 @@ class HistoryRow extends Component {
);
}
if (name === 'customFormats') {
return (
<TableRowCell key={name}>
<EpisodeFormats
formats={customFormats}
/>
</TableRowCell>
);
}
if (name === 'date') {
return (
<RelativeDateCellConnector
@@ -195,13 +206,20 @@ class HistoryRow extends Component {
);
}
if (name === 'preferredWordScore') {
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.preferredWordScore}
className={styles.customFormatScore}
>
{formatPreferredWordScore(data.preferredWordScore)}
<Tooltip
anchor={formatCustomFormatScore(
customFormatScore,
customFormats.length
)}
tooltip={<EpisodeFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
@@ -233,10 +251,12 @@ class HistoryRow extends Component {
key={name}
className={styles.details}
>
<IconButton
name={icons.INFO}
onPress={this.onDetailsPress}
/>
<div className={styles.actionContents}>
<IconButton
name={icons.INFO}
onPress={this.onDetailsPress}
/>
</div>
</TableRowCell>
);
}
@@ -250,6 +270,7 @@ class HistoryRow extends Component {
eventType={eventType}
sourceTitle={sourceTitle}
data={data}
downloadId={downloadId}
isMarkingAsFailed={isMarkingAsFailed}
shortDateFormat={shortDateFormat}
timeFormat={timeFormat}
@@ -266,14 +287,16 @@ HistoryRow.propTypes = {
episodeId: PropTypes.number,
series: PropTypes.object.isRequired,
episode: PropTypes.object,
language: PropTypes.object.isRequired,
languageCutoffNotMet: PropTypes.bool.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired,
eventType: PropTypes.string.isRequired,
sourceTitle: PropTypes.string.isRequired,
date: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,
downloadId: PropTypes.string,
isMarkingAsFailed: PropTypes.bool,
markAsFailedError: PropTypes.object,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
@@ -282,4 +305,8 @@ HistoryRow.propTypes = {
onMarkAsFailedPress: PropTypes.func.isRequired
};
HistoryRow.defaultProps = {
customFormats: []
};
export default HistoryRow;

View File

@@ -3,8 +3,8 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import HistoryRow from './HistoryRow';
@@ -49,7 +49,7 @@ class HistoryRowConnector extends Component {
onMarkAsFailedPress = () => {
this.props.markAsFailed({ id: this.props.id });
}
};
//
// Render

View File

@@ -1,13 +1,13 @@
.torrent {
composes: label from '~Components/Label.css';
border-color: $torrentColor;
background-color: $torrentColor;
border-color: var(--torrentColor);
background-color: var(--torrentColor);
}
.usenet {
composes: label from '~Components/Label.css';
border-color: $usenetColor;
background-color: $usenetColor;
border-color: var(--usenetColor);
background-color: var(--usenetColor);
}

View File

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

View File

@@ -1,27 +1,31 @@
import _ from 'lodash';
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 PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
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 { align, icons } from 'Helpers/Props';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TablePager from 'Components/Table/TablePager';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import RemoveQueueItemsModal from './RemoveQueueItemsModal';
import QueueFilterModal from './QueueFilterModal';
import QueueOptionsConnector from './QueueOptionsConnector';
import QueueRowConnector from './QueueRowConnector';
import RemoveQueueItemsModal from './RemoveQueueItemsModal';
class Queue extends Component {
@@ -72,13 +76,23 @@ class Queue extends Component {
return;
}
const nextState = {};
if (prevProps.items !== items) {
nextState.items = items;
}
const selectedIds = this.getSelectedIds();
const isPendingSelected = _.some(this.props.items, (item) => {
return selectedIds.indexOf(item.id) > -1 && item.status === 'delay';
});
if (isPendingSelected !== this.state.isPendingSelected) {
this.setState({ isPendingSelected });
nextState.isPendingSelected = isPendingSelected;
}
if (!_.isEmpty(nextState)) {
this.setState(nextState);
}
}
@@ -87,45 +101,45 @@ class Queue extends Component {
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
}
};
//
// Listeners
onQueueRowModalOpenOrClose = (isOpen) => {
this._shouldBlockRefresh = isOpen;
}
};
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
}
};
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
}
};
onGrabSelectedPress = () => {
this.props.onGrabSelectedPress(this.getSelectedIds());
}
};
onRemoveSelectedPress = () => {
this.setState({ isConfirmRemoveModalOpen: true }, () => {
this._shouldBlockRefresh = true;
});
}
};
onRemoveSelectedConfirmed = (payload) => {
this._shouldBlockRefresh = false;
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
this.setState({ isConfirmRemoveModalOpen: false });
}
};
onConfirmRemoveModalClose = () => {
this._shouldBlockRefresh = false;
this.setState({ isConfirmRemoveModalOpen: false });
}
};
//
// Render
@@ -139,11 +153,16 @@ class Queue extends Component {
isEpisodesPopulated,
episodesError,
columns,
selectedFilterKey,
filters,
customFilters,
count,
totalRecords,
isGrabbing,
isRemoving,
isRefreshMonitoredDownloadsExecuting,
onRefreshPress,
onFilterSelect,
...otherProps
} = this.props;
@@ -164,7 +183,7 @@ class Queue extends Component {
const disableSelectedActions = selectedCount === 0;
return (
<PageContent title="Queue">
<PageContent title={translate('Queue')}>
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
@@ -177,7 +196,7 @@ class Queue extends Component {
<PageToolbarSeparator />
<PageToolbarButton
label="Grab Selected"
label={translate('GrabSelected')}
iconName={icons.DOWNLOAD}
isDisabled={disableSelectedActions || !isPendingSelected}
isSpinning={isGrabbing}
@@ -185,7 +204,7 @@ class Queue extends Component {
/>
<PageToolbarButton
label="Remove Selected"
label={translate('RemoveSelected')}
iconName={icons.REMOVE}
isDisabled={disableSelectedActions}
isSpinning={isRemoving}
@@ -202,35 +221,51 @@ class Queue extends Component {
optionsComponent={QueueOptionsConnector}
>
<PageToolbarButton
label="Options"
label={translate('Options')}
iconName={icons.TABLE}
/>
</TableOptionsModalWrapper>
<FilterMenu
alignMenu={align.RIGHT}
selectedFilterKey={selectedFilterKey}
filters={filters}
customFilters={customFilters}
filterModalConnectorComponent={QueueFilterModal}
onFilterSelect={onFilterSelect}
/>
</PageToolbarSection>
</PageToolbar>
<PageContentBody>
{
isRefreshing && !isAllPopulated &&
<LoadingIndicator />
isRefreshing && !isAllPopulated ?
<LoadingIndicator /> :
null
}
{
!isRefreshing && hasError &&
<div>
Failed to load Queue
</div>
!isRefreshing && hasError ?
<Alert kind={kinds.DANGER}>
{translate('QueueLoadError')}
</Alert> :
null
}
{
isAllPopulated && !hasError && !items.length &&
<div>
Queue is empty
</div>
isAllPopulated && !hasError && !items.length ?
<Alert kind={kinds.INFO}>
{
selectedFilterKey !== 'all' && count > 0 ?
translate('QueueFilterHasNoItems') :
translate('QueueIsEmpty')
}
</Alert> :
null
}
{
isAllPopulated && !hasError && !!items.length &&
isAllPopulated && !hasError && !!items.length ?
<div>
<Table
columns={columns}
@@ -265,7 +300,8 @@ class Queue extends Component {
isFetching={isRefreshing}
{...otherProps}
/>
</div>
</div> :
null
}
</PageContentBody>
@@ -307,13 +343,22 @@ Queue.propTypes = {
isEpisodesPopulated: PropTypes.bool.isRequired,
episodesError: PropTypes.object,
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,
count: PropTypes.number.isRequired,
totalRecords: PropTypes.number,
isGrabbing: PropTypes.bool.isRequired,
isRemoving: PropTypes.bool.isRequired,
isRefreshMonitoredDownloadsExecuting: PropTypes.bool.isRequired,
onRefreshPress: PropTypes.func.isRequired,
onGrabSelectedPress: PropTypes.func.isRequired,
onRemoveSelectedPress: PropTypes.func.isRequired
onRemoveSelectedPress: PropTypes.func.isRequired,
onFilterSelect: PropTypes.func.isRequired
};
Queue.defaultProps = {
count: 0
};
export default Queue;

View File

@@ -2,15 +2,16 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import * as commandNames from 'Commands/commandNames';
import withCurrentPage from 'Components/withCurrentPage';
import { executeCommand } from 'Store/Actions/commandActions';
import { clearEpisodes, fetchEpisodes } from 'Store/Actions/episodeActions';
import * as queueActions from 'Store/Actions/queueActions';
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import withCurrentPage from 'Components/withCurrentPage';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import { executeCommand } from 'Store/Actions/commandActions';
import * as queueActions from 'Store/Actions/queueActions';
import { fetchEpisodes, clearEpisodes } from 'Store/Actions/episodeActions';
import * as commandNames from 'Commands/commandNames';
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import Queue from './Queue';
function createMapStateToProps() {
@@ -18,12 +19,16 @@ function createMapStateToProps() {
(state) => state.episodes,
(state) => state.queue.options,
(state) => state.queue.paged,
(state) => state.queue.status.item,
createCustomFiltersSelector('queue'),
createCommandExecutingSelector(commandNames.REFRESH_MONITORED_DOWNLOADS),
(episodes, options, queue, isRefreshMonitoredDownloadsExecuting) => {
(episodes, options, queue, status, customFilters, isRefreshMonitoredDownloadsExecuting) => {
return {
count: options.includeUnknownSeriesItems ? status.totalCount : status.count,
isEpisodesFetching: episodes.isFetching,
isEpisodesPopulated: episodes.isPopulated,
episodesError: episodes.error,
customFilters,
isRefreshMonitoredDownloadsExecuting,
...options,
...queue
@@ -93,34 +98,38 @@ class QueueConnector extends Component {
repopulate = () => {
this.props.fetchQueue();
}
};
//
// Listeners
onFirstPagePress = () => {
this.props.gotoQueueFirstPage();
}
};
onPreviousPagePress = () => {
this.props.gotoQueuePreviousPage();
}
};
onNextPagePress = () => {
this.props.gotoQueueNextPage();
}
};
onLastPagePress = () => {
this.props.gotoQueueLastPage();
}
};
onPageSelect = (page) => {
this.props.gotoQueuePage({ page });
}
};
onSortPress = (sortKey) => {
this.props.setQueueSort({ sortKey });
}
};
onFilterSelect = (selectedFilterKey) => {
this.props.setQueueFilter({ selectedFilterKey });
};
onTableOptionChange = (payload) => {
this.props.setQueueTableOption(payload);
@@ -128,21 +137,21 @@ class QueueConnector extends Component {
if (payload.pageSize) {
this.props.gotoQueueFirstPage();
}
}
};
onRefreshPress = () => {
this.props.executeCommand({
name: commandNames.REFRESH_MONITORED_DOWNLOADS
});
}
};
onGrabSelectedPress = (ids) => {
this.props.grabQueueItems({ ids });
}
};
onRemoveSelectedPress = (payload) => {
this.props.removeQueueItems(payload);
}
};
//
// Render
@@ -156,6 +165,7 @@ class QueueConnector extends Component {
onLastPagePress={this.onLastPagePress}
onPageSelect={this.onPageSelect}
onSortPress={this.onSortPress}
onFilterSelect={this.onFilterSelect}
onTableOptionChange={this.onTableOptionChange}
onRefreshPress={this.onRefreshPress}
onGrabSelectedPress={this.onGrabSelectedPress}
@@ -178,6 +188,7 @@ QueueConnector.propTypes = {
gotoQueueLastPage: PropTypes.func.isRequired,
gotoQueuePage: PropTypes.func.isRequired,
setQueueSort: PropTypes.func.isRequired,
setQueueFilter: PropTypes.func.isRequired,
setQueueTableOption: PropTypes.func.isRequired,
clearQueue: PropTypes.func.isRequired,
grabQueueItems: PropTypes.func.isRequired,

View File

@@ -0,0 +1,5 @@
.progressBarContainer {
display: flex;
justify-content: center;
width: 100%;
}

View File

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

View File

@@ -1,115 +1,71 @@
import moment from 'moment';
import PropTypes from 'prop-types';
import React from 'react';
import { icons, kinds } from 'Helpers/Props';
import Icon from 'Components/Icon';
import Popover from 'Components/Tooltip/Popover';
import { icons, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import QueueStatus from './QueueStatus';
import styles from './QueueDetails.css';
function QueueDetails(props) {
const {
title,
size,
sizeleft,
estimatedCompletionTime,
status,
trackedDownloadState,
trackedDownloadStatus,
statusMessages,
errorMessage,
progressBar
} = props;
const progress = (100 - sizeleft / size * 100);
const isDownloading = status === 'downloading';
const isPaused = status === 'paused';
const hasWarning = trackedDownloadStatus === 'warning';
const hasError = trackedDownloadStatus === 'error';
if (status === 'pending') {
return (
<Icon
name={icons.PENDING}
title={`Release will be processed ${moment(estimatedCompletionTime).fromNow()}`}
/>
);
}
if (
(isDownloading || isPaused) &&
!hasWarning &&
!hasError
) {
const state = isPaused ? translate('Paused') : translate('Downloading');
if (status === 'completed') {
if (errorMessage) {
if (progress < 5) {
return (
<Icon
name={icons.DOWNLOAD}
kind={kinds.DANGER}
title={`Import failed: ${errorMessage}`}
name={icons.DOWNLOADING}
title={`${state} - ${progress.toFixed(1)}% ${title}`}
/>
);
}
if (trackedDownloadStatus === 'warning') {
return (
<Icon
name={icons.DOWNLOAD}
kind={kinds.WARNING}
title={'Downloaded - Unable to Import: check logs for details'}
/>
);
}
if (trackedDownloadState === 'importPending') {
return (
<Icon
name={icons.DOWNLOAD}
kind={kinds.PURPLE}
title={'Downloaded - Waiting to Import'}
/>
);
}
if (trackedDownloadState === 'importing') {
return (
<Icon
name={icons.DOWNLOAD}
kind={kinds.PURPLE}
title={'Downloaded - Importing'}
/>
);
}
}
if (errorMessage) {
return (
<Icon
name={icons.DOWNLOADING}
kind={kinds.DANGER}
title={`Download failed: ${errorMessage}`}
<Popover
className={styles.progressBarContainer}
anchor={progressBar}
title={`${state} - ${progress.toFixed(1)}%`}
body={
<div>{title}</div>
}
position={tooltipPositions.LEFT}
/>
);
}
if (status === 'failed') {
return (
<Icon
name={icons.DOWNLOADING}
kind={kinds.DANGER}
title="Download failed: check download client for more details"
/>
);
}
if (status === 'warning') {
return (
<Icon
name={icons.DOWNLOADING}
kind={kinds.WARNING}
title="Download warning: check download client for more details"
/>
);
}
if (progress < 5) {
return (
<Icon
name={icons.DOWNLOADING}
title={`Episode is downloading - ${progress.toFixed(1)}% ${title}`}
/>
);
}
return progressBar;
return (
<QueueStatus
sourceTitle={title}
status={status}
trackedDownloadStatus={trackedDownloadStatus}
trackedDownloadState={trackedDownloadState}
statusMessages={statusMessages}
errorMessage={errorMessage}
position={tooltipPositions.LEFT}
/>
);
}
QueueDetails.propTypes = {
@@ -120,8 +76,14 @@ QueueDetails.propTypes = {
status: PropTypes.string.isRequired,
trackedDownloadState: PropTypes.string.isRequired,
trackedDownloadStatus: PropTypes.string.isRequired,
statusMessages: PropTypes.arrayOf(PropTypes.object),
errorMessage: PropTypes.string,
progressBar: PropTypes.node.isRequired
};
QueueDetails.defaultProps = {
trackedDownloadStatus: 'ok',
trackedDownloadState: 'downloading'
};
export default QueueDetails;

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 { setQueueFilter } from 'Store/Actions/queueActions';
function createQueueSelector() {
return createSelector(
(state: AppState) => state.queue.paged.items,
(queueItems) => {
return queueItems;
}
);
}
function createFilterBuilderPropsSelector() {
return createSelector(
(state: AppState) => state.queue.paged.filterBuilderProps,
(filterBuilderProps) => {
return filterBuilderProps;
}
);
}
interface QueueFilterModalProps {
isOpen: boolean;
}
export default function QueueFilterModal(props: QueueFilterModalProps) {
const sectionItems = useSelector(createQueueSelector());
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
const customFilterType = 'queue';
const dispatch = useDispatch();
const dispatchSetFilter = useCallback(
(payload: unknown) => {
dispatch(setQueueFilter(payload));
},
[dispatch]
);
return (
<FilterModal
// TODO: Don't spread all the props
{...props}
sectionItems={sectionItems}
filterBuilderProps={filterBuilderProps}
customFilterType={customFilterType}
dispatchSetFilter={dispatchSetFilter}
/>
);
}

View File

@@ -1,9 +1,10 @@
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import { inputTypes } from 'Helpers/Props';
import FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class QueueOptions extends Component {
@@ -41,7 +42,7 @@ class QueueOptions extends Component {
[name]: value
});
});
}
};
//
// Render
@@ -54,13 +55,13 @@ class QueueOptions extends Component {
return (
<Fragment>
<FormGroup>
<FormLabel>Show Unknown Series Items</FormLabel>
<FormLabel>{translate('ShowUnknownSeriesItems')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="includeUnknownSeriesItems"
value={includeUnknownSeriesItems}
helpText="Show items without a series in the queue, this could include removed series, movies or anything else in Sonarr's category"
helpText={translate('ShowUnknownSeriesItemsHelpText')}
onChange={this.onOptionChange}
/>
</FormGroup>

View File

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

View File

@@ -0,0 +1,11 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'actions': string;
'customFormatScore': string;
'progress': string;
'protocol': string;
'quality': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,25 +1,29 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { icons, kinds } from 'Helpers/Props';
import ProtocolLabel from 'Activity/Queue/ProtocolLabel';
import IconButton from 'Components/Link/IconButton';
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
import ProgressBar from 'Components/ProgressBar';
import TableRow from 'Components/Table/TableRow';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import ProtocolLabel from 'Activity/Queue/ProtocolLabel';
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import EpisodeLanguage from 'Episode/EpisodeLanguage';
import TableRow from 'Components/Table/TableRow';
import Tooltip from 'Components/Tooltip/Tooltip';
import EpisodeFormats from 'Episode/EpisodeFormats';
import EpisodeLanguages from 'Episode/EpisodeLanguages';
import EpisodeQuality from 'Episode/EpisodeQuality';
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import SeriesTitleLink from 'Series/SeriesTitleLink';
import QueueStatusCell from './QueueStatusCell';
import TimeleftCell from './TimeleftCell';
import RemoveQueueItemModal from './RemoveQueueItemModal';
import styles from './QueueRow.css';
import formatBytes from 'Utilities/Number/formatBytes';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import translate from 'Utilities/String/translate';
import QueueStatusCell from './QueueStatusCell';
import RemoveQueueItemModal from './RemoveQueueItemModal';
import TimeleftCell from './TimeleftCell';
import styles from './QueueRow.css';
class QueueRow extends Component {
@@ -40,37 +44,37 @@ class QueueRow extends Component {
onRemoveQueueItemPress = () => {
this.setState({ isRemoveQueueItemModalOpen: true });
}
};
onRemoveQueueItemModalConfirmed = (blocklist) => {
onRemoveQueueItemModalConfirmed = (blocklist, skipRedownload) => {
const {
onRemoveQueueItemPress,
onQueueRowModalOpenOrClose
} = this.props;
onQueueRowModalOpenOrClose(false);
onRemoveQueueItemPress(blocklist);
onRemoveQueueItemPress(blocklist, skipRedownload);
this.setState({ isRemoveQueueItemModalOpen: false });
}
};
onRemoveQueueItemModalClose = () => {
this.props.onQueueRowModalOpenOrClose(false);
this.setState({ isRemoveQueueItemModalOpen: false });
}
};
onInteractiveImportPress = () => {
this.props.onQueueRowModalOpenOrClose(true);
this.setState({ isInteractiveImportModalOpen: true });
}
};
onInteractiveImportModalClose = () => {
this.props.onQueueRowModalOpenOrClose(false);
this.setState({ isInteractiveImportModalOpen: false });
}
};
//
// Render
@@ -87,8 +91,10 @@ class QueueRow extends Component {
errorMessage,
series,
episode,
language,
languages,
quality,
customFormats,
customFormatScore,
protocol,
indexer,
outputPath,
@@ -188,7 +194,7 @@ class QueueRow extends Component {
);
}
if (name === 'episode.title') {
if (name === 'episodes.title') {
return (
<TableRowCell key={name}>
{
@@ -206,7 +212,7 @@ class QueueRow extends Component {
);
}
if (name === 'episode.airDateUtc') {
if (name === 'episodes.airDateUtc') {
if (episode) {
return (
<RelativeDateCellConnector
@@ -223,11 +229,11 @@ class QueueRow extends Component {
);
}
if (name === 'language') {
if (name === 'languages') {
return (
<TableRowCell key={name}>
<EpisodeLanguage
language={language}
<EpisodeLanguages
languages={languages}
/>
</TableRowCell>
);
@@ -247,6 +253,34 @@ class QueueRow extends Component {
);
}
if (name === 'customFormats') {
return (
<TableRowCell key={name}>
<EpisodeFormats
formats={customFormats}
/>
</TableRowCell>
);
}
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
<Tooltip
anchor={formatCustomFormatScore(
customFormatScore,
customFormats.length
)}
tooltip={<EpisodeFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
if (name === 'protocol') {
return (
<TableRowCell key={name}>
@@ -353,7 +387,7 @@ class QueueRow extends Component {
}
<SpinnerIconButton
title="Remove from queue"
title={translate('RemoveFromQueue')}
name={icons.REMOVE}
isSpinning={isRemoving}
onPress={this.onRemoveQueueItemPress}
@@ -398,8 +432,10 @@ QueueRow.propTypes = {
errorMessage: PropTypes.string,
series: PropTypes.object,
episode: PropTypes.object,
language: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
protocol: PropTypes.string.isRequired,
indexer: PropTypes.string,
outputPath: PropTypes.string,
@@ -423,6 +459,7 @@ QueueRow.propTypes = {
};
QueueRow.defaultProps = {
customFormats: [],
isGrabbing: false,
isRemoving: false
};

View File

@@ -3,8 +3,8 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { grabQueueItem, removeQueueItem } from 'Store/Actions/queueActions';
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
import createEpisodeSelector from 'Store/Selectors/createEpisodeSelector';
import createSeriesSelector from 'Store/Selectors/createSeriesSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import QueueRow from './QueueRow';
@@ -40,11 +40,11 @@ class QueueRowConnector extends Component {
onGrabPress = () => {
this.props.grabQueueItem({ id: this.props.id });
}
};
onRemoveQueueItemPress = (payload) => {
this.props.removeQueueItem({ id: this.props.id, ...payload });
}
};
//
// Render

View File

@@ -0,0 +1,3 @@
.noMessages {
margin-bottom: 10px;
}

View File

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

View File

@@ -0,0 +1,162 @@
import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './QueueStatus.css';
function getDetailedPopoverBody(statusMessages) {
return (
<div>
{
statusMessages.map(({ title, messages }) => {
return (
<div
key={title}
className={messages.length ? undefined: styles.noMessages}
>
{title}
<ul>
{
messages.map((message) => {
return (
<li key={message}>
{message}
</li>
);
})
}
</ul>
</div>
);
})
}
</div>
);
}
function QueueStatus(props) {
const {
sourceTitle,
status,
trackedDownloadStatus,
trackedDownloadState,
statusMessages,
errorMessage,
position,
canFlip
} = props;
const hasWarning = trackedDownloadStatus === 'warning';
const hasError = trackedDownloadStatus === 'error';
// status === 'downloading'
let iconName = icons.DOWNLOADING;
let iconKind = kinds.DEFAULT;
let title = translate('Downloading');
if (status === 'paused') {
iconName = icons.PAUSED;
title = translate('Paused');
}
if (status === 'queued') {
iconName = icons.QUEUED;
title = translate('Queued');
}
if (status === 'completed') {
iconName = icons.DOWNLOADED;
title = translate('Downloaded');
if (trackedDownloadState === 'importPending') {
title += ` - ${translate('WaitingToImport')}`;
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'importing') {
title += ` - ${translate('Importing')}`;
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'failedPending') {
title += ` - ${translate('WaitingToProcess')}`;
iconKind = kinds.DANGER;
}
}
if (hasWarning) {
iconKind = kinds.WARNING;
}
if (status === 'delay') {
iconName = icons.PENDING;
title = translate('Pending');
}
if (status === 'downloadClientUnavailable') {
iconName = icons.PENDING;
iconKind = kinds.WARNING;
title = translate('PendingDownloadClientUnavailable');
}
if (status === 'failed') {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = translate('DownloadFailed');
}
if (status === 'warning') {
iconName = icons.DOWNLOADING;
iconKind = kinds.WARNING;
const warningMessage = errorMessage || translate('CheckDownloadClientForDetails');
title = translate('DownloadWarning', { warningMessage });
}
if (hasError) {
if (status === 'completed') {
iconName = icons.DOWNLOAD;
iconKind = kinds.DANGER;
title = translate('ImportFailed', { sourceTitle });
} else {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = translate('DownloadFailed');
}
}
return (
<Popover
anchor={
<Icon
name={iconName}
kind={iconKind}
/>
}
title={title}
body={hasWarning || hasError ? getDetailedPopoverBody(statusMessages) : sourceTitle}
position={position}
canFlip={canFlip}
/>
);
}
QueueStatus.propTypes = {
sourceTitle: PropTypes.string.isRequired,
status: PropTypes.string.isRequired,
trackedDownloadStatus: PropTypes.string.isRequired,
trackedDownloadState: PropTypes.string.isRequired,
statusMessages: PropTypes.arrayOf(PropTypes.object),
errorMessage: PropTypes.string,
position: PropTypes.oneOf(tooltipPositions.all).isRequired,
canFlip: PropTypes.bool.isRequired
};
QueueStatus.defaultProps = {
trackedDownloadStatus: 'ok',
trackedDownloadState: 'downloading',
canFlip: false
};
export default QueueStatus;

View File

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

View File

@@ -1,41 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import Icon from 'Components/Icon';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Popover from 'Components/Tooltip/Popover';
import { tooltipPositions } from 'Helpers/Props';
import QueueStatus from './QueueStatus';
import styles from './QueueStatusCell.css';
function getDetailedPopoverBody(statusMessages) {
return (
<div>
{
statusMessages.map(({ title, messages }) => {
return (
<div
key={title}
className={messages.length ? undefined: styles.noMessages}
>
{title}
<ul>
{
messages.map((message) => {
return (
<li key={message}>
{message}
</li>
);
})
}
</ul>
</div>
);
})
}
</div>
);
}
function QueueStatusCell(props) {
const {
sourceTitle,
@@ -46,96 +15,16 @@ function QueueStatusCell(props) {
errorMessage
} = props;
const hasWarning = trackedDownloadStatus === 'warning';
const hasError = trackedDownloadStatus === 'error';
// status === 'downloading'
let iconName = icons.DOWNLOADING;
let iconKind = kinds.DEFAULT;
let title = 'Downloading';
if (status === 'paused') {
iconName = icons.PAUSED;
title = 'Paused';
}
if (status === 'queued') {
iconName = icons.QUEUED;
title = 'Queued';
}
if (status === 'completed') {
iconName = icons.DOWNLOADED;
title = 'Downloaded';
if (trackedDownloadState === 'importPending') {
title += ' - Waiting to Import';
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'importing') {
title += ' - Importing';
iconKind = kinds.PURPLE;
}
if (trackedDownloadState === 'failedPending') {
title += ' - Waiting to Process';
iconKind = kinds.DANGER;
}
}
if (hasWarning) {
iconKind = kinds.WARNING;
}
if (status === 'delay') {
iconName = icons.PENDING;
title = 'Pending';
}
if (status === 'downloadClientUnavailable') {
iconName = icons.PENDING;
iconKind = kinds.WARNING;
title = 'Pending - Download client is unavailable';
}
if (status === 'failed') {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = 'Download failed';
}
if (status === 'warning') {
iconName = icons.DOWNLOADING;
iconKind = kinds.WARNING;
title = `Download warning: ${errorMessage || 'check download client for more details'}`;
}
if (hasError) {
if (status === 'completed') {
iconName = icons.DOWNLOAD;
iconKind = kinds.DANGER;
title = `Import failed: ${sourceTitle}`;
} else {
iconName = icons.DOWNLOADING;
iconKind = kinds.DANGER;
title = 'Download failed';
}
}
return (
<TableRowCell className={styles.status}>
<Popover
anchor={
<Icon
name={iconName}
kind={iconKind}
/>
}
title={title}
body={hasWarning || hasError ? getDetailedPopoverBody(statusMessages) : sourceTitle}
<QueueStatus
sourceTitle={sourceTitle}
status={status}
trackedDownloadStatus={trackedDownloadStatus}
trackedDownloadState={trackedDownloadState}
statusMessages={statusMessages}
errorMessage={errorMessage}
position={tooltipPositions.RIGHT}
canFlip={false}
/>
</TableRowCell>
);
@@ -151,8 +40,8 @@ QueueStatusCell.propTypes = {
};
QueueStatusCell.defaultProps = {
trackedDownloadStatus: 'Ok',
trackedDownloadState: 'Downloading'
trackedDownloadStatus: 'ok',
trackedDownloadState: 'downloading'
};
export default QueueStatusCell;

View File

@@ -1,15 +1,16 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
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 FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
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 {
@@ -21,7 +22,8 @@ class RemoveQueueItemModal extends Component {
this.state = {
remove: true,
blocklist: false
blocklist: false,
skipRedownload: false
};
}
@@ -31,32 +33,37 @@ class RemoveQueueItemModal extends Component {
resetState = function() {
this.setState({
remove: true,
blocklist: false
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
@@ -69,7 +76,7 @@ class RemoveQueueItemModal extends Component {
isPending
} = this.props;
const { remove, blocklist } = this.state;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
@@ -81,25 +88,25 @@ class RemoveQueueItemModal extends Component {
onModalClose={this.onModalClose}
>
<ModalHeader>
Remove - {sourceTitle}
{translate('RemoveQueueItem', { sourceTitle })}
</ModalHeader>
<ModalBody>
<div>
Are you sure you want to remove '{sourceTitle}' from the queue?
{translate('RemoveQueueItemConfirmation', { sourceTitle })}
</div>
{
isPending ?
null :
<FormGroup>
<FormLabel>Remove From Download Client</FormLabel>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning="Removing will remove the download and the file(s) from the download client."
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
@@ -107,29 +114,43 @@ class RemoveQueueItemModal extends Component {
}
<FormGroup>
<FormLabel>Add Release To Blocklist</FormLabel>
<FormLabel>{translate('BlocklistRelease')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText="Starts a search for this episode again and prevents this release from being grabbed again"
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}>
Close
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>

View File

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

View File

@@ -1,15 +1,16 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
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 FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
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 {
@@ -22,42 +23,48 @@ class RemoveQueueItemsModal extends Component {
this.state = {
remove: true,
blocklist: false
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false
});
}
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
}
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
@@ -70,7 +77,7 @@ class RemoveQueueItemsModal extends Component {
allPending
} = this.props;
const { remove, blocklist } = this.state;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
@@ -82,25 +89,25 @@ class RemoveQueueItemsModal extends Component {
onModalClose={this.onModalClose}
>
<ModalHeader>
Remove Selected Item{selectedCount > 1 ? 's' : ''}
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
</ModalHeader>
<ModalBody>
<div className={styles.message}>
Are you sure you want to remove {selectedCount} item{selectedCount > 1 ? 's' : ''} from the queue?
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', { selectedCount }) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
allPending ?
null :
<FormGroup>
<FormLabel>Remove From Download Client</FormLabel>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning="Removing will remove the download and the file(s) from the download client."
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
@@ -109,30 +116,44 @@ class RemoveQueueItemsModal extends Component {
<FormGroup>
<FormLabel>
Add Release{selectedCount > 1 ? 's' : ''} To Blocklist
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText="Prevents Sonarr from automatically grabbing this episode again"
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}>
Close
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -2,8 +2,8 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchQueueStatus } from 'Store/Actions/queueActions';
import PageSidebarStatus from 'Components/Page/Sidebar/PageSidebarStatus';
import { fetchQueueStatus } from 'Store/Actions/queueActions';
function createMapStateToProps() {
return createSelector(

View File

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

View File

@@ -1,10 +1,14 @@
import PropTypes from 'prop-types';
import React from 'react';
import Icon from 'Components/Icon';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import formatTime from 'Utilities/Date/formatTime';
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
import getRelativeDate from 'Utilities/Date/getRelativeDate';
import formatBytes from 'Utilities/Number/formatBytes';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import translate from 'Utilities/String/translate';
import styles from './TimeleftCell.css';
function TimeleftCell(props) {
@@ -24,11 +28,13 @@ function TimeleftCell(props) {
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (
<TableRowCell
className={styles.timeleft}
title={`Delaying download until ${date} at ${time}`}
>
-
<TableRowCell className={styles.timeleft}>
<Tooltip
anchor={<Icon name={icons.INFO} />}
tooltip={translate('DelayingDownloadUntil', { date, time })}
kind={kinds.INVERSE}
position={tooltipPositions.TOP}
/>
</TableRowCell>
);
}
@@ -38,11 +44,13 @@ function TimeleftCell(props) {
const time = formatTime(estimatedCompletionTime, timeFormat, { includeMinuteZero: true });
return (
<TableRowCell
className={styles.timeleft}
title={`Retrying download ${date} at ${time}`}
>
-
<TableRowCell className={styles.timeleft}>
<Tooltip
anchor={<Icon name={icons.INFO} />}
tooltip={translate('RetryingDownloadOn', { date, time })}
kind={kinds.INVERSE}
position={tooltipPositions.TOP}
/>
</TableRowCell>
);
}

View File

@@ -6,12 +6,12 @@
.searchIconContainer {
width: 58px;
height: 46px;
border: 1px solid $inputBorderColor;
border: 1px solid var(--inputBorderColor);
border-right: none;
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
background-color: #edf1f2;
background-color: var(--searchIconContainerBackgroundColor);
text-align: center;
line-height: 46px;
}
@@ -25,7 +25,7 @@
}
.clearLookupButton {
border: 1px solid $inputBorderColor;
border: 1px solid var(--inputBorderColor);
border-left: none;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;

View File

@@ -0,0 +1,15 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'clearLookupButton': string;
'helpText': string;
'message': string;
'noResults': string;
'noSeriesText': string;
'searchContainer': string;
'searchIconContainer': string;
'searchInput': string;
'searchResults': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,14 +1,15 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import { icons, kinds } from 'Helpers/Props';
import TextInput from 'Components/Form/TextInput';
import Icon from 'Components/Icon';
import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link';
import Icon from 'Components/Icon';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import TextInput from 'Components/Form/TextInput';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { icons, kinds } from 'Helpers/Props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import AddNewSeriesSearchResultConnector from './AddNewSeriesSearchResultConnector';
import styles from './AddNewSeries.css';
@@ -66,12 +67,12 @@ class AddNewSeries extends Component {
this.props.onClearSeriesLookup();
}
});
}
};
onClearSeriesLookupPress = () => {
this.setState({ term: '' });
this.props.onClearSeriesLookup();
}
};
//
// Render
@@ -87,7 +88,7 @@ class AddNewSeries extends Component {
const isFetching = this.state.isFetching;
return (
<PageContent title="Add New Series">
<PageContent title={translate('AddNewSeries')}>
<PageContentBody>
<div className={styles.searchContainer}>
<div className={styles.searchIconContainer}>
@@ -126,7 +127,7 @@ class AddNewSeries extends Component {
!isFetching && !!error ?
<div className={styles.message}>
<div className={styles.helpText}>
Failed to load search results, please try again.
{translate('AddNewSeriesError')}
</div>
<div>{getErrorMessage(error)}</div>
</div> : null
@@ -151,11 +152,11 @@ class AddNewSeries extends Component {
{
!isFetching && !error && !items.length && !!term &&
<div className={styles.message}>
<div className={styles.noResults}>Couldn't find any results for '{term}'</div>
<div>You can also search using TVDB ID of a show. eg. tvdb:71663</div>
<div className={styles.noResults}>{translate('CouldNotFindResults', { term })}</div>
<div>{translate('SearchByTvdbId')}</div>
<div>
<Link to="https://wiki.servarr.com/sonarr/faq#why-cant-i-add-a-new-series-when-i-know-the-tvdb-id">
Why can't I find my show?
{translate('WhyCantIFindMyShow')}
</Link>
</div>
</div>
@@ -166,9 +167,9 @@ class AddNewSeries extends Component {
null :
<div className={styles.message}>
<div className={styles.helpText}>
It's easy to add a new series, just start typing the name the series you want to add.
{translate('AddNewSeriesHelpText')}
</div>
<div>You can also search using TVDB ID of a show. eg. tvdb:71663</div>
<div>{translate('SearchByTvdbId')}</div>
</div>
}
@@ -176,14 +177,14 @@ class AddNewSeries extends Component {
!term && !hasExistingSeries ?
<div className={styles.message}>
<div className={styles.noSeriesText}>
You haven't added any series yet, do you want to import some or all of your series first?
{translate('NoSeriesHaveBeenAdded')}
</div>
<div>
<Button
to="/add/import"
kind={kinds.PRIMARY}
>
Import Existing Series
{translate('ImportExistingSeries')}
</Button>
</div>
</div> :

View File

@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import parseUrl from 'Utilities/String/parseUrl';
import { lookupSeries, clearAddSeries } from 'Store/Actions/addSeriesActions';
import { clearAddSeries, lookupSeries } from 'Store/Actions/addSeriesActions';
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
import parseUrl from 'Utilities/String/parseUrl';
import AddNewSeries from './AddNewSeries';
function createMapStateToProps() {
@@ -68,11 +68,11 @@ class AddNewSeriesConnector extends Component {
this.props.lookupSeries({ term });
}, 300);
}
}
};
onClearSeriesLookup = () => {
this.props.clearAddSeries();
}
};
//
// Render

View File

@@ -4,7 +4,7 @@
.year {
margin-left: 5px;
color: $disabledColor;
color: var(--disabledColor);
}
.poster {
@@ -57,12 +57,6 @@
composes: button from '~Components/Link/SpinnerButton.css';
}
.hideLanguageProfile {
composes: group from '~Components/Form/FormGroup.css';
display: none;
}
@media only screen and (max-width: $breakpointSmall) {
.modalFooter {
display: block;

View File

@@ -0,0 +1,18 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'addButton': string;
'container': string;
'info': string;
'labelIcon': string;
'modalFooter': string;
'overview': string;
'poster': string;
'searchInput': string;
'searchInputContainer': string;
'searchLabel': string;
'searchLabelContainer': string;
'year': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,22 +1,23 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { icons, kinds, inputTypes, tooltipPositions } from 'Helpers/Props';
import Icon from 'Components/Icon';
import SpinnerButton from 'Components/Link/SpinnerButton';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormLabel from 'Components/Form/FormLabel';
import FormInputGroup from 'Components/Form/FormInputGroup';
import CheckInput from 'Components/Form/CheckInput';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
import ModalFooter from 'Components/Modal/ModalFooter';
import Popover from 'Components/Tooltip/Popover';
import SeriesPoster from 'Series/SeriesPoster';
import * as seriesTypes from 'Utilities/Series/seriesTypes';
import SeriesMonitoringOptionsPopoverContent from 'AddSeries/SeriesMonitoringOptionsPopoverContent';
import SeriesTypePopoverContent from 'AddSeries/SeriesTypePopoverContent';
import CheckInput from 'Components/Form/CheckInput';
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 Icon from 'Components/Icon';
import SpinnerButton from 'Components/Link/SpinnerButton';
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 Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
import SeriesPoster from 'Series/SeriesPoster';
import * as seriesTypes from 'Utilities/Series/seriesTypes';
import translate from 'Utilities/String/translate';
import styles from './AddNewSeriesModalContent.css';
class AddNewSeriesModalContent extends Component {
@@ -45,11 +46,7 @@ class AddNewSeriesModalContent extends Component {
onQualityProfileIdChange = ({ value }) => {
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
}
onLanguageProfileIdChange = ({ value }) => {
this.props.onInputChange({ name: 'languageProfileId', value: parseInt(value) });
}
};
onAddSeriesPress = () => {
const {
@@ -59,7 +56,7 @@ class AddNewSeriesModalContent extends Component {
this.props.onAddSeriesPress(
seriesType
);
}
};
//
// Render
@@ -74,14 +71,12 @@ class AddNewSeriesModalContent extends Component {
rootFolderPath,
monitor,
qualityProfileId,
languageProfileId,
seriesType,
seasonFolder,
searchForMissingEpisodes,
searchForCutoffUnmetEpisodes,
folder,
tags,
showLanguageProfile,
isSmallScreen,
isWindows,
onModalClose,
@@ -125,7 +120,7 @@ class AddNewSeriesModalContent extends Component {
<Form {...otherProps}>
<FormGroup>
<FormLabel>Root Folder</FormLabel>
<FormLabel>{translate('RootFolder')}</FormLabel>
<FormInputGroup
type={inputTypes.ROOT_FOLDER_SELECT}
@@ -138,7 +133,7 @@ class AddNewSeriesModalContent extends Component {
seriesFolder: folder,
isWindows
}}
helpText={`'${folder}' subfolder will be created automatically`}
helpText={translate('AddNewSeriesRootFolderHelpText', { folder })}
onChange={onInputChange}
{...rootFolderPath}
/>
@@ -146,7 +141,7 @@ class AddNewSeriesModalContent extends Component {
<FormGroup>
<FormLabel>
Monitor
{translate('Monitor')}
<Popover
anchor={
@@ -155,7 +150,7 @@ class AddNewSeriesModalContent extends Component {
name={icons.INFO}
/>
}
title="Monitoring Options"
title={translate('MonitoringOptions')}
body={<SeriesMonitoringOptionsPopoverContent />}
position={tooltipPositions.RIGHT}
/>
@@ -170,7 +165,7 @@ class AddNewSeriesModalContent extends Component {
</FormGroup>
<FormGroup>
<FormLabel>Quality Profile</FormLabel>
<FormLabel>{translate('QualityProfile')}</FormLabel>
<FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT}
@@ -180,20 +175,9 @@ class AddNewSeriesModalContent extends Component {
/>
</FormGroup>
<FormGroup className={showLanguageProfile ? undefined : styles.hideLanguageProfile}>
<FormLabel>Language Profile</FormLabel>
<FormInputGroup
type={inputTypes.LANGUAGE_PROFILE_SELECT}
name="languageProfileId"
onChange={this.onLanguageProfileIdChange}
{...languageProfileId}
/>
</FormGroup>
<FormGroup>
<FormLabel>
Series Type
{translate('SeriesType')}
<Popover
anchor={
@@ -202,7 +186,7 @@ class AddNewSeriesModalContent extends Component {
name={icons.INFO}
/>
}
title="Series Types"
title={translate('SeriesTypes')}
body={<SeriesTypePopoverContent />}
position={tooltipPositions.RIGHT}
/>
@@ -214,11 +198,12 @@ class AddNewSeriesModalContent extends Component {
onChange={onInputChange}
{...seriesType}
value={this.state.seriesType}
helpText={translate('SeriesTypesHelpText')}
/>
</FormGroup>
<FormGroup>
<FormLabel>Season Folder</FormLabel>
<FormLabel>{translate('SeasonFolder')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
@@ -229,7 +214,7 @@ class AddNewSeriesModalContent extends Component {
</FormGroup>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
@@ -247,7 +232,7 @@ class AddNewSeriesModalContent extends Component {
<div>
<label className={styles.searchLabelContainer}>
<span className={styles.searchLabel}>
Start search for missing episodes
{translate('AddNewSeriesSearchForMissingEpisodes')}
</span>
<CheckInput
@@ -261,7 +246,7 @@ class AddNewSeriesModalContent extends Component {
<label className={styles.searchLabelContainer}>
<span className={styles.searchLabel}>
Start search for cutoff unmet episodes
{translate('AddNewSeriesSearchForCutoffUnmetEpisodes')}
</span>
<CheckInput
@@ -280,7 +265,7 @@ class AddNewSeriesModalContent extends Component {
isSpinning={isAdding}
onPress={this.onAddSeriesPress}
>
Add {title}
{translate('AddSeriesWithTitle', { title })}
</SpinnerButton>
</ModalFooter>
</ModalContent>
@@ -299,14 +284,12 @@ AddNewSeriesModalContent.propTypes = {
rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object,
languageProfileId: PropTypes.object,
seriesType: PropTypes.object.isRequired,
seasonFolder: PropTypes.object.isRequired,
searchForMissingEpisodes: PropTypes.object.isRequired,
searchForCutoffUnmetEpisodes: PropTypes.object.isRequired,
folder: PropTypes.string.isRequired,
tags: PropTypes.object.isRequired,
showLanguageProfile: PropTypes.bool.isRequired,
isSmallScreen: PropTypes.bool.isRequired,
isWindows: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired,

View File

@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { setAddSeriesDefault, addSeries } from 'Store/Actions/addSeriesActions';
import { addSeries, setAddSeriesDefault } from 'Store/Actions/addSeriesActions';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createSystemStatusSelector from 'Store/Selectors/createSystemStatusSelector';
import selectSettings from 'Store/Selectors/selectSettings';
@@ -11,10 +11,9 @@ import AddNewSeriesModalContent from './AddNewSeriesModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.addSeries,
(state) => state.settings.languageProfiles,
createDimensionsSelector(),
createSystemStatusSelector(),
(addSeriesState, languageProfiles, dimensions, systemStatus) => {
(addSeriesState, dimensions, systemStatus) => {
const {
isAdding,
addError,
@@ -30,7 +29,6 @@ function createMapStateToProps() {
return {
isAdding,
addError,
showLanguageProfile: languageProfiles.items.length > 1,
isSmallScreen: dimensions.isSmallScreen,
validationErrors,
validationWarnings,
@@ -53,7 +51,7 @@ class AddNewSeriesModalContentConnector extends Component {
onInputChange = ({ name, value }) => {
this.props.setAddSeriesDefault({ [name]: value });
}
};
onAddSeriesPress = (seriesType) => {
const {
@@ -61,7 +59,6 @@ class AddNewSeriesModalContentConnector extends Component {
rootFolderPath,
monitor,
qualityProfileId,
languageProfileId,
seasonFolder,
searchForMissingEpisodes,
searchForCutoffUnmetEpisodes,
@@ -73,14 +70,13 @@ class AddNewSeriesModalContentConnector extends Component {
rootFolderPath: rootFolderPath.value,
monitor: monitor.value,
qualityProfileId: qualityProfileId.value,
languageProfileId: languageProfileId.value,
seriesType,
seasonFolder: seasonFolder.value,
searchForMissingEpisodes: searchForMissingEpisodes.value,
searchForCutoffUnmetEpisodes: searchForCutoffUnmetEpisodes.value,
tags: tags.value
});
}
};
//
// Render
@@ -101,7 +97,6 @@ AddNewSeriesModalContentConnector.propTypes = {
rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object,
languageProfileId: PropTypes.object,
seriesType: PropTypes.object.isRequired,
seasonFolder: PropTypes.object.isRequired,
searchForMissingEpisodes: PropTypes.object.isRequired,

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